1 /* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd.
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.
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.
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. */
21 /***************************************************************************\
22 * Definitions for the support routines *
23 \***************************************************************************/
25 ARMword ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg);
26 void ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg,
28 ARMword ARMul_GetPC (ARMul_State * state);
29 ARMword ARMul_GetNextPC (ARMul_State * state);
30 void ARMul_SetPC (ARMul_State * state, ARMword value);
31 ARMword ARMul_GetR15 (ARMul_State * state);
32 void ARMul_SetR15 (ARMul_State * state, ARMword value);
34 ARMword ARMul_GetCPSR (ARMul_State * state);
35 void ARMul_SetCPSR (ARMul_State * state, ARMword value);
36 void ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs);
37 ARMword ARMul_GetSPSR (ARMul_State * state, ARMword mode);
38 void ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value);
39 void ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs);
41 void ARMul_CPSRAltered (ARMul_State * state);
42 void ARMul_R15Altered (ARMul_State * state);
44 ARMword ARMul_SwitchMode (ARMul_State * state, ARMword oldmode,
46 static ARMword ModeToBank (ARMul_State * state, ARMword mode);
48 unsigned ARMul_NthReg (ARMword instr, unsigned number);
50 void ARMul_NegZero (ARMul_State * state, ARMword result);
51 void ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b,
53 void ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b,
55 void ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b,
57 void ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b,
60 void ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address);
61 void ARMul_STC (ARMul_State * state, ARMword instr, ARMword address);
62 void ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source);
63 ARMword ARMul_MRC (ARMul_State * state, ARMword instr);
64 void ARMul_CDP (ARMul_State * state, ARMword instr);
65 void ARMul_UndefInstr (ARMul_State * state, ARMword instr);
66 unsigned IntPending (ARMul_State * state);
68 ARMword ARMul_Align (ARMul_State * state, ARMword address, ARMword data);
70 void ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
72 void ARMul_EnvokeEvent (ARMul_State * state);
73 unsigned long ARMul_Time (ARMul_State * state);
74 static void EnvokeList (ARMul_State * state, unsigned long from,
78 { /* An event list node */
79 unsigned (*func) (); /* The function to call */
80 struct EventNode *next;
83 /***************************************************************************\
84 * This routine returns the value of a register from a mode. *
85 \***************************************************************************/
88 ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg)
91 if (mode != state->Mode)
92 return (state->RegBank[ModeToBank (state, (ARMword) mode)][reg]);
94 return (state->Reg[reg]);
97 /***************************************************************************\
98 * This routine sets the value of a register for a mode. *
99 \***************************************************************************/
102 ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value)
105 if (mode != state->Mode)
106 state->RegBank[ModeToBank (state, (ARMword) mode)][reg] = value;
108 state->Reg[reg] = value;
111 /***************************************************************************\
112 * This routine returns the value of the PC, mode independently. *
113 \***************************************************************************/
116 ARMul_GetPC (ARMul_State * state)
118 if (state->Mode > SVC26MODE)
119 return (state->Reg[15]);
124 /***************************************************************************\
125 * This routine returns the value of the PC, mode independently. *
126 \***************************************************************************/
129 ARMul_GetNextPC (ARMul_State * state)
131 if (state->Mode > SVC26MODE)
132 return (state->Reg[15] + isize);
134 return ((state->Reg[15] + isize) & R15PCBITS);
137 /***************************************************************************\
138 * This routine sets the value of the PC. *
139 \***************************************************************************/
142 ARMul_SetPC (ARMul_State * state, ARMword value)
145 state->Reg[15] = value & PCBITS;
147 state->Reg[15] = R15CCINTMODE | (value & R15PCBITS);
151 /***************************************************************************\
152 * This routine returns the value of register 15, mode independently. *
153 \***************************************************************************/
156 ARMul_GetR15 (ARMul_State * state)
158 if (state->Mode > SVC26MODE)
159 return (state->Reg[15]);
161 return (R15PC | ECC | ER15INT | EMODE);
164 /***************************************************************************\
165 * This routine sets the value of Register 15. *
166 \***************************************************************************/
169 ARMul_SetR15 (ARMul_State * state, ARMword value)
172 state->Reg[15] = value & PCBITS;
175 state->Reg[15] = value;
176 ARMul_R15Altered (state);
181 /***************************************************************************\
182 * This routine returns the value of the CPSR *
183 \***************************************************************************/
186 ARMul_GetCPSR (ARMul_State * state)
191 /***************************************************************************\
192 * This routine sets the value of the CPSR *
193 \***************************************************************************/
196 ARMul_SetCPSR (ARMul_State * state, ARMword value)
199 SETPSR (state->Cpsr, value);
200 ARMul_CPSRAltered (state);
203 /***************************************************************************\
204 * This routine does all the nasty bits involved in a write to the CPSR, *
205 * including updating the register bank, given a MSR instruction. *
206 \***************************************************************************/
209 ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs)
212 if (state->Bank == USERBANK)
213 { /* Only write flags in user mode */
216 SETCC (state->Cpsr, rhs);
220 { /* Not a user mode */
221 if (BITS (16, 19) == 9)
222 SETPSR (state->Cpsr, rhs);
224 SETINTMODE (state->Cpsr, rhs);
226 SETCC (state->Cpsr, rhs);
228 ARMul_CPSRAltered (state);
231 /***************************************************************************\
232 * Get an SPSR from the specified mode *
233 \***************************************************************************/
236 ARMul_GetSPSR (ARMul_State * state, ARMword mode)
238 ARMword bank = ModeToBank (state, mode & MODEBITS);
239 if (bank == USERBANK || bank == DUMMYBANK)
242 return (state->Spsr[bank]);
245 /***************************************************************************\
246 * This routine does a write to an SPSR *
247 \***************************************************************************/
250 ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value)
252 ARMword bank = ModeToBank (state, mode & MODEBITS);
253 if (bank != USERBANK && bank != DUMMYBANK)
254 state->Spsr[bank] = value;
257 /***************************************************************************\
258 * This routine does a write to the current SPSR, given an MSR instruction *
259 \***************************************************************************/
262 ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs)
264 if (state->Bank != USERBANK && state->Bank != DUMMYBANK)
266 if (BITS (16, 19) == 9)
267 SETPSR (state->Spsr[state->Bank], rhs);
269 SETINTMODE (state->Spsr[state->Bank], rhs);
271 SETCC (state->Spsr[state->Bank], rhs);
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 \***************************************************************************/
281 ARMul_CPSRAltered (ARMul_State * state)
285 if (state->prog32Sig == LOW)
286 state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS);
287 oldmode = state->Mode;
288 if (state->Mode != (state->Cpsr & MODEBITS))
291 ARMul_SwitchMode (state, state->Mode, state->Cpsr & MODEBITS);
292 state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
295 ASSIGNINT (state->Cpsr & INTBITS);
296 ASSIGNN ((state->Cpsr & NBIT) != 0);
297 ASSIGNZ ((state->Cpsr & ZBIT) != 0);
298 ASSIGNC ((state->Cpsr & CBIT) != 0);
299 ASSIGNV ((state->Cpsr & VBIT) != 0);
301 ASSIGNT ((state->Cpsr & TBIT) != 0);
304 if (oldmode > SVC26MODE)
306 if (state->Mode <= SVC26MODE)
308 state->Emulate = CHANGEMODE;
309 state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
314 if (state->Mode > SVC26MODE)
316 state->Emulate = CHANGEMODE;
317 state->Reg[15] = R15PC;
320 state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
325 /***************************************************************************\
326 * This routine updates the state of the emulator after register 15 has *
327 * been changed. Both the processor flags and register bank are updated. *
328 * This routine should only be called from a 26 bit mode. *
329 \***************************************************************************/
332 ARMul_R15Altered (ARMul_State * state)
334 if (state->Mode != R15MODE)
336 state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE);
337 state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
339 if (state->Mode > SVC26MODE)
340 state->Emulate = CHANGEMODE;
341 ASSIGNR15INT (R15INT);
342 ASSIGNN ((state->Reg[15] & NBIT) != 0);
343 ASSIGNZ ((state->Reg[15] & ZBIT) != 0);
344 ASSIGNC ((state->Reg[15] & CBIT) != 0);
345 ASSIGNV ((state->Reg[15] & VBIT) != 0);
348 /***************************************************************************\
349 * This routine controls the saving and restoring of registers across mode *
350 * changes. The regbank matrix is largely unused, only rows 13 and 14 are *
351 * used across all modes, 8 to 14 are used for FIQ, all others use the USER *
352 * column. It's easier this way. old and new parameter are modes numbers. *
353 * Notice the side effect of changing the Bank variable. *
354 \***************************************************************************/
357 ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode)
361 oldmode = ModeToBank (state, oldmode);
362 state->Bank = ModeToBank (state, newmode);
363 if (oldmode != state->Bank)
364 { /* really need to do it */
366 { /* save away the old registers */
372 if (state->Bank == FIQBANK)
373 for (i = 8; i < 13; i++)
374 state->RegBank[USERBANK][i] = state->Reg[i];
375 state->RegBank[oldmode][13] = state->Reg[13];
376 state->RegBank[oldmode][14] = state->Reg[14];
379 for (i = 8; i < 15; i++)
380 state->RegBank[FIQBANK][i] = state->Reg[i];
383 for (i = 8; i < 15; i++)
384 state->RegBank[DUMMYBANK][i] = 0;
389 { /* restore the new registers */
395 if (oldmode == FIQBANK)
396 for (i = 8; i < 13; i++)
397 state->Reg[i] = state->RegBank[USERBANK][i];
398 state->Reg[13] = state->RegBank[state->Bank][13];
399 state->Reg[14] = state->RegBank[state->Bank][14];
402 for (i = 8; i < 15; i++)
403 state->Reg[i] = state->RegBank[FIQBANK][i];
406 for (i = 8; i < 15; i++)
414 /***************************************************************************\
415 * Given a processor mode, this routine returns the register bank that *
416 * will be accessed in that mode. *
417 \***************************************************************************/
420 ModeToBank (ARMul_State * state, ARMword mode)
422 static ARMword bankofmode[] = { USERBANK, FIQBANK, IRQBANK, SVCBANK,
423 DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
424 DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
425 DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
426 USERBANK, FIQBANK, IRQBANK, SVCBANK,
427 DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK,
428 DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK
431 if (mode > UNDEF32MODE)
434 return (bankofmode[mode]);
437 /***************************************************************************\
438 * Returns the register number of the nth register in a reg list. *
439 \***************************************************************************/
442 ARMul_NthReg (ARMword instr, unsigned number)
446 for (bit = 0, upto = 0; upto <= number; bit++)
452 /***************************************************************************\
453 * Assigns the N and Z flags depending on the value of result *
454 \***************************************************************************/
457 ARMul_NegZero (ARMul_State * state, ARMword result)
464 else if (result == 0)
476 /* Compute whether an addition of A and B, giving RESULT, overflowed. */
478 AddOverflow (ARMword a, ARMword b, ARMword result)
480 return ((NEG (a) && NEG (b) && POS (result))
481 || (POS (a) && POS (b) && NEG (result)));
484 /* Compute whether a subtraction of A and B, giving RESULT, overflowed. */
486 SubOverflow (ARMword a, ARMword b, ARMword result)
488 return ((NEG (a) && POS (b) && POS (result))
489 || (POS (a) && NEG (b) && NEG (result)));
492 /***************************************************************************\
493 * Assigns the C flag after an addition of a and b to give result *
494 \***************************************************************************/
497 ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
499 ASSIGNC ((NEG (a) && NEG (b)) ||
500 (NEG (a) && POS (result)) || (NEG (b) && POS (result)));
503 /***************************************************************************\
504 * Assigns the V flag after an addition of a and b to give result *
505 \***************************************************************************/
508 ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
510 ASSIGNV (AddOverflow (a, b, result));
513 /***************************************************************************\
514 * Assigns the C flag after an subtraction of a and b to give result *
515 \***************************************************************************/
518 ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
520 ASSIGNC ((NEG (a) && POS (b)) ||
521 (NEG (a) && POS (result)) || (POS (b) && POS (result)));
524 /***************************************************************************\
525 * Assigns the V flag after an subtraction of a and b to give result *
526 \***************************************************************************/
529 ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
531 ASSIGNV (SubOverflow (a, b, result));
534 /***************************************************************************\
535 * This function does the work of generating the addresses used in an *
536 * LDC instruction. The code here is always post-indexed, it's up to the *
537 * caller to get the input address correct and to handle base register *
538 * modification. It also handles the Busy-Waiting. *
539 \***************************************************************************/
542 ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
548 if (ADDREXCEPT (address))
550 INTERNALABORT (address);
552 cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0);
553 while (cpab == ARMul_BUSY)
555 ARMul_Icycles (state, 1, 0);
556 if (IntPending (state))
558 cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
562 cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, 0);
564 if (cpab == ARMul_CANT)
569 cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0);
570 data = ARMul_LoadWordN (state, address);
573 LSBase = state->Base;
574 cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
575 while (cpab == ARMul_INC)
578 data = ARMul_LoadWordN (state, address);
579 cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
581 if (state->abortSig || state->Aborted)
587 /***************************************************************************\
588 * This function does the work of generating the addresses used in an *
589 * STC instruction. The code here is always post-indexed, it's up to the *
590 * caller to get the input address correct and to handle base register *
591 * modification. It also handles the Busy-Waiting. *
592 \***************************************************************************/
595 ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
601 if (ADDREXCEPT (address) || VECTORACCESS (address))
603 INTERNALABORT (address);
605 cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data);
606 while (cpab == ARMul_BUSY)
608 ARMul_Icycles (state, 1, 0);
609 if (IntPending (state))
611 cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
615 cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, &data);
617 if (cpab == ARMul_CANT)
623 if (ADDREXCEPT (address) || VECTORACCESS (address))
625 INTERNALABORT (address);
630 LSBase = state->Base;
631 cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
632 ARMul_StoreWordN (state, address, data);
633 while (cpab == ARMul_INC)
636 cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
637 ARMul_StoreWordN (state, address, data);
639 if (state->abortSig || state->Aborted)
645 /***************************************************************************\
646 * This function does the Busy-Waiting for an MCR instruction. *
647 \***************************************************************************/
650 ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
654 cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source);
655 while (cpab == ARMul_BUSY)
657 ARMul_Icycles (state, 1, 0);
658 if (IntPending (state))
660 cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
664 cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, source);
666 if (cpab == ARMul_CANT)
667 ARMul_Abort (state, ARMul_UndefinedInstrV);
671 ARMul_Ccycles (state, 1, 0);
675 /***************************************************************************\
676 * This function does the Busy-Waiting for an MRC instruction. *
677 \***************************************************************************/
680 ARMul_MRC (ARMul_State * state, ARMword instr)
685 cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
686 while (cpab == ARMul_BUSY)
688 ARMul_Icycles (state, 1, 0);
689 if (IntPending (state))
691 cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
695 cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, &result);
697 if (cpab == ARMul_CANT)
699 ARMul_Abort (state, ARMul_UndefinedInstrV);
700 result = ECC; /* Parent will destroy the flags otherwise */
705 ARMul_Ccycles (state, 1, 0);
706 ARMul_Icycles (state, 1, 0);
711 /***************************************************************************\
712 * This function does the Busy-Waiting for an CDP instruction. *
713 \***************************************************************************/
716 ARMul_CDP (ARMul_State * state, ARMword instr)
720 cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr);
721 while (cpab == ARMul_BUSY)
723 ARMul_Icycles (state, 1, 0);
724 if (IntPending (state))
726 cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, instr);
730 cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr);
732 if (cpab == ARMul_CANT)
733 ARMul_Abort (state, ARMul_UndefinedInstrV);
738 /***************************************************************************\
739 * This function handles Undefined instructions, as CP isntruction *
740 \***************************************************************************/
743 ARMul_UndefInstr (ARMul_State * state, ARMword instr)
745 ARMul_Abort (state, ARMul_UndefinedInstrV);
748 /***************************************************************************\
749 * Return TRUE if an interrupt is pending, FALSE otherwise. *
750 \***************************************************************************/
753 IntPending (ARMul_State * state)
755 if (state->Exception)
756 { /* Any exceptions */
757 if (state->NresetSig == LOW)
759 ARMul_Abort (state, ARMul_ResetV);
762 else if (!state->NfiqSig && !FFLAG)
764 ARMul_Abort (state, ARMul_FIQV);
767 else if (!state->NirqSig && !IFLAG)
769 ARMul_Abort (state, ARMul_IRQV);
776 /***************************************************************************\
777 * Align a word access to a non word boundary *
778 \***************************************************************************/
781 ARMul_Align (ARMul_State * state, ARMword address, ARMword data)
782 { /* this code assumes the address is really unaligned,
783 as a shift by 32 is undefined in C */
785 address = (address & 3) << 3; /* get the word address */
786 return ((data >> address) | (data << (32 - address))); /* rot right */
789 /***************************************************************************\
790 * This routine is used to call another routine after a certain number of *
791 * cycles have been executed. The first parameter is the number of cycles *
792 * delay before the function is called, the second argument is a pointer *
793 * to the function. A delay of zero doesn't work, just call the function. *
794 \***************************************************************************/
797 ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
801 struct EventNode *event;
803 if (state->EventSet++ == 0)
804 state->Now = ARMul_Time (state);
805 when = (state->Now + delay) % EVENTLISTSIZE;
806 event = (struct EventNode *) malloc (sizeof (struct EventNode));
808 event->next = *(state->EventPtr + when);
809 *(state->EventPtr + when) = event;
812 /***************************************************************************\
813 * This routine is called at the beginning of every cycle, to envoke *
814 * scheduled events. *
815 \***************************************************************************/
818 ARMul_EnvokeEvent (ARMul_State * state)
820 static unsigned long then;
823 state->Now = ARMul_Time (state) % EVENTLISTSIZE;
824 if (then < state->Now) /* schedule events */
825 EnvokeList (state, then, state->Now);
826 else if (then > state->Now)
827 { /* need to wrap around the list */
828 EnvokeList (state, then, EVENTLISTSIZE - 1L);
829 EnvokeList (state, 0L, state->Now);
834 EnvokeList (ARMul_State * state, unsigned long from, unsigned long to)
835 /* envokes all the entries in a range */
837 struct EventNode *anevent;
839 for (; from <= to; from++)
841 anevent = *(state->EventPtr + from);
844 (anevent->func) (state);
846 anevent = anevent->next;
848 *(state->EventPtr + from) = NULL;
852 /***************************************************************************\
853 * This routine is returns the number of clock ticks since the last reset. *
854 \***************************************************************************/
857 ARMul_Time (ARMul_State * state)
859 return (state->NumScycles + state->NumNcycles +
860 state->NumIcycles + state->NumCcycles + state->NumFcycles);