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