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