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. */
22 /***************************************************************************\
23 * Definitions for the support routines *
24 \***************************************************************************/
26 ARMword ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg);
27 void ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg,
29 ARMword ARMul_GetPC (ARMul_State * state);
30 ARMword ARMul_GetNextPC (ARMul_State * state);
31 void ARMul_SetPC (ARMul_State * state, ARMword value);
32 ARMword ARMul_GetR15 (ARMul_State * state);
33 void ARMul_SetR15 (ARMul_State * state, ARMword value);
35 ARMword ARMul_GetCPSR (ARMul_State * state);
36 void ARMul_SetCPSR (ARMul_State * state, ARMword value);
37 ARMword ARMul_GetSPSR (ARMul_State * state, ARMword mode);
38 void ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value);
40 void ARMul_CPSRAltered (ARMul_State * state);
41 void ARMul_R15Altered (ARMul_State * state);
43 ARMword ARMul_SwitchMode (ARMul_State * state, ARMword oldmode,
45 static ARMword ModeToBank (ARMword mode);
47 unsigned ARMul_NthReg (ARMword instr, unsigned number);
49 void ARMul_NegZero (ARMul_State * state, ARMword result);
50 void ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b,
52 void ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b,
54 void ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b,
56 void ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b,
59 void ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address);
60 void ARMul_STC (ARMul_State * state, ARMword instr, ARMword address);
61 void ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source);
62 ARMword ARMul_MRC (ARMul_State * state, ARMword instr);
63 void ARMul_CDP (ARMul_State * state, ARMword instr);
64 unsigned IntPending (ARMul_State * state);
66 ARMword ARMul_Align (ARMul_State * state, ARMword address, ARMword data);
68 void ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
70 void ARMul_EnvokeEvent (ARMul_State * state);
71 unsigned long ARMul_Time (ARMul_State * state);
72 static void EnvokeList (ARMul_State * state, unsigned long from,
76 { /* An event list node */
77 unsigned (*func) (); /* The function to call */
78 struct EventNode *next;
81 /***************************************************************************\
82 * This routine returns the value of a register from a mode. *
83 \***************************************************************************/
86 ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg)
89 if (mode != state->Mode)
90 return (state->RegBank[ModeToBank ((ARMword) mode)][reg]);
92 return (state->Reg[reg]);
95 /***************************************************************************\
96 * This routine sets the value of a register for a mode. *
97 \***************************************************************************/
100 ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value)
103 if (mode != state->Mode)
104 state->RegBank[ModeToBank ((ARMword) mode)][reg] = value;
106 state->Reg[reg] = value;
109 /***************************************************************************\
110 * This routine returns the value of the PC, mode independently. *
111 \***************************************************************************/
114 ARMul_GetPC (ARMul_State * state)
116 if (state->Mode > SVC26MODE)
117 return (state->Reg[15]);
122 /***************************************************************************\
123 * This routine returns the value of the PC, mode independently. *
124 \***************************************************************************/
127 ARMul_GetNextPC (ARMul_State * state)
129 if (state->Mode > SVC26MODE)
130 return (state->Reg[15] + isize);
132 return ((state->Reg[15] + isize) & R15PCBITS);
135 /***************************************************************************\
136 * This routine sets the value of the PC. *
137 \***************************************************************************/
140 ARMul_SetPC (ARMul_State * state, ARMword value)
143 state->Reg[15] = value & PCBITS;
145 state->Reg[15] = R15CCINTMODE | (value & R15PCBITS);
149 /***************************************************************************\
150 * This routine returns the value of register 15, mode independently. *
151 \***************************************************************************/
154 ARMul_GetR15 (ARMul_State * state)
156 if (state->Mode > SVC26MODE)
157 return (state->Reg[15]);
159 return (R15PC | ECC | ER15INT | EMODE);
162 /***************************************************************************\
163 * This routine sets the value of Register 15. *
164 \***************************************************************************/
167 ARMul_SetR15 (ARMul_State * state, ARMword value)
170 state->Reg[15] = value & PCBITS;
173 state->Reg[15] = value;
174 ARMul_R15Altered (state);
179 /***************************************************************************\
180 * This routine returns the value of the CPSR *
181 \***************************************************************************/
184 ARMul_GetCPSR (ARMul_State * state)
186 return (CPSR | state->Cpsr);
189 /***************************************************************************\
190 * This routine sets the value of the CPSR *
191 \***************************************************************************/
194 ARMul_SetCPSR (ARMul_State * state, ARMword value)
197 ARMul_CPSRAltered (state);
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 \***************************************************************************/
206 ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs)
208 state->Cpsr = ARMul_GetCPSR (state);
209 if (state->Mode != USER26MODE
210 && state->Mode != USER32MODE)
211 { /* In user mode, only write flags */
213 SETPSR_C (state->Cpsr, rhs);
215 SETPSR_X (state->Cpsr, rhs);
217 SETPSR_S (state->Cpsr, rhs);
220 SETPSR_F (state->Cpsr, rhs);
221 ARMul_CPSRAltered (state);
224 /***************************************************************************\
225 * Get an SPSR from the specified mode *
226 \***************************************************************************/
229 ARMul_GetSPSR (ARMul_State * state, ARMword mode)
231 ARMword bank = ModeToBank (mode & MODEBITS);
233 if (! BANK_CAN_ACCESS_SPSR (bank))
234 return ARMul_GetCPSR (state);
236 return state->Spsr[bank];
239 /***************************************************************************\
240 * This routine does a write to an SPSR *
241 \***************************************************************************/
244 ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value)
246 ARMword bank = ModeToBank (mode & MODEBITS);
248 if (BANK_CAN_ACCESS_SPSR (bank))
249 state->Spsr[bank] = value;
252 /***************************************************************************\
253 * This routine does a write to the current SPSR, given an MSR instruction *
254 \***************************************************************************/
257 ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs)
259 if (BANK_CAN_ACCESS_SPSR (state->Bank))
262 SETPSR_C (state->Spsr[state->Bank], rhs);
264 SETPSR_X (state->Spsr[state->Bank], rhs);
266 SETPSR_S (state->Spsr[state->Bank], rhs);
268 SETPSR_F (state->Spsr[state->Bank], rhs);
272 /***************************************************************************\
273 * This routine updates the state of the emulator after the Cpsr has been *
274 * changed. Both the processor flags and register bank are updated. *
275 \***************************************************************************/
278 ARMul_CPSRAltered (ARMul_State * state)
282 if (state->prog32Sig == LOW)
283 state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS);
285 oldmode = state->Mode;
287 if (state->Mode != (state->Cpsr & MODEBITS))
290 ARMul_SwitchMode (state, state->Mode, state->Cpsr & MODEBITS);
292 state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
294 state->Cpsr &= ~MODEBITS;
296 ASSIGNINT (state->Cpsr & INTBITS);
297 state->Cpsr &= ~INTBITS;
298 ASSIGNN ((state->Cpsr & NBIT) != 0);
299 state->Cpsr &= ~NBIT;
300 ASSIGNZ ((state->Cpsr & ZBIT) != 0);
301 state->Cpsr &= ~ZBIT;
302 ASSIGNC ((state->Cpsr & CBIT) != 0);
303 state->Cpsr &= ~CBIT;
304 ASSIGNV ((state->Cpsr & VBIT) != 0);
305 state->Cpsr &= ~VBIT;
306 ASSIGNS ((state->Cpsr & SBIT) != 0);
307 state->Cpsr &= ~SBIT;
309 ASSIGNT ((state->Cpsr & TBIT) != 0);
310 state->Cpsr &= ~TBIT;
313 if (oldmode > SVC26MODE)
315 if (state->Mode <= SVC26MODE)
317 state->Emulate = CHANGEMODE;
318 state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
323 if (state->Mode > SVC26MODE)
325 state->Emulate = CHANGEMODE;
326 state->Reg[15] = R15PC;
329 state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
333 /***************************************************************************\
334 * This routine updates the state of the emulator after register 15 has *
335 * been changed. Both the processor flags and register bank are updated. *
336 * This routine should only be called from a 26 bit mode. *
337 \***************************************************************************/
340 ARMul_R15Altered (ARMul_State * state)
342 if (state->Mode != R15MODE)
344 state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE);
345 state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
347 if (state->Mode > SVC26MODE)
348 state->Emulate = CHANGEMODE;
349 ASSIGNR15INT (R15INT);
350 ASSIGNN ((state->Reg[15] & NBIT) != 0);
351 ASSIGNZ ((state->Reg[15] & ZBIT) != 0);
352 ASSIGNC ((state->Reg[15] & CBIT) != 0);
353 ASSIGNV ((state->Reg[15] & VBIT) != 0);
356 /***************************************************************************\
357 * This routine controls the saving and restoring of registers across mode *
358 * changes. The regbank matrix is largely unused, only rows 13 and 14 are *
359 * used across all modes, 8 to 14 are used for FIQ, all others use the USER *
360 * column. It's easier this way. old and new parameter are modes numbers. *
361 * Notice the side effect of changing the Bank variable. *
362 \***************************************************************************/
365 ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode)
371 oldbank = ModeToBank (oldmode);
372 newbank = state->Bank = ModeToBank (newmode);
374 if (oldbank != newbank)
375 { /* really need to do it */
377 { /* save away the old registers */
383 if (newbank == FIQBANK)
384 for (i = 8; i < 13; i++)
385 state->RegBank[USERBANK][i] = state->Reg[i];
386 state->RegBank[oldbank][13] = state->Reg[13];
387 state->RegBank[oldbank][14] = state->Reg[14];
390 for (i = 8; i < 15; i++)
391 state->RegBank[FIQBANK][i] = state->Reg[i];
394 for (i = 8; i < 15; i++)
395 state->RegBank[DUMMYBANK][i] = 0;
402 { /* restore the new registers */
408 if (oldbank == FIQBANK)
409 for (i = 8; i < 13; i++)
410 state->Reg[i] = state->RegBank[USERBANK][i];
411 state->Reg[13] = state->RegBank[newbank][13];
412 state->Reg[14] = state->RegBank[newbank][14];
415 for (i = 8; i < 15; i++)
416 state->Reg[i] = state->RegBank[FIQBANK][i];
419 for (i = 8; i < 15; i++)
430 /***************************************************************************\
431 * Given a processor mode, this routine returns the register bank that *
432 * will be accessed in that mode. *
433 \***************************************************************************/
436 ModeToBank (ARMword mode)
438 static ARMword bankofmode[] =
440 USERBANK, FIQBANK, IRQBANK, SVCBANK,
441 DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
442 DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
443 DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
444 USERBANK, FIQBANK, IRQBANK, SVCBANK,
445 DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK,
446 DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK,
447 DUMMYBANK, DUMMYBANK, DUMMYBANK, SYSTEMBANK
450 if (mode >= (sizeof (bankofmode) / sizeof (bankofmode[0])))
453 return bankofmode[mode];
456 /***************************************************************************\
457 * Returns the register number of the nth register in a reg list. *
458 \***************************************************************************/
461 ARMul_NthReg (ARMword instr, unsigned number)
465 for (bit = 0, upto = 0; upto <= number; bit++)
471 /***************************************************************************\
472 * Assigns the N and Z flags depending on the value of result *
473 \***************************************************************************/
476 ARMul_NegZero (ARMul_State * state, ARMword result)
483 else if (result == 0)
495 /* Compute whether an addition of A and B, giving RESULT, overflowed. */
497 AddOverflow (ARMword a, ARMword b, ARMword result)
499 return ((NEG (a) && NEG (b) && POS (result))
500 || (POS (a) && POS (b) && NEG (result)));
503 /* Compute whether a subtraction of A and B, giving RESULT, overflowed. */
505 SubOverflow (ARMword a, ARMword b, ARMword result)
507 return ((NEG (a) && POS (b) && POS (result))
508 || (POS (a) && NEG (b) && NEG (result)));
511 /***************************************************************************\
512 * Assigns the C flag after an addition of a and b to give result *
513 \***************************************************************************/
516 ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
518 ASSIGNC ((NEG (a) && NEG (b)) ||
519 (NEG (a) && POS (result)) || (NEG (b) && POS (result)));
522 /***************************************************************************\
523 * Assigns the V flag after an addition of a and b to give result *
524 \***************************************************************************/
527 ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
529 ASSIGNV (AddOverflow (a, b, result));
532 /***************************************************************************\
533 * Assigns the C flag after an subtraction of a and b to give result *
534 \***************************************************************************/
537 ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
539 ASSIGNC ((NEG (a) && POS (b)) ||
540 (NEG (a) && POS (result)) || (POS (b) && POS (result)));
543 /***************************************************************************\
544 * Assigns the V flag after an subtraction of a and b to give result *
545 \***************************************************************************/
548 ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
550 ASSIGNV (SubOverflow (a, b, result));
553 /***************************************************************************\
554 * This function does the work of generating the addresses used in an *
555 * LDC instruction. The code here is always post-indexed, it's up to the *
556 * caller to get the input address correct and to handle base register *
557 * modification. It also handles the Busy-Waiting. *
558 \***************************************************************************/
561 ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
567 if (ADDREXCEPT (address))
569 INTERNALABORT (address);
571 cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0);
572 while (cpab == ARMul_BUSY)
574 ARMul_Icycles (state, 1, 0);
575 if (IntPending (state))
577 cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
581 cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, 0);
583 if (cpab == ARMul_CANT)
588 cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0);
589 data = ARMul_LoadWordN (state, address);
592 LSBase = state->Base;
593 cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
594 while (cpab == ARMul_INC)
597 data = ARMul_LoadWordN (state, address);
598 cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
600 if (state->abortSig || state->Aborted)
606 /***************************************************************************\
607 * This function does the work of generating the addresses used in an *
608 * STC instruction. The code here is always post-indexed, it's up to the *
609 * caller to get the input address correct and to handle base register *
610 * modification. It also handles the Busy-Waiting. *
611 \***************************************************************************/
614 ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
620 if (ADDREXCEPT (address) || VECTORACCESS (address))
622 INTERNALABORT (address);
624 cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data);
625 while (cpab == ARMul_BUSY)
627 ARMul_Icycles (state, 1, 0);
628 if (IntPending (state))
630 cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
634 cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, &data);
636 if (cpab == ARMul_CANT)
642 if (ADDREXCEPT (address) || VECTORACCESS (address))
644 INTERNALABORT (address);
649 LSBase = state->Base;
650 cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
651 ARMul_StoreWordN (state, address, data);
652 while (cpab == ARMul_INC)
655 cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
656 ARMul_StoreWordN (state, address, data);
658 if (state->abortSig || state->Aborted)
664 /***************************************************************************\
665 * This function does the Busy-Waiting for an MCR instruction. *
666 \***************************************************************************/
669 ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
673 cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source);
675 while (cpab == ARMul_BUSY)
677 ARMul_Icycles (state, 1, 0);
679 if (IntPending (state))
681 cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
685 cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, source);
688 if (cpab == ARMul_CANT)
689 ARMul_Abort (state, ARMul_UndefinedInstrV);
693 ARMul_Ccycles (state, 1, 0);
697 /***************************************************************************\
698 * This function does the Busy-Waiting for an MRC instruction. *
699 \***************************************************************************/
702 ARMul_MRC (ARMul_State * state, ARMword instr)
707 cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
708 while (cpab == ARMul_BUSY)
710 ARMul_Icycles (state, 1, 0);
711 if (IntPending (state))
713 cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
717 cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, &result);
719 if (cpab == ARMul_CANT)
721 ARMul_Abort (state, ARMul_UndefinedInstrV);
722 result = ECC; /* Parent will destroy the flags otherwise */
727 ARMul_Ccycles (state, 1, 0);
728 ARMul_Icycles (state, 1, 0);
733 /***************************************************************************\
734 * This function does the Busy-Waiting for an CDP instruction. *
735 \***************************************************************************/
738 ARMul_CDP (ARMul_State * state, ARMword instr)
742 cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr);
743 while (cpab == ARMul_BUSY)
745 ARMul_Icycles (state, 1, 0);
746 if (IntPending (state))
748 cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, instr);
752 cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr);
754 if (cpab == ARMul_CANT)
755 ARMul_Abort (state, ARMul_UndefinedInstrV);
760 /***************************************************************************\
761 * This function handles Undefined instructions, as CP isntruction *
762 \***************************************************************************/
765 ARMul_UndefInstr (ARMul_State * state, ARMword instr ATTRIBUTE_UNUSED)
767 ARMul_Abort (state, ARMul_UndefinedInstrV);
770 /***************************************************************************\
771 * Return TRUE if an interrupt is pending, FALSE otherwise. *
772 \***************************************************************************/
775 IntPending (ARMul_State * state)
777 if (state->Exception)
778 { /* Any exceptions */
779 if (state->NresetSig == LOW)
781 ARMul_Abort (state, ARMul_ResetV);
784 else if (!state->NfiqSig && !FFLAG)
786 ARMul_Abort (state, ARMul_FIQV);
789 else if (!state->NirqSig && !IFLAG)
791 ARMul_Abort (state, ARMul_IRQV);
798 /***************************************************************************\
799 * Align a word access to a non word boundary *
800 \***************************************************************************/
803 ARMul_Align (state, address, data)
804 ARMul_State * state ATTRIBUTE_UNUSED;
808 /* This code assumes the address is really unaligned,
809 as a shift by 32 is undefined in C. */
811 address = (address & 3) << 3; /* get the word address */
812 return ((data >> address) | (data << (32 - address))); /* rot right */
815 /***************************************************************************\
816 * This routine is used to call another routine after a certain number of *
817 * cycles have been executed. The first parameter is the number of cycles *
818 * delay before the function is called, the second argument is a pointer *
819 * to the function. A delay of zero doesn't work, just call the function. *
820 \***************************************************************************/
823 ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
827 struct EventNode *event;
829 if (state->EventSet++ == 0)
830 state->Now = ARMul_Time (state);
831 when = (state->Now + delay) % EVENTLISTSIZE;
832 event = (struct EventNode *) malloc (sizeof (struct EventNode));
834 event->next = *(state->EventPtr + when);
835 *(state->EventPtr + when) = event;
838 /***************************************************************************\
839 * This routine is called at the beginning of every cycle, to envoke *
840 * scheduled events. *
841 \***************************************************************************/
844 ARMul_EnvokeEvent (ARMul_State * state)
846 static unsigned long then;
849 state->Now = ARMul_Time (state) % EVENTLISTSIZE;
850 if (then < state->Now) /* schedule events */
851 EnvokeList (state, then, state->Now);
852 else if (then > state->Now)
853 { /* need to wrap around the list */
854 EnvokeList (state, then, EVENTLISTSIZE - 1L);
855 EnvokeList (state, 0L, state->Now);
860 EnvokeList (ARMul_State * state, unsigned long from, unsigned long to)
861 /* envokes all the entries in a range */
863 struct EventNode *anevent;
865 for (; from <= to; from++)
867 anevent = *(state->EventPtr + from);
870 (anevent->func) (state);
872 anevent = anevent->next;
874 *(state->EventPtr + from) = NULL;
878 /***************************************************************************\
879 * This routine is returns the number of clock ticks since the last reset. *
880 \***************************************************************************/
883 ARMul_Time (ARMul_State * state)
885 return (state->NumScycles + state->NumNcycles +
886 state->NumIcycles + state->NumCcycles + state->NumFcycles);