* config/tc-arm.c (psrs): Accept combinations of flags.
[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
JM
371 { /* save away the old registers */
372 case USERBANK:
373 case IRQBANK:
374 case SVCBANK:
375 case ABORTBANK:
376 case UNDEFBANK:
c1a72ffd 377 if (newbank == FIQBANK)
dfcd3bfb
JM
378 for (i = 8; i < 13; i++)
379 state->RegBank[USERBANK][i] = state->Reg[i];
c1a72ffd
NC
380 state->RegBank[oldbank][13] = state->Reg[13];
381 state->RegBank[oldbank][14] = state->Reg[14];
dfcd3bfb
JM
382 break;
383 case FIQBANK:
384 for (i = 8; i < 15; i++)
385 state->RegBank[FIQBANK][i] = state->Reg[i];
386 break;
387 case DUMMYBANK:
388 for (i = 8; i < 15; i++)
389 state->RegBank[DUMMYBANK][i] = 0;
390 break;
c1a72ffd
NC
391 default:
392 abort ();
dfcd3bfb 393 }
c1a72ffd
NC
394
395 switch (newbank)
dfcd3bfb
JM
396 { /* restore the new registers */
397 case USERBANK:
398 case IRQBANK:
399 case SVCBANK:
400 case ABORTBANK:
401 case UNDEFBANK:
c1a72ffd 402 if (oldbank == FIQBANK)
dfcd3bfb
JM
403 for (i = 8; i < 13; i++)
404 state->Reg[i] = state->RegBank[USERBANK][i];
c1a72ffd
NC
405 state->Reg[13] = state->RegBank[newbank][13];
406 state->Reg[14] = state->RegBank[newbank][14];
dfcd3bfb
JM
407 break;
408 case FIQBANK:
409 for (i = 8; i < 15; i++)
410 state->Reg[i] = state->RegBank[FIQBANK][i];
411 break;
412 case DUMMYBANK:
413 for (i = 8; i < 15; i++)
414 state->Reg[i] = 0;
415 break;
c1a72ffd
NC
416 default:
417 abort ();
dfcd3bfb
JM
418 } /* switch */
419 } /* if */
c1a72ffd
NC
420
421 return newmode;
c906108c
SS
422}
423
424/***************************************************************************\
425* Given a processor mode, this routine returns the register bank that *
426* will be accessed in that mode. *
427\***************************************************************************/
428
dfcd3bfb 429static ARMword
c1a72ffd 430ModeToBank (ARMword mode)
dfcd3bfb 431{
c1a72ffd
NC
432 static ARMword bankofmode[] =
433 {
434 USERBANK, FIQBANK, IRQBANK, SVCBANK,
dfcd3bfb
JM
435 DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
436 DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
437 DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
c1a72ffd 438 USERBANK, FIQBANK, IRQBANK, SVCBANK,
dfcd3bfb 439 DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK,
c1a72ffd
NC
440 DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK,
441 DUMMYBANK, DUMMYBANK, DUMMYBANK, SYSTEMBANK
dfcd3bfb
JM
442 };
443
c1a72ffd
NC
444 if (mode >= (sizeof (bankofmode) / sizeof (bankofmode[0])))
445 return DUMMYBANK;
446
447 return bankofmode[mode];
dfcd3bfb 448}
c906108c
SS
449
450/***************************************************************************\
451* Returns the register number of the nth register in a reg list. *
452\***************************************************************************/
453
dfcd3bfb
JM
454unsigned
455ARMul_NthReg (ARMword instr, unsigned number)
456{
457 unsigned bit, upto;
c906108c 458
dfcd3bfb
JM
459 for (bit = 0, upto = 0; upto <= number; bit++)
460 if (BIT (bit))
461 upto++;
462 return (bit - 1);
c906108c
SS
463}
464
465/***************************************************************************\
466* Assigns the N and Z flags depending on the value of result *
467\***************************************************************************/
468
dfcd3bfb
JM
469void
470ARMul_NegZero (ARMul_State * state, ARMword result)
c906108c 471{
dfcd3bfb
JM
472 if (NEG (result))
473 {
474 SETN;
475 CLEARZ;
476 }
477 else if (result == 0)
478 {
479 CLEARN;
480 SETZ;
481 }
482 else
483 {
484 CLEARN;
485 CLEARZ;
486 };
487}
c906108c 488
f743149e 489/* Compute whether an addition of A and B, giving RESULT, overflowed. */
dfcd3bfb
JM
490int
491AddOverflow (ARMword a, ARMword b, ARMword result)
f743149e
JM
492{
493 return ((NEG (a) && NEG (b) && POS (result))
494 || (POS (a) && POS (b) && NEG (result)));
495}
496
497/* Compute whether a subtraction of A and B, giving RESULT, overflowed. */
dfcd3bfb
JM
498int
499SubOverflow (ARMword a, ARMword b, ARMword result)
f743149e
JM
500{
501 return ((NEG (a) && POS (b) && POS (result))
502 || (POS (a) && NEG (b) && NEG (result)));
503}
504
c906108c
SS
505/***************************************************************************\
506* Assigns the C flag after an addition of a and b to give result *
507\***************************************************************************/
508
dfcd3bfb
JM
509void
510ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
c906108c 511{
dfcd3bfb
JM
512 ASSIGNC ((NEG (a) && NEG (b)) ||
513 (NEG (a) && POS (result)) || (NEG (b) && POS (result)));
514}
c906108c
SS
515
516/***************************************************************************\
517* Assigns the V flag after an addition of a and b to give result *
518\***************************************************************************/
519
dfcd3bfb
JM
520void
521ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
c906108c 522{
f743149e
JM
523 ASSIGNV (AddOverflow (a, b, result));
524}
c906108c
SS
525
526/***************************************************************************\
527* Assigns the C flag after an subtraction of a and b to give result *
528\***************************************************************************/
529
dfcd3bfb
JM
530void
531ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
c906108c 532{
dfcd3bfb
JM
533 ASSIGNC ((NEG (a) && POS (b)) ||
534 (NEG (a) && POS (result)) || (POS (b) && POS (result)));
c906108c
SS
535}
536
537/***************************************************************************\
538* Assigns the V flag after an subtraction of a and b to give result *
539\***************************************************************************/
540
dfcd3bfb
JM
541void
542ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
c906108c 543{
f743149e 544 ASSIGNV (SubOverflow (a, b, result));
c906108c
SS
545}
546
547/***************************************************************************\
548* This function does the work of generating the addresses used in an *
549* LDC instruction. The code here is always post-indexed, it's up to the *
550* caller to get the input address correct and to handle base register *
551* modification. It also handles the Busy-Waiting. *
552\***************************************************************************/
553
dfcd3bfb
JM
554void
555ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
556{
557 unsigned cpab;
558 ARMword data;
c906108c 559
dfcd3bfb
JM
560 UNDEF_LSCPCBaseWb;
561 if (ADDREXCEPT (address))
562 {
563 INTERNALABORT (address);
c906108c 564 }
dfcd3bfb
JM
565 cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0);
566 while (cpab == ARMul_BUSY)
567 {
568 ARMul_Icycles (state, 1, 0);
569 if (IntPending (state))
570 {
571 cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
572 return;
573 }
574 else
575 cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, 0);
c906108c 576 }
dfcd3bfb
JM
577 if (cpab == ARMul_CANT)
578 {
579 CPTAKEABORT;
580 return;
c906108c 581 }
dfcd3bfb
JM
582 cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0);
583 data = ARMul_LoadWordN (state, address);
584 BUSUSEDINCPCN;
585 if (BIT (21))
586 LSBase = state->Base;
587 cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
588 while (cpab == ARMul_INC)
589 {
590 address += 4;
591 data = ARMul_LoadWordN (state, address);
592 cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
c906108c 593 }
dfcd3bfb
JM
594 if (state->abortSig || state->Aborted)
595 {
596 TAKEABORT;
c906108c 597 }
dfcd3bfb 598}
c906108c
SS
599
600/***************************************************************************\
601* This function does the work of generating the addresses used in an *
602* STC instruction. The code here is always post-indexed, it's up to the *
603* caller to get the input address correct and to handle base register *
604* modification. It also handles the Busy-Waiting. *
605\***************************************************************************/
606
dfcd3bfb
JM
607void
608ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
609{
610 unsigned cpab;
611 ARMword data;
c906108c 612
dfcd3bfb
JM
613 UNDEF_LSCPCBaseWb;
614 if (ADDREXCEPT (address) || VECTORACCESS (address))
615 {
616 INTERNALABORT (address);
c906108c 617 }
dfcd3bfb
JM
618 cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data);
619 while (cpab == ARMul_BUSY)
620 {
621 ARMul_Icycles (state, 1, 0);
622 if (IntPending (state))
623 {
624 cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
625 return;
626 }
627 else
628 cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, &data);
c906108c 629 }
dfcd3bfb
JM
630 if (cpab == ARMul_CANT)
631 {
632 CPTAKEABORT;
633 return;
c906108c
SS
634 }
635#ifndef MODE32
dfcd3bfb
JM
636 if (ADDREXCEPT (address) || VECTORACCESS (address))
637 {
638 INTERNALABORT (address);
c906108c
SS
639 }
640#endif
dfcd3bfb
JM
641 BUSUSEDINCPCN;
642 if (BIT (21))
643 LSBase = state->Base;
644 cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
645 ARMul_StoreWordN (state, address, data);
646 while (cpab == ARMul_INC)
647 {
648 address += 4;
649 cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
650 ARMul_StoreWordN (state, address, data);
c906108c 651 }
dfcd3bfb
JM
652 if (state->abortSig || state->Aborted)
653 {
654 TAKEABORT;
c906108c 655 }
dfcd3bfb 656}
c906108c
SS
657
658/***************************************************************************\
659* This function does the Busy-Waiting for an MCR instruction. *
660\***************************************************************************/
661
dfcd3bfb
JM
662void
663ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
664{
665 unsigned cpab;
666
667 cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source);
c1a72ffd 668
dfcd3bfb
JM
669 while (cpab == ARMul_BUSY)
670 {
671 ARMul_Icycles (state, 1, 0);
c1a72ffd 672
dfcd3bfb
JM
673 if (IntPending (state))
674 {
675 cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
676 return;
677 }
678 else
679 cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, source);
c906108c 680 }
c1a72ffd 681
dfcd3bfb
JM
682 if (cpab == ARMul_CANT)
683 ARMul_Abort (state, ARMul_UndefinedInstrV);
684 else
685 {
686 BUSUSEDINCPCN;
687 ARMul_Ccycles (state, 1, 0);
c906108c 688 }
dfcd3bfb 689}
c906108c
SS
690
691/***************************************************************************\
692* This function does the Busy-Waiting for an MRC instruction. *
693\***************************************************************************/
694
dfcd3bfb
JM
695ARMword
696ARMul_MRC (ARMul_State * state, ARMword instr)
697{
698 unsigned cpab;
699 ARMword result = 0;
700
701 cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
702 while (cpab == ARMul_BUSY)
703 {
704 ARMul_Icycles (state, 1, 0);
705 if (IntPending (state))
706 {
707 cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
708 return (0);
709 }
710 else
711 cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, &result);
c906108c 712 }
dfcd3bfb
JM
713 if (cpab == ARMul_CANT)
714 {
715 ARMul_Abort (state, ARMul_UndefinedInstrV);
716 result = ECC; /* Parent will destroy the flags otherwise */
c906108c 717 }
dfcd3bfb
JM
718 else
719 {
720 BUSUSEDINCPCN;
721 ARMul_Ccycles (state, 1, 0);
722 ARMul_Icycles (state, 1, 0);
c906108c 723 }
dfcd3bfb 724 return (result);
c906108c
SS
725}
726
727/***************************************************************************\
728* This function does the Busy-Waiting for an CDP instruction. *
729\***************************************************************************/
730
dfcd3bfb
JM
731void
732ARMul_CDP (ARMul_State * state, ARMword instr)
733{
734 unsigned cpab;
735
736 cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr);
737 while (cpab == ARMul_BUSY)
738 {
739 ARMul_Icycles (state, 1, 0);
740 if (IntPending (state))
741 {
742 cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, instr);
743 return;
744 }
745 else
746 cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr);
c906108c 747 }
dfcd3bfb
JM
748 if (cpab == ARMul_CANT)
749 ARMul_Abort (state, ARMul_UndefinedInstrV);
750 else
751 BUSUSEDN;
c906108c
SS
752}
753
754/***************************************************************************\
755* This function handles Undefined instructions, as CP isntruction *
756\***************************************************************************/
757
dfcd3bfb 758void
6d358e86 759ARMul_UndefInstr (ARMul_State * state, ARMword instr ATTRIBUTE_UNUSED)
c906108c 760{
dfcd3bfb 761 ARMul_Abort (state, ARMul_UndefinedInstrV);
c906108c
SS
762}
763
764/***************************************************************************\
765* Return TRUE if an interrupt is pending, FALSE otherwise. *
766\***************************************************************************/
767
dfcd3bfb
JM
768unsigned
769IntPending (ARMul_State * state)
770{
771 if (state->Exception)
772 { /* Any exceptions */
773 if (state->NresetSig == LOW)
774 {
775 ARMul_Abort (state, ARMul_ResetV);
776 return (TRUE);
777 }
778 else if (!state->NfiqSig && !FFLAG)
779 {
780 ARMul_Abort (state, ARMul_FIQV);
781 return (TRUE);
782 }
783 else if (!state->NirqSig && !IFLAG)
784 {
785 ARMul_Abort (state, ARMul_IRQV);
786 return (TRUE);
787 }
c906108c 788 }
dfcd3bfb
JM
789 return (FALSE);
790}
c906108c
SS
791
792/***************************************************************************\
793* Align a word access to a non word boundary *
794\***************************************************************************/
795
dfcd3bfb 796ARMword
6d358e86
NC
797ARMul_Align (state, address, data)
798 ARMul_State * state ATTRIBUTE_UNUSED;
799 ARMword address;
800 ARMword data;
801{
802 /* This code assumes the address is really unaligned,
803 as a shift by 32 is undefined in C. */
c906108c 804
dfcd3bfb
JM
805 address = (address & 3) << 3; /* get the word address */
806 return ((data >> address) | (data << (32 - address))); /* rot right */
c906108c
SS
807}
808
809/***************************************************************************\
810* This routine is used to call another routine after a certain number of *
811* cycles have been executed. The first parameter is the number of cycles *
812* delay before the function is called, the second argument is a pointer *
813* to the function. A delay of zero doesn't work, just call the function. *
814\***************************************************************************/
815
dfcd3bfb
JM
816void
817ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
818 unsigned (*what) ())
819{
820 unsigned long when;
821 struct EventNode *event;
822
823 if (state->EventSet++ == 0)
824 state->Now = ARMul_Time (state);
825 when = (state->Now + delay) % EVENTLISTSIZE;
826 event = (struct EventNode *) malloc (sizeof (struct EventNode));
827 event->func = what;
828 event->next = *(state->EventPtr + when);
829 *(state->EventPtr + when) = event;
c906108c
SS
830}
831
832/***************************************************************************\
833* This routine is called at the beginning of every cycle, to envoke *
834* scheduled events. *
835\***************************************************************************/
836
dfcd3bfb
JM
837void
838ARMul_EnvokeEvent (ARMul_State * state)
839{
840 static unsigned long then;
841
842 then = state->Now;
843 state->Now = ARMul_Time (state) % EVENTLISTSIZE;
844 if (then < state->Now) /* schedule events */
845 EnvokeList (state, then, state->Now);
846 else if (then > state->Now)
847 { /* need to wrap around the list */
848 EnvokeList (state, then, EVENTLISTSIZE - 1L);
849 EnvokeList (state, 0L, state->Now);
c906108c 850 }
dfcd3bfb 851}
c906108c 852
dfcd3bfb
JM
853static void
854EnvokeList (ARMul_State * state, unsigned long from, unsigned long to)
c906108c 855/* envokes all the entries in a range */
dfcd3bfb
JM
856{
857 struct EventNode *anevent;
858
859 for (; from <= to; from++)
860 {
861 anevent = *(state->EventPtr + from);
862 while (anevent)
863 {
864 (anevent->func) (state);
865 state->EventSet--;
866 anevent = anevent->next;
867 }
868 *(state->EventPtr + from) = NULL;
c906108c 869 }
dfcd3bfb 870}
c906108c
SS
871
872/***************************************************************************\
873* This routine is returns the number of clock ticks since the last reset. *
874\***************************************************************************/
875
dfcd3bfb
JM
876unsigned long
877ARMul_Time (ARMul_State * state)
878{
879 return (state->NumScycles + state->NumNcycles +
880 state->NumIcycles + state->NumCcycles + state->NumFcycles);
c906108c 881}
This page took 0.087239 seconds and 4 git commands to generate.