]>
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 | ||
f743149e JM |
394 | /* Compute whether an addition of A and B, giving RESULT, overflowed. */ |
395 | int AddOverflow (ARMword a, ARMword b, ARMword result) | |
396 | { | |
397 | return ((NEG (a) && NEG (b) && POS (result)) | |
398 | || (POS (a) && POS (b) && NEG (result))); | |
399 | } | |
400 | ||
401 | /* Compute whether a subtraction of A and B, giving RESULT, overflowed. */ | |
402 | int SubOverflow (ARMword a, ARMword b, ARMword result) | |
403 | { | |
404 | return ((NEG (a) && POS (b) && POS (result)) | |
405 | || (POS (a) && NEG (b) && NEG (result))); | |
406 | } | |
407 | ||
c906108c SS |
408 | /***************************************************************************\ |
409 | * Assigns the C flag after an addition of a and b to give result * | |
410 | \***************************************************************************/ | |
411 | ||
412 | void ARMul_AddCarry(ARMul_State *state, ARMword a,ARMword b,ARMword result) | |
413 | { | |
414 | ASSIGNC( (NEG(a) && NEG(b)) || | |
415 | (NEG(a) && POS(result)) || | |
416 | (NEG(b) && POS(result)) ) ; | |
417 | } | |
418 | ||
419 | /***************************************************************************\ | |
420 | * Assigns the V flag after an addition of a and b to give result * | |
421 | \***************************************************************************/ | |
422 | ||
423 | void ARMul_AddOverflow(ARMul_State *state, ARMword a,ARMword b,ARMword result) | |
424 | { | |
f743149e JM |
425 | ASSIGNV (AddOverflow (a, b, result)); |
426 | } | |
c906108c SS |
427 | |
428 | /***************************************************************************\ | |
429 | * Assigns the C flag after an subtraction of a and b to give result * | |
430 | \***************************************************************************/ | |
431 | ||
432 | void ARMul_SubCarry(ARMul_State *state, ARMword a,ARMword b,ARMword result) | |
433 | { | |
434 | ASSIGNC( (NEG(a) && POS(b)) || | |
435 | (NEG(a) && POS(result)) || | |
436 | (POS(b) && POS(result)) ) ; | |
437 | } | |
438 | ||
439 | /***************************************************************************\ | |
440 | * Assigns the V flag after an subtraction of a and b to give result * | |
441 | \***************************************************************************/ | |
442 | ||
443 | void ARMul_SubOverflow(ARMul_State *state,ARMword a,ARMword b,ARMword result) | |
444 | { | |
f743149e | 445 | ASSIGNV (SubOverflow (a, b, result)); |
c906108c SS |
446 | } |
447 | ||
448 | /***************************************************************************\ | |
449 | * This function does the work of generating the addresses used in an * | |
450 | * LDC instruction. The code here is always post-indexed, it's up to the * | |
451 | * caller to get the input address correct and to handle base register * | |
452 | * modification. It also handles the Busy-Waiting. * | |
453 | \***************************************************************************/ | |
454 | ||
455 | void ARMul_LDC(ARMul_State *state,ARMword instr,ARMword address) | |
456 | {unsigned cpab ; | |
457 | ARMword data ; | |
458 | ||
459 | UNDEF_LSCPCBaseWb ; | |
460 | if (ADDREXCEPT(address)) { | |
461 | INTERNALABORT(address) ; | |
462 | } | |
463 | cpab = (state->LDC[CPNum])(state,ARMul_FIRST,instr,0) ; | |
464 | while (cpab == ARMul_BUSY) { | |
465 | ARMul_Icycles(state,1,0) ; | |
466 | if (IntPending(state)) { | |
467 | cpab = (state->LDC[CPNum])(state,ARMul_INTERRUPT,instr,0) ; | |
468 | return ; | |
469 | } | |
470 | else | |
471 | cpab = (state->LDC[CPNum])(state,ARMul_BUSY,instr,0) ; | |
472 | } | |
473 | if (cpab == ARMul_CANT) { | |
474 | CPTAKEABORT ; | |
475 | return ; | |
476 | } | |
477 | cpab = (state->LDC[CPNum])(state,ARMul_TRANSFER,instr,0) ; | |
478 | data = ARMul_LoadWordN(state,address) ; | |
479 | BUSUSEDINCPCN ; | |
480 | if (BIT(21)) | |
481 | LSBase = state->Base ; | |
482 | cpab = (state->LDC[CPNum])(state,ARMul_DATA,instr,data) ; | |
483 | while (cpab == ARMul_INC) { | |
484 | address += 4 ; | |
485 | data = ARMul_LoadWordN(state,address) ; | |
486 | cpab = (state->LDC[CPNum])(state,ARMul_DATA,instr,data) ; | |
487 | } | |
488 | if (state->abortSig || state->Aborted) { | |
489 | TAKEABORT ; | |
490 | } | |
491 | } | |
492 | ||
493 | /***************************************************************************\ | |
494 | * This function does the work of generating the addresses used in an * | |
495 | * STC instruction. The code here is always post-indexed, it's up to the * | |
496 | * caller to get the input address correct and to handle base register * | |
497 | * modification. It also handles the Busy-Waiting. * | |
498 | \***************************************************************************/ | |
499 | ||
500 | void ARMul_STC(ARMul_State *state,ARMword instr,ARMword address) | |
501 | {unsigned cpab ; | |
502 | ARMword data ; | |
503 | ||
504 | UNDEF_LSCPCBaseWb ; | |
505 | if (ADDREXCEPT(address) || VECTORACCESS(address)) { | |
506 | INTERNALABORT(address) ; | |
507 | } | |
508 | cpab = (state->STC[CPNum])(state,ARMul_FIRST,instr,&data) ; | |
509 | while (cpab == ARMul_BUSY) { | |
510 | ARMul_Icycles(state,1,0) ; | |
511 | if (IntPending(state)) { | |
512 | cpab = (state->STC[CPNum])(state,ARMul_INTERRUPT,instr,0) ; | |
513 | return ; | |
514 | } | |
515 | else | |
516 | cpab = (state->STC[CPNum])(state,ARMul_BUSY,instr,&data) ; | |
517 | } | |
518 | if (cpab == ARMul_CANT) { | |
519 | CPTAKEABORT ; | |
520 | return ; | |
521 | } | |
522 | #ifndef MODE32 | |
523 | if (ADDREXCEPT(address) || VECTORACCESS(address)) { | |
524 | INTERNALABORT(address) ; | |
525 | } | |
526 | #endif | |
527 | BUSUSEDINCPCN ; | |
528 | if (BIT(21)) | |
529 | LSBase = state->Base ; | |
530 | cpab = (state->STC[CPNum])(state,ARMul_DATA,instr,&data) ; | |
531 | ARMul_StoreWordN(state,address,data) ; | |
532 | while (cpab == ARMul_INC) { | |
533 | address += 4 ; | |
534 | cpab = (state->STC[CPNum])(state,ARMul_DATA,instr,&data) ; | |
535 | ARMul_StoreWordN(state,address,data) ; | |
536 | } | |
537 | if (state->abortSig || state->Aborted) { | |
538 | TAKEABORT ; | |
539 | } | |
540 | } | |
541 | ||
542 | /***************************************************************************\ | |
543 | * This function does the Busy-Waiting for an MCR instruction. * | |
544 | \***************************************************************************/ | |
545 | ||
546 | void ARMul_MCR(ARMul_State *state,ARMword instr, ARMword source) | |
547 | {unsigned cpab ; | |
548 | ||
549 | cpab = (state->MCR[CPNum])(state,ARMul_FIRST,instr,source) ; | |
550 | while (cpab == ARMul_BUSY) { | |
551 | ARMul_Icycles(state,1,0) ; | |
552 | if (IntPending(state)) { | |
553 | cpab = (state->MCR[CPNum])(state,ARMul_INTERRUPT,instr,0) ; | |
554 | return ; | |
555 | } | |
556 | else | |
557 | cpab = (state->MCR[CPNum])(state,ARMul_BUSY,instr,source) ; | |
558 | } | |
559 | if (cpab == ARMul_CANT) | |
560 | ARMul_Abort(state,ARMul_UndefinedInstrV) ; | |
561 | else { | |
562 | BUSUSEDINCPCN ; | |
563 | ARMul_Ccycles(state,1,0) ; | |
564 | } | |
565 | } | |
566 | ||
567 | /***************************************************************************\ | |
568 | * This function does the Busy-Waiting for an MRC instruction. * | |
569 | \***************************************************************************/ | |
570 | ||
571 | ARMword ARMul_MRC(ARMul_State *state,ARMword instr) | |
572 | {unsigned cpab ; | |
573 | ARMword result = 0 ; | |
574 | ||
575 | cpab = (state->MRC[CPNum])(state,ARMul_FIRST,instr,&result) ; | |
576 | while (cpab == ARMul_BUSY) { | |
577 | ARMul_Icycles(state,1,0) ; | |
578 | if (IntPending(state)) { | |
579 | cpab = (state->MRC[CPNum])(state,ARMul_INTERRUPT,instr,0) ; | |
580 | return(0) ; | |
581 | } | |
582 | else | |
583 | cpab = (state->MRC[CPNum])(state,ARMul_BUSY,instr,&result) ; | |
584 | } | |
585 | if (cpab == ARMul_CANT) { | |
586 | ARMul_Abort(state,ARMul_UndefinedInstrV) ; | |
587 | result = ECC ; /* Parent will destroy the flags otherwise */ | |
588 | } | |
589 | else { | |
590 | BUSUSEDINCPCN ; | |
591 | ARMul_Ccycles(state,1,0) ; | |
592 | ARMul_Icycles(state,1,0) ; | |
593 | } | |
594 | return(result) ; | |
595 | } | |
596 | ||
597 | /***************************************************************************\ | |
598 | * This function does the Busy-Waiting for an CDP instruction. * | |
599 | \***************************************************************************/ | |
600 | ||
601 | void ARMul_CDP(ARMul_State *state,ARMword instr) | |
602 | {unsigned cpab ; | |
603 | ||
604 | cpab = (state->CDP[CPNum])(state,ARMul_FIRST,instr) ; | |
605 | while (cpab == ARMul_BUSY) { | |
606 | ARMul_Icycles(state,1,0) ; | |
607 | if (IntPending(state)) { | |
608 | cpab = (state->CDP[CPNum])(state,ARMul_INTERRUPT,instr) ; | |
609 | return ; | |
610 | } | |
611 | else | |
612 | cpab = (state->CDP[CPNum])(state,ARMul_BUSY,instr) ; | |
613 | } | |
614 | if (cpab == ARMul_CANT) | |
615 | ARMul_Abort(state,ARMul_UndefinedInstrV) ; | |
616 | else | |
617 | BUSUSEDN ; | |
618 | } | |
619 | ||
620 | /***************************************************************************\ | |
621 | * This function handles Undefined instructions, as CP isntruction * | |
622 | \***************************************************************************/ | |
623 | ||
624 | void ARMul_UndefInstr(ARMul_State *state,ARMword instr) | |
625 | { | |
626 | ARMul_Abort(state,ARMul_UndefinedInstrV) ; | |
627 | } | |
628 | ||
629 | /***************************************************************************\ | |
630 | * Return TRUE if an interrupt is pending, FALSE otherwise. * | |
631 | \***************************************************************************/ | |
632 | ||
633 | unsigned IntPending(ARMul_State *state) | |
634 | { | |
635 | if (state->Exception) { /* Any exceptions */ | |
636 | if (state->NresetSig == LOW) { | |
637 | ARMul_Abort(state,ARMul_ResetV) ; | |
638 | return(TRUE) ; | |
639 | } | |
640 | else if (!state->NfiqSig && !FFLAG) { | |
641 | ARMul_Abort(state,ARMul_FIQV) ; | |
642 | return(TRUE) ; | |
643 | } | |
644 | else if (!state->NirqSig && !IFLAG) { | |
645 | ARMul_Abort(state,ARMul_IRQV) ; | |
646 | return(TRUE) ; | |
647 | } | |
648 | } | |
649 | return(FALSE) ; | |
650 | } | |
651 | ||
652 | /***************************************************************************\ | |
653 | * Align a word access to a non word boundary * | |
654 | \***************************************************************************/ | |
655 | ||
656 | ARMword ARMul_Align(ARMul_State *state, ARMword address, ARMword data) | |
657 | {/* this code assumes the address is really unaligned, | |
658 | as a shift by 32 is undefined in C */ | |
659 | ||
660 | address = (address & 3) << 3 ; /* get the word address */ | |
661 | return( ( data >> address) | (data << (32 - address)) ) ; /* rot right */ | |
662 | } | |
663 | ||
664 | /***************************************************************************\ | |
665 | * This routine is used to call another routine after a certain number of * | |
666 | * cycles have been executed. The first parameter is the number of cycles * | |
667 | * delay before the function is called, the second argument is a pointer * | |
668 | * to the function. A delay of zero doesn't work, just call the function. * | |
669 | \***************************************************************************/ | |
670 | ||
671 | void ARMul_ScheduleEvent(ARMul_State *state, unsigned long delay, unsigned (*what)()) | |
672 | {unsigned long when ; | |
673 | struct EventNode *event ; | |
674 | ||
675 | if (state->EventSet++ == 0) | |
676 | state->Now = ARMul_Time(state) ; | |
677 | when = (state->Now + delay) % EVENTLISTSIZE ; | |
678 | event = (struct EventNode *)malloc(sizeof(struct EventNode)) ; | |
679 | event->func = what ; | |
680 | event->next = *(state->EventPtr + when) ; | |
681 | *(state->EventPtr + when) = event ; | |
682 | } | |
683 | ||
684 | /***************************************************************************\ | |
685 | * This routine is called at the beginning of every cycle, to envoke * | |
686 | * scheduled events. * | |
687 | \***************************************************************************/ | |
688 | ||
689 | void ARMul_EnvokeEvent(ARMul_State *state) | |
690 | {static unsigned long then ; | |
691 | ||
692 | then = state->Now ; | |
693 | state->Now = ARMul_Time(state) % EVENTLISTSIZE ; | |
694 | if (then < state->Now) /* schedule events */ | |
695 | EnvokeList(state,then,state->Now) ; | |
696 | else if (then > state->Now) { /* need to wrap around the list */ | |
697 | EnvokeList(state,then,EVENTLISTSIZE-1L) ; | |
698 | EnvokeList(state,0L,state->Now) ; | |
699 | } | |
700 | } | |
701 | ||
702 | static void EnvokeList(ARMul_State *state, unsigned long from, unsigned long to) | |
703 | /* envokes all the entries in a range */ | |
704 | {struct EventNode *anevent ; | |
705 | ||
706 | for (; from <= to ; from++) { | |
707 | anevent = *(state->EventPtr + from) ; | |
708 | while (anevent) { | |
709 | (anevent->func)(state) ; | |
710 | state->EventSet-- ; | |
711 | anevent = anevent->next ; | |
712 | } | |
713 | *(state->EventPtr + from) = NULL ; | |
714 | } | |
715 | } | |
716 | ||
717 | /***************************************************************************\ | |
718 | * This routine is returns the number of clock ticks since the last reset. * | |
719 | \***************************************************************************/ | |
720 | ||
721 | unsigned long ARMul_Time(ARMul_State *state) | |
722 | {return(state->NumScycles + state->NumNcycles + | |
723 | state->NumIcycles + state->NumCcycles + state->NumFcycles) ; | |
724 | } |