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