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)
189 /***************************************************************************\
190 * This routine sets the value of the CPSR *
191 \***************************************************************************/
194 ARMul_SetCPSR (ARMul_State * state, ARMword value)
197 SETPSR (state->Cpsr, value);
198 ARMul_CPSRAltered (state);
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 \***************************************************************************/
207 ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs)
210 if (state->Bank == USERBANK)
211 { /* Only write flags in user mode */
214 SETCC (state->Cpsr, rhs);
218 { /* Not a user mode */
219 if (BITS (16, 19) == 9)
220 SETPSR (state->Cpsr, rhs);
222 SETINTMODE (state->Cpsr, rhs);
224 SETCC (state->Cpsr, rhs);
226 ARMul_CPSRAltered (state);
229 /***************************************************************************\
230 * Get an SPSR from the specified mode *
231 \***************************************************************************/
234 ARMul_GetSPSR (ARMul_State * state, ARMword mode)
236 ARMword bank = ModeToBank (mode & MODEBITS);
238 if (! BANK_CAN_ACCESS_SPSR (bank))
241 return state->Spsr[bank];
244 /***************************************************************************\
245 * This routine does a write to an SPSR *
246 \***************************************************************************/
249 ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value)
251 ARMword bank = ModeToBank (mode & MODEBITS);
253 if (BANK_CAN_ACCESS_SPSR (bank))
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 (BANK_CAN_ACCESS_SPSR (state->Bank))
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);
288 oldmode = state->Mode;
290 if (state->Mode != (state->Cpsr & MODEBITS))
293 ARMul_SwitchMode (state, state->Mode, state->Cpsr & MODEBITS);
295 state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
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);
304 ASSIGNT ((state->Cpsr & TBIT) != 0);
307 if (oldmode > SVC26MODE)
309 if (state->Mode <= SVC26MODE)
311 state->Emulate = CHANGEMODE;
312 state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
317 if (state->Mode > SVC26MODE)
319 state->Emulate = CHANGEMODE;
320 state->Reg[15] = R15PC;
323 state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
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 \***************************************************************************/
334 ARMul_R15Altered (ARMul_State * state)
336 if (state->Mode != R15MODE)
338 state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE);
339 state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
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);
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 \***************************************************************************/
359 ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode)
365 oldbank = ModeToBank (oldmode);
366 newbank = state->Bank = ModeToBank (newmode);
368 if (oldbank != newbank)
369 { /* really need to do it */
371 { /* save away the old registers */
373 /* The System mode uses the USER bank. */
381 if (newbank == FIQBANK)
382 for (i = 8; i < 13; i++)
383 state->RegBank[USERBANK][i] = state->Reg[i];
384 state->RegBank[oldbank][13] = state->Reg[13];
385 state->RegBank[oldbank][14] = state->Reg[14];
388 for (i = 8; i < 15; i++)
389 state->RegBank[FIQBANK][i] = state->Reg[i];
392 for (i = 8; i < 15; i++)
393 state->RegBank[DUMMYBANK][i] = 0;
400 { /* restore the new registers */
409 if (oldbank == FIQBANK)
410 for (i = 8; i < 13; i++)
411 state->Reg[i] = state->RegBank[USERBANK][i];
412 state->Reg[13] = state->RegBank[newbank][13];
413 state->Reg[14] = state->RegBank[newbank][14];
416 for (i = 8; i < 15; i++)
417 state->Reg[i] = state->RegBank[FIQBANK][i];
420 for (i = 8; i < 15; i++)
431 /***************************************************************************\
432 * Given a processor mode, this routine returns the register bank that *
433 * will be accessed in that mode. *
434 \***************************************************************************/
437 ModeToBank (ARMword mode)
439 static ARMword bankofmode[] =
441 USERBANK, FIQBANK, IRQBANK, SVCBANK,
442 DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
443 DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
444 DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
445 USERBANK, FIQBANK, IRQBANK, SVCBANK,
446 DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK,
447 DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK,
448 DUMMYBANK, DUMMYBANK, DUMMYBANK, SYSTEMBANK
451 if (mode >= (sizeof (bankofmode) / sizeof (bankofmode[0])))
454 return bankofmode[mode];
457 /***************************************************************************\
458 * Returns the register number of the nth register in a reg list. *
459 \***************************************************************************/
462 ARMul_NthReg (ARMword instr, unsigned number)
466 for (bit = 0, upto = 0; upto <= number; bit++)
472 /***************************************************************************\
473 * Assigns the N and Z flags depending on the value of result *
474 \***************************************************************************/
477 ARMul_NegZero (ARMul_State * state, ARMword result)
484 else if (result == 0)
496 /* Compute whether an addition of A and B, giving RESULT, overflowed. */
498 AddOverflow (ARMword a, ARMword b, ARMword result)
500 return ((NEG (a) && NEG (b) && POS (result))
501 || (POS (a) && POS (b) && NEG (result)));
504 /* Compute whether a subtraction of A and B, giving RESULT, overflowed. */
506 SubOverflow (ARMword a, ARMword b, ARMword result)
508 return ((NEG (a) && POS (b) && POS (result))
509 || (POS (a) && NEG (b) && NEG (result)));
512 /***************************************************************************\
513 * Assigns the C flag after an addition of a and b to give result *
514 \***************************************************************************/
517 ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
519 ASSIGNC ((NEG (a) && NEG (b)) ||
520 (NEG (a) && POS (result)) || (NEG (b) && POS (result)));
523 /***************************************************************************\
524 * Assigns the V flag after an addition of a and b to give result *
525 \***************************************************************************/
528 ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
530 ASSIGNV (AddOverflow (a, b, result));
533 /***************************************************************************\
534 * Assigns the C flag after an subtraction of a and b to give result *
535 \***************************************************************************/
538 ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
540 ASSIGNC ((NEG (a) && POS (b)) ||
541 (NEG (a) && POS (result)) || (POS (b) && POS (result)));
544 /***************************************************************************\
545 * Assigns the V flag after an subtraction of a and b to give result *
546 \***************************************************************************/
549 ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
551 ASSIGNV (SubOverflow (a, b, result));
554 /***************************************************************************\
555 * This function does the work of generating the addresses used in an *
556 * LDC instruction. The code here is always post-indexed, it's up to the *
557 * caller to get the input address correct and to handle base register *
558 * modification. It also handles the Busy-Waiting. *
559 \***************************************************************************/
562 ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
568 if (ADDREXCEPT (address))
570 INTERNALABORT (address);
572 cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0);
573 while (cpab == ARMul_BUSY)
575 ARMul_Icycles (state, 1, 0);
576 if (IntPending (state))
578 cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
582 cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, 0);
584 if (cpab == ARMul_CANT)
589 cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0);
590 data = ARMul_LoadWordN (state, address);
593 LSBase = state->Base;
594 cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
595 while (cpab == ARMul_INC)
598 data = ARMul_LoadWordN (state, address);
599 cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
601 if (state->abortSig || state->Aborted)
607 /***************************************************************************\
608 * This function does the work of generating the addresses used in an *
609 * STC instruction. The code here is always post-indexed, it's up to the *
610 * caller to get the input address correct and to handle base register *
611 * modification. It also handles the Busy-Waiting. *
612 \***************************************************************************/
615 ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
621 if (ADDREXCEPT (address) || VECTORACCESS (address))
623 INTERNALABORT (address);
625 cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data);
626 while (cpab == ARMul_BUSY)
628 ARMul_Icycles (state, 1, 0);
629 if (IntPending (state))
631 cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
635 cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, &data);
637 if (cpab == ARMul_CANT)
643 if (ADDREXCEPT (address) || VECTORACCESS (address))
645 INTERNALABORT (address);
650 LSBase = state->Base;
651 cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
652 ARMul_StoreWordN (state, address, data);
653 while (cpab == ARMul_INC)
656 cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
657 ARMul_StoreWordN (state, address, data);
659 if (state->abortSig || state->Aborted)
665 /***************************************************************************\
666 * This function does the Busy-Waiting for an MCR instruction. *
667 \***************************************************************************/
670 ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
674 cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source);
676 while (cpab == ARMul_BUSY)
678 ARMul_Icycles (state, 1, 0);
680 if (IntPending (state))
682 cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
686 cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, source);
689 if (cpab == ARMul_CANT)
690 ARMul_Abort (state, ARMul_UndefinedInstrV);
694 ARMul_Ccycles (state, 1, 0);
698 /***************************************************************************\
699 * This function does the Busy-Waiting for an MRC instruction. *
700 \***************************************************************************/
703 ARMul_MRC (ARMul_State * state, ARMword instr)
708 cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
709 while (cpab == ARMul_BUSY)
711 ARMul_Icycles (state, 1, 0);
712 if (IntPending (state))
714 cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
718 cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, &result);
720 if (cpab == ARMul_CANT)
722 ARMul_Abort (state, ARMul_UndefinedInstrV);
723 result = ECC; /* Parent will destroy the flags otherwise */
728 ARMul_Ccycles (state, 1, 0);
729 ARMul_Icycles (state, 1, 0);
734 /***************************************************************************\
735 * This function does the Busy-Waiting for an CDP instruction. *
736 \***************************************************************************/
739 ARMul_CDP (ARMul_State * state, ARMword instr)
743 cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr);
744 while (cpab == ARMul_BUSY)
746 ARMul_Icycles (state, 1, 0);
747 if (IntPending (state))
749 cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, instr);
753 cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr);
755 if (cpab == ARMul_CANT)
756 ARMul_Abort (state, ARMul_UndefinedInstrV);
761 /***************************************************************************\
762 * This function handles Undefined instructions, as CP isntruction *
763 \***************************************************************************/
766 ARMul_UndefInstr (ARMul_State * state, ARMword instr ATTRIBUTE_UNUSED)
768 ARMul_Abort (state, ARMul_UndefinedInstrV);
771 /***************************************************************************\
772 * Return TRUE if an interrupt is pending, FALSE otherwise. *
773 \***************************************************************************/
776 IntPending (ARMul_State * state)
778 if (state->Exception)
779 { /* Any exceptions */
780 if (state->NresetSig == LOW)
782 ARMul_Abort (state, ARMul_ResetV);
785 else if (!state->NfiqSig && !FFLAG)
787 ARMul_Abort (state, ARMul_FIQV);
790 else if (!state->NirqSig && !IFLAG)
792 ARMul_Abort (state, ARMul_IRQV);
799 /***************************************************************************\
800 * Align a word access to a non word boundary *
801 \***************************************************************************/
804 ARMul_Align (state, address, data)
805 ARMul_State * state ATTRIBUTE_UNUSED;
809 /* This code assumes the address is really unaligned,
810 as a shift by 32 is undefined in C. */
812 address = (address & 3) << 3; /* get the word address */
813 return ((data >> address) | (data << (32 - address))); /* rot right */
816 /***************************************************************************\
817 * This routine is used to call another routine after a certain number of *
818 * cycles have been executed. The first parameter is the number of cycles *
819 * delay before the function is called, the second argument is a pointer *
820 * to the function. A delay of zero doesn't work, just call the function. *
821 \***************************************************************************/
824 ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
828 struct EventNode *event;
830 if (state->EventSet++ == 0)
831 state->Now = ARMul_Time (state);
832 when = (state->Now + delay) % EVENTLISTSIZE;
833 event = (struct EventNode *) malloc (sizeof (struct EventNode));
835 event->next = *(state->EventPtr + when);
836 *(state->EventPtr + when) = event;
839 /***************************************************************************\
840 * This routine is called at the beginning of every cycle, to envoke *
841 * scheduled events. *
842 \***************************************************************************/
845 ARMul_EnvokeEvent (ARMul_State * state)
847 static unsigned long then;
850 state->Now = ARMul_Time (state) % EVENTLISTSIZE;
851 if (then < state->Now) /* schedule events */
852 EnvokeList (state, then, state->Now);
853 else if (then > state->Now)
854 { /* need to wrap around the list */
855 EnvokeList (state, then, EVENTLISTSIZE - 1L);
856 EnvokeList (state, 0L, state->Now);
861 EnvokeList (ARMul_State * state, unsigned long from, unsigned long to)
862 /* envokes all the entries in a range */
864 struct EventNode *anevent;
866 for (; from <= to; from++)
868 anevent = *(state->EventPtr + from);
871 (anevent->func) (state);
873 anevent = anevent->next;
875 *(state->EventPtr + from) = NULL;
879 /***************************************************************************\
880 * This routine is returns the number of clock ticks since the last reset. *
881 \***************************************************************************/
884 ARMul_Time (ARMul_State * state)
886 return (state->NumScycles + state->NumNcycles +
887 state->NumIcycles + state->NumCcycles + state->NumFcycles);