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