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