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