Home | History | Annotate | Line # | Download | only in arm
armsupp.c revision 1.1
      1  1.1  christos /*  armsupp.c -- ARMulator support code:  ARM6 Instruction Emulator.
      2  1.1  christos     Copyright (C) 1994 Advanced RISC Machines Ltd.
      3  1.1  christos 
      4  1.1  christos     This program is free software; you can redistribute it and/or modify
      5  1.1  christos     it under the terms of the GNU General Public License as published by
      6  1.1  christos     the Free Software Foundation; either version 3 of the License, or
      7  1.1  christos     (at your option) any later version.
      8  1.1  christos 
      9  1.1  christos     This program is distributed in the hope that it will be useful,
     10  1.1  christos     but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  1.1  christos     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  1.1  christos     GNU General Public License for more details.
     13  1.1  christos 
     14  1.1  christos     You should have received a copy of the GNU General Public License
     15  1.1  christos     along with this program; if not, see <http://www.gnu.org/licenses/>. */
     16  1.1  christos 
     17  1.1  christos #include "armdefs.h"
     18  1.1  christos #include "armemu.h"
     19  1.1  christos #include "ansidecl.h"
     20  1.1  christos 
     21  1.1  christos /* Definitions for the support routines.  */
     22  1.1  christos 
     23  1.1  christos static ARMword ModeToBank (ARMword);
     24  1.1  christos static void    EnvokeList (ARMul_State *, unsigned long, unsigned long);
     25  1.1  christos 
     26  1.1  christos struct EventNode
     27  1.1  christos {					/* An event list node.  */
     28  1.1  christos   unsigned (*func) (ARMul_State *);	/* The function to call.  */
     29  1.1  christos   struct EventNode *next;
     30  1.1  christos };
     31  1.1  christos 
     32  1.1  christos /* This routine returns the value of a register from a mode.  */
     33  1.1  christos 
     34  1.1  christos ARMword
     35  1.1  christos ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg)
     36  1.1  christos {
     37  1.1  christos   mode &= MODEBITS;
     38  1.1  christos   if (mode != state->Mode)
     39  1.1  christos     return (state->RegBank[ModeToBank ((ARMword) mode)][reg]);
     40  1.1  christos   else
     41  1.1  christos     return (state->Reg[reg]);
     42  1.1  christos }
     43  1.1  christos 
     44  1.1  christos /* This routine sets the value of a register for a mode.  */
     45  1.1  christos 
     46  1.1  christos void
     47  1.1  christos ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value)
     48  1.1  christos {
     49  1.1  christos   mode &= MODEBITS;
     50  1.1  christos   if (mode != state->Mode)
     51  1.1  christos     state->RegBank[ModeToBank ((ARMword) mode)][reg] = value;
     52  1.1  christos   else
     53  1.1  christos     state->Reg[reg] = value;
     54  1.1  christos }
     55  1.1  christos 
     56  1.1  christos /* This routine returns the value of the PC, mode independently.  */
     57  1.1  christos 
     58  1.1  christos ARMword
     59  1.1  christos ARMul_GetPC (ARMul_State * state)
     60  1.1  christos {
     61  1.1  christos   if (state->Mode > SVC26MODE)
     62  1.1  christos     return state->Reg[15];
     63  1.1  christos   else
     64  1.1  christos     return R15PC;
     65  1.1  christos }
     66  1.1  christos 
     67  1.1  christos /* This routine returns the value of the PC, mode independently.  */
     68  1.1  christos 
     69  1.1  christos ARMword
     70  1.1  christos ARMul_GetNextPC (ARMul_State * state)
     71  1.1  christos {
     72  1.1  christos   if (state->Mode > SVC26MODE)
     73  1.1  christos     return state->Reg[15] + isize;
     74  1.1  christos   else
     75  1.1  christos     return (state->Reg[15] + isize) & R15PCBITS;
     76  1.1  christos }
     77  1.1  christos 
     78  1.1  christos /* This routine sets the value of the PC.  */
     79  1.1  christos 
     80  1.1  christos void
     81  1.1  christos ARMul_SetPC (ARMul_State * state, ARMword value)
     82  1.1  christos {
     83  1.1  christos   if (ARMul_MODE32BIT)
     84  1.1  christos     state->Reg[15] = value & PCBITS;
     85  1.1  christos   else
     86  1.1  christos     state->Reg[15] = R15CCINTMODE | (value & R15PCBITS);
     87  1.1  christos   FLUSHPIPE;
     88  1.1  christos }
     89  1.1  christos 
     90  1.1  christos /* This routine returns the value of register 15, mode independently.  */
     91  1.1  christos 
     92  1.1  christos ARMword
     93  1.1  christos ARMul_GetR15 (ARMul_State * state)
     94  1.1  christos {
     95  1.1  christos   if (state->Mode > SVC26MODE)
     96  1.1  christos     return (state->Reg[15]);
     97  1.1  christos   else
     98  1.1  christos     return (R15PC | ECC | ER15INT | EMODE);
     99  1.1  christos }
    100  1.1  christos 
    101  1.1  christos /* This routine sets the value of Register 15.  */
    102  1.1  christos 
    103  1.1  christos void
    104  1.1  christos ARMul_SetR15 (ARMul_State * state, ARMword value)
    105  1.1  christos {
    106  1.1  christos   if (ARMul_MODE32BIT)
    107  1.1  christos     state->Reg[15] = value & PCBITS;
    108  1.1  christos   else
    109  1.1  christos     {
    110  1.1  christos       state->Reg[15] = value;
    111  1.1  christos       ARMul_R15Altered (state);
    112  1.1  christos     }
    113  1.1  christos   FLUSHPIPE;
    114  1.1  christos }
    115  1.1  christos 
    116  1.1  christos /* This routine returns the value of the CPSR.  */
    117  1.1  christos 
    118  1.1  christos ARMword
    119  1.1  christos ARMul_GetCPSR (ARMul_State * state)
    120  1.1  christos {
    121  1.1  christos   return (CPSR | state->Cpsr);
    122  1.1  christos }
    123  1.1  christos 
    124  1.1  christos /* This routine sets the value of the CPSR.  */
    125  1.1  christos 
    126  1.1  christos void
    127  1.1  christos ARMul_SetCPSR (ARMul_State * state, ARMword value)
    128  1.1  christos {
    129  1.1  christos   state->Cpsr = value;
    130  1.1  christos   ARMul_CPSRAltered (state);
    131  1.1  christos }
    132  1.1  christos 
    133  1.1  christos /* This routine does all the nasty bits involved in a write to the CPSR,
    134  1.1  christos    including updating the register bank, given a MSR instruction.  */
    135  1.1  christos 
    136  1.1  christos void
    137  1.1  christos ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs)
    138  1.1  christos {
    139  1.1  christos   state->Cpsr = ARMul_GetCPSR (state);
    140  1.1  christos 
    141  1.1  christos   if (state->Mode != USER26MODE
    142  1.1  christos       && state->Mode != USER32MODE)
    143  1.1  christos     {
    144  1.1  christos       /* In user mode, only write flags.  */
    145  1.1  christos       if (BIT (16))
    146  1.1  christos 	SETPSR_C (state->Cpsr, rhs);
    147  1.1  christos       if (BIT (17))
    148  1.1  christos 	SETPSR_X (state->Cpsr, rhs);
    149  1.1  christos       if (BIT (18))
    150  1.1  christos 	SETPSR_S (state->Cpsr, rhs);
    151  1.1  christos     }
    152  1.1  christos   if (BIT (19))
    153  1.1  christos     SETPSR_F (state->Cpsr, rhs);
    154  1.1  christos   ARMul_CPSRAltered (state);
    155  1.1  christos }
    156  1.1  christos 
    157  1.1  christos /* Get an SPSR from the specified mode.  */
    158  1.1  christos 
    159  1.1  christos ARMword
    160  1.1  christos ARMul_GetSPSR (ARMul_State * state, ARMword mode)
    161  1.1  christos {
    162  1.1  christos   ARMword bank = ModeToBank (mode & MODEBITS);
    163  1.1  christos 
    164  1.1  christos   if (! BANK_CAN_ACCESS_SPSR (bank))
    165  1.1  christos     return ARMul_GetCPSR (state);
    166  1.1  christos 
    167  1.1  christos   return state->Spsr[bank];
    168  1.1  christos }
    169  1.1  christos 
    170  1.1  christos /* This routine does a write to an SPSR.  */
    171  1.1  christos 
    172  1.1  christos void
    173  1.1  christos ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value)
    174  1.1  christos {
    175  1.1  christos   ARMword bank = ModeToBank (mode & MODEBITS);
    176  1.1  christos 
    177  1.1  christos   if (BANK_CAN_ACCESS_SPSR (bank))
    178  1.1  christos     state->Spsr[bank] = value;
    179  1.1  christos }
    180  1.1  christos 
    181  1.1  christos /* This routine does a write to the current SPSR, given an MSR instruction.  */
    182  1.1  christos 
    183  1.1  christos void
    184  1.1  christos ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs)
    185  1.1  christos {
    186  1.1  christos   if (BANK_CAN_ACCESS_SPSR (state->Bank))
    187  1.1  christos     {
    188  1.1  christos       if (BIT (16))
    189  1.1  christos 	SETPSR_C (state->Spsr[state->Bank], rhs);
    190  1.1  christos       if (BIT (17))
    191  1.1  christos 	SETPSR_X (state->Spsr[state->Bank], rhs);
    192  1.1  christos       if (BIT (18))
    193  1.1  christos 	SETPSR_S (state->Spsr[state->Bank], rhs);
    194  1.1  christos       if (BIT (19))
    195  1.1  christos 	SETPSR_F (state->Spsr[state->Bank], rhs);
    196  1.1  christos     }
    197  1.1  christos }
    198  1.1  christos 
    199  1.1  christos /* This routine updates the state of the emulator after the Cpsr has been
    200  1.1  christos    changed.  Both the processor flags and register bank are updated.  */
    201  1.1  christos 
    202  1.1  christos void
    203  1.1  christos ARMul_CPSRAltered (ARMul_State * state)
    204  1.1  christos {
    205  1.1  christos   ARMword oldmode;
    206  1.1  christos 
    207  1.1  christos   if (state->prog32Sig == LOW)
    208  1.1  christos     state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS);
    209  1.1  christos 
    210  1.1  christos   oldmode = state->Mode;
    211  1.1  christos 
    212  1.1  christos   if (state->Mode != (state->Cpsr & MODEBITS))
    213  1.1  christos     {
    214  1.1  christos       state->Mode =
    215  1.1  christos 	ARMul_SwitchMode (state, state->Mode, state->Cpsr & MODEBITS);
    216  1.1  christos 
    217  1.1  christos       state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
    218  1.1  christos     }
    219  1.1  christos   state->Cpsr &= ~MODEBITS;
    220  1.1  christos 
    221  1.1  christos   ASSIGNINT (state->Cpsr & INTBITS);
    222  1.1  christos   state->Cpsr &= ~INTBITS;
    223  1.1  christos   ASSIGNN ((state->Cpsr & NBIT) != 0);
    224  1.1  christos   state->Cpsr &= ~NBIT;
    225  1.1  christos   ASSIGNZ ((state->Cpsr & ZBIT) != 0);
    226  1.1  christos   state->Cpsr &= ~ZBIT;
    227  1.1  christos   ASSIGNC ((state->Cpsr & CBIT) != 0);
    228  1.1  christos   state->Cpsr &= ~CBIT;
    229  1.1  christos   ASSIGNV ((state->Cpsr & VBIT) != 0);
    230  1.1  christos   state->Cpsr &= ~VBIT;
    231  1.1  christos   ASSIGNS ((state->Cpsr & SBIT) != 0);
    232  1.1  christos   state->Cpsr &= ~SBIT;
    233  1.1  christos #ifdef MODET
    234  1.1  christos   ASSIGNT ((state->Cpsr & TBIT) != 0);
    235  1.1  christos   state->Cpsr &= ~TBIT;
    236  1.1  christos #endif
    237  1.1  christos 
    238  1.1  christos   if (oldmode > SVC26MODE)
    239  1.1  christos     {
    240  1.1  christos       if (state->Mode <= SVC26MODE)
    241  1.1  christos 	{
    242  1.1  christos 	  state->Emulate = CHANGEMODE;
    243  1.1  christos 	  state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
    244  1.1  christos 	}
    245  1.1  christos     }
    246  1.1  christos   else
    247  1.1  christos     {
    248  1.1  christos       if (state->Mode > SVC26MODE)
    249  1.1  christos 	{
    250  1.1  christos 	  state->Emulate = CHANGEMODE;
    251  1.1  christos 	  state->Reg[15] = R15PC;
    252  1.1  christos 	}
    253  1.1  christos       else
    254  1.1  christos 	state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
    255  1.1  christos     }
    256  1.1  christos }
    257  1.1  christos 
    258  1.1  christos /* This routine updates the state of the emulator after register 15 has
    259  1.1  christos    been changed.  Both the processor flags and register bank are updated.
    260  1.1  christos    This routine should only be called from a 26 bit mode.  */
    261  1.1  christos 
    262  1.1  christos void
    263  1.1  christos ARMul_R15Altered (ARMul_State * state)
    264  1.1  christos {
    265  1.1  christos   if (state->Mode != R15MODE)
    266  1.1  christos     {
    267  1.1  christos       state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE);
    268  1.1  christos       state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
    269  1.1  christos     }
    270  1.1  christos 
    271  1.1  christos   if (state->Mode > SVC26MODE)
    272  1.1  christos     state->Emulate = CHANGEMODE;
    273  1.1  christos 
    274  1.1  christos   ASSIGNR15INT (R15INT);
    275  1.1  christos 
    276  1.1  christos   ASSIGNN ((state->Reg[15] & NBIT) != 0);
    277  1.1  christos   ASSIGNZ ((state->Reg[15] & ZBIT) != 0);
    278  1.1  christos   ASSIGNC ((state->Reg[15] & CBIT) != 0);
    279  1.1  christos   ASSIGNV ((state->Reg[15] & VBIT) != 0);
    280  1.1  christos }
    281  1.1  christos 
    282  1.1  christos /* This routine controls the saving and restoring of registers across mode
    283  1.1  christos    changes.  The regbank matrix is largely unused, only rows 13 and 14 are
    284  1.1  christos    used across all modes, 8 to 14 are used for FIQ, all others use the USER
    285  1.1  christos    column.  It's easier this way.  old and new parameter are modes numbers.
    286  1.1  christos    Notice the side effect of changing the Bank variable.  */
    287  1.1  christos 
    288  1.1  christos ARMword
    289  1.1  christos ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode)
    290  1.1  christos {
    291  1.1  christos   unsigned i;
    292  1.1  christos   ARMword  oldbank;
    293  1.1  christos   ARMword  newbank;
    294  1.1  christos 
    295  1.1  christos   oldbank = ModeToBank (oldmode);
    296  1.1  christos   newbank = state->Bank = ModeToBank (newmode);
    297  1.1  christos 
    298  1.1  christos   /* Do we really need to do it?  */
    299  1.1  christos   if (oldbank != newbank)
    300  1.1  christos     {
    301  1.1  christos       /* Save away the old registers.  */
    302  1.1  christos       switch (oldbank)
    303  1.1  christos 	{
    304  1.1  christos 	case USERBANK:
    305  1.1  christos 	case IRQBANK:
    306  1.1  christos 	case SVCBANK:
    307  1.1  christos 	case ABORTBANK:
    308  1.1  christos 	case UNDEFBANK:
    309  1.1  christos 	  if (newbank == FIQBANK)
    310  1.1  christos 	    for (i = 8; i < 13; i++)
    311  1.1  christos 	      state->RegBank[USERBANK][i] = state->Reg[i];
    312  1.1  christos 	  state->RegBank[oldbank][13] = state->Reg[13];
    313  1.1  christos 	  state->RegBank[oldbank][14] = state->Reg[14];
    314  1.1  christos 	  break;
    315  1.1  christos 	case FIQBANK:
    316  1.1  christos 	  for (i = 8; i < 15; i++)
    317  1.1  christos 	    state->RegBank[FIQBANK][i] = state->Reg[i];
    318  1.1  christos 	  break;
    319  1.1  christos 	case DUMMYBANK:
    320  1.1  christos 	  for (i = 8; i < 15; i++)
    321  1.1  christos 	    state->RegBank[DUMMYBANK][i] = 0;
    322  1.1  christos 	  break;
    323  1.1  christos 	default:
    324  1.1  christos 	  abort ();
    325  1.1  christos 	}
    326  1.1  christos 
    327  1.1  christos       /* Restore the new registers.  */
    328  1.1  christos       switch (newbank)
    329  1.1  christos 	{
    330  1.1  christos 	case USERBANK:
    331  1.1  christos 	case IRQBANK:
    332  1.1  christos 	case SVCBANK:
    333  1.1  christos 	case ABORTBANK:
    334  1.1  christos 	case UNDEFBANK:
    335  1.1  christos 	  if (oldbank == FIQBANK)
    336  1.1  christos 	    for (i = 8; i < 13; i++)
    337  1.1  christos 	      state->Reg[i] = state->RegBank[USERBANK][i];
    338  1.1  christos 	  state->Reg[13] = state->RegBank[newbank][13];
    339  1.1  christos 	  state->Reg[14] = state->RegBank[newbank][14];
    340  1.1  christos 	  break;
    341  1.1  christos 	case FIQBANK:
    342  1.1  christos 	  for (i = 8; i < 15; i++)
    343  1.1  christos 	    state->Reg[i] = state->RegBank[FIQBANK][i];
    344  1.1  christos 	  break;
    345  1.1  christos 	case DUMMYBANK:
    346  1.1  christos 	  for (i = 8; i < 15; i++)
    347  1.1  christos 	    state->Reg[i] = 0;
    348  1.1  christos 	  break;
    349  1.1  christos 	default:
    350  1.1  christos 	  abort ();
    351  1.1  christos 	}
    352  1.1  christos     }
    353  1.1  christos 
    354  1.1  christos   return newmode;
    355  1.1  christos }
    356  1.1  christos 
    357  1.1  christos /* Given a processor mode, this routine returns the
    358  1.1  christos    register bank that will be accessed in that mode.  */
    359  1.1  christos 
    360  1.1  christos static ARMword
    361  1.1  christos ModeToBank (ARMword mode)
    362  1.1  christos {
    363  1.1  christos   static ARMword bankofmode[] =
    364  1.1  christos   {
    365  1.1  christos     USERBANK,  FIQBANK,   IRQBANK,   SVCBANK,
    366  1.1  christos     DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
    367  1.1  christos     DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
    368  1.1  christos     DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
    369  1.1  christos     USERBANK,  FIQBANK,   IRQBANK,   SVCBANK,
    370  1.1  christos     DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK,
    371  1.1  christos     DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK,
    372  1.1  christos     DUMMYBANK, DUMMYBANK, DUMMYBANK, SYSTEMBANK
    373  1.1  christos   };
    374  1.1  christos 
    375  1.1  christos   if (mode >= (sizeof (bankofmode) / sizeof (bankofmode[0])))
    376  1.1  christos     return DUMMYBANK;
    377  1.1  christos 
    378  1.1  christos   return bankofmode[mode];
    379  1.1  christos }
    380  1.1  christos 
    381  1.1  christos /* Returns the register number of the nth register in a reg list.  */
    382  1.1  christos 
    383  1.1  christos unsigned
    384  1.1  christos ARMul_NthReg (ARMword instr, unsigned number)
    385  1.1  christos {
    386  1.1  christos   unsigned bit, upto;
    387  1.1  christos 
    388  1.1  christos   for (bit = 0, upto = 0; upto <= number; bit ++)
    389  1.1  christos     if (BIT (bit))
    390  1.1  christos       upto ++;
    391  1.1  christos 
    392  1.1  christos   return (bit - 1);
    393  1.1  christos }
    394  1.1  christos 
    395  1.1  christos /* Assigns the N and Z flags depending on the value of result.  */
    396  1.1  christos 
    397  1.1  christos void
    398  1.1  christos ARMul_NegZero (ARMul_State * state, ARMword result)
    399  1.1  christos {
    400  1.1  christos   if (NEG (result))
    401  1.1  christos     {
    402  1.1  christos       SETN;
    403  1.1  christos       CLEARZ;
    404  1.1  christos     }
    405  1.1  christos   else if (result == 0)
    406  1.1  christos     {
    407  1.1  christos       CLEARN;
    408  1.1  christos       SETZ;
    409  1.1  christos     }
    410  1.1  christos   else
    411  1.1  christos     {
    412  1.1  christos       CLEARN;
    413  1.1  christos       CLEARZ;
    414  1.1  christos     }
    415  1.1  christos }
    416  1.1  christos 
    417  1.1  christos /* Compute whether an addition of A and B, giving RESULT, overflowed.  */
    418  1.1  christos 
    419  1.1  christos int
    420  1.1  christos AddOverflow (ARMword a, ARMword b, ARMword result)
    421  1.1  christos {
    422  1.1  christos   return ((NEG (a) && NEG (b) && POS (result))
    423  1.1  christos 	  || (POS (a) && POS (b) && NEG (result)));
    424  1.1  christos }
    425  1.1  christos 
    426  1.1  christos /* Compute whether a subtraction of A and B, giving RESULT, overflowed.  */
    427  1.1  christos 
    428  1.1  christos int
    429  1.1  christos SubOverflow (ARMword a, ARMword b, ARMword result)
    430  1.1  christos {
    431  1.1  christos   return ((NEG (a) && POS (b) && POS (result))
    432  1.1  christos 	  || (POS (a) && NEG (b) && NEG (result)));
    433  1.1  christos }
    434  1.1  christos 
    435  1.1  christos /* Assigns the C flag after an addition of a and b to give result.  */
    436  1.1  christos 
    437  1.1  christos void
    438  1.1  christos ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
    439  1.1  christos {
    440  1.1  christos   ASSIGNC ((NEG (a) && NEG (b)) ||
    441  1.1  christos 	   (NEG (a) && POS (result)) || (NEG (b) && POS (result)));
    442  1.1  christos }
    443  1.1  christos 
    444  1.1  christos /* Assigns the V flag after an addition of a and b to give result.  */
    445  1.1  christos 
    446  1.1  christos void
    447  1.1  christos ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
    448  1.1  christos {
    449  1.1  christos   ASSIGNV (AddOverflow (a, b, result));
    450  1.1  christos }
    451  1.1  christos 
    452  1.1  christos /* Assigns the C flag after an subtraction of a and b to give result.  */
    453  1.1  christos 
    454  1.1  christos void
    455  1.1  christos ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
    456  1.1  christos {
    457  1.1  christos   ASSIGNC ((NEG (a) && POS (b)) ||
    458  1.1  christos 	   (NEG (a) && POS (result)) || (POS (b) && POS (result)));
    459  1.1  christos }
    460  1.1  christos 
    461  1.1  christos /* Assigns the V flag after an subtraction of a and b to give result.  */
    462  1.1  christos 
    463  1.1  christos void
    464  1.1  christos ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
    465  1.1  christos {
    466  1.1  christos   ASSIGNV (SubOverflow (a, b, result));
    467  1.1  christos }
    468  1.1  christos 
    469  1.1  christos /* This function does the work of generating the addresses used in an
    470  1.1  christos    LDC instruction.  The code here is always post-indexed, it's up to the
    471  1.1  christos    caller to get the input address correct and to handle base register
    472  1.1  christos    modification. It also handles the Busy-Waiting.  */
    473  1.1  christos 
    474  1.1  christos void
    475  1.1  christos ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
    476  1.1  christos {
    477  1.1  christos   unsigned cpab;
    478  1.1  christos   ARMword data;
    479  1.1  christos 
    480  1.1  christos   UNDEF_LSCPCBaseWb;
    481  1.1  christos 
    482  1.1  christos   if (! CP_ACCESS_ALLOWED (state, CPNum))
    483  1.1  christos     {
    484  1.1  christos       ARMul_UndefInstr (state, instr);
    485  1.1  christos       return;
    486  1.1  christos     }
    487  1.1  christos 
    488  1.1  christos   if (ADDREXCEPT (address))
    489  1.1  christos     INTERNALABORT (address);
    490  1.1  christos 
    491  1.1  christos   cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0);
    492  1.1  christos   while (cpab == ARMul_BUSY)
    493  1.1  christos     {
    494  1.1  christos       ARMul_Icycles (state, 1, 0);
    495  1.1  christos 
    496  1.1  christos       if (IntPending (state))
    497  1.1  christos 	{
    498  1.1  christos 	  cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
    499  1.1  christos 	  return;
    500  1.1  christos 	}
    501  1.1  christos       else
    502  1.1  christos 	cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, 0);
    503  1.1  christos     }
    504  1.1  christos   if (cpab == ARMul_CANT)
    505  1.1  christos     {
    506  1.1  christos       CPTAKEABORT;
    507  1.1  christos       return;
    508  1.1  christos     }
    509  1.1  christos 
    510  1.1  christos   cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0);
    511  1.1  christos   data = ARMul_LoadWordN (state, address);
    512  1.1  christos   BUSUSEDINCPCN;
    513  1.1  christos 
    514  1.1  christos   if (BIT (21))
    515  1.1  christos     LSBase = state->Base;
    516  1.1  christos   cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
    517  1.1  christos 
    518  1.1  christos   while (cpab == ARMul_INC)
    519  1.1  christos     {
    520  1.1  christos       address += 4;
    521  1.1  christos       data = ARMul_LoadWordN (state, address);
    522  1.1  christos       cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
    523  1.1  christos     }
    524  1.1  christos 
    525  1.1  christos   if (state->abortSig || state->Aborted)
    526  1.1  christos     TAKEABORT;
    527  1.1  christos }
    528  1.1  christos 
    529  1.1  christos /* This function does the work of generating the addresses used in an
    530  1.1  christos    STC instruction.  The code here is always post-indexed, it's up to the
    531  1.1  christos    caller to get the input address correct and to handle base register
    532  1.1  christos    modification. It also handles the Busy-Waiting.  */
    533  1.1  christos 
    534  1.1  christos void
    535  1.1  christos ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
    536  1.1  christos {
    537  1.1  christos   unsigned cpab;
    538  1.1  christos   ARMword data;
    539  1.1  christos 
    540  1.1  christos   UNDEF_LSCPCBaseWb;
    541  1.1  christos 
    542  1.1  christos   if (! CP_ACCESS_ALLOWED (state, CPNum))
    543  1.1  christos     {
    544  1.1  christos       ARMul_UndefInstr (state, instr);
    545  1.1  christos       return;
    546  1.1  christos     }
    547  1.1  christos 
    548  1.1  christos   if (ADDREXCEPT (address) || VECTORACCESS (address))
    549  1.1  christos     INTERNALABORT (address);
    550  1.1  christos 
    551  1.1  christos   cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data);
    552  1.1  christos   while (cpab == ARMul_BUSY)
    553  1.1  christos     {
    554  1.1  christos       ARMul_Icycles (state, 1, 0);
    555  1.1  christos       if (IntPending (state))
    556  1.1  christos 	{
    557  1.1  christos 	  cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
    558  1.1  christos 	  return;
    559  1.1  christos 	}
    560  1.1  christos       else
    561  1.1  christos 	cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, &data);
    562  1.1  christos     }
    563  1.1  christos 
    564  1.1  christos   if (cpab == ARMul_CANT)
    565  1.1  christos     {
    566  1.1  christos       CPTAKEABORT;
    567  1.1  christos       return;
    568  1.1  christos     }
    569  1.1  christos #ifndef MODE32
    570  1.1  christos   if (ADDREXCEPT (address) || VECTORACCESS (address))
    571  1.1  christos     INTERNALABORT (address);
    572  1.1  christos #endif
    573  1.1  christos   BUSUSEDINCPCN;
    574  1.1  christos   if (BIT (21))
    575  1.1  christos     LSBase = state->Base;
    576  1.1  christos   cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
    577  1.1  christos   ARMul_StoreWordN (state, address, data);
    578  1.1  christos 
    579  1.1  christos   while (cpab == ARMul_INC)
    580  1.1  christos     {
    581  1.1  christos       address += 4;
    582  1.1  christos       cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
    583  1.1  christos       ARMul_StoreWordN (state, address, data);
    584  1.1  christos     }
    585  1.1  christos 
    586  1.1  christos   if (state->abortSig || state->Aborted)
    587  1.1  christos     TAKEABORT;
    588  1.1  christos }
    589  1.1  christos 
    590  1.1  christos /* This function does the Busy-Waiting for an MCR instruction.  */
    591  1.1  christos 
    592  1.1  christos void
    593  1.1  christos ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
    594  1.1  christos {
    595  1.1  christos   unsigned cpab;
    596  1.1  christos 
    597  1.1  christos   if (! CP_ACCESS_ALLOWED (state, CPNum))
    598  1.1  christos     {
    599  1.1  christos       ARMul_UndefInstr (state, instr);
    600  1.1  christos       return;
    601  1.1  christos     }
    602  1.1  christos 
    603  1.1  christos   cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source);
    604  1.1  christos 
    605  1.1  christos   while (cpab == ARMul_BUSY)
    606  1.1  christos     {
    607  1.1  christos       ARMul_Icycles (state, 1, 0);
    608  1.1  christos 
    609  1.1  christos       if (IntPending (state))
    610  1.1  christos 	{
    611  1.1  christos 	  cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
    612  1.1  christos 	  return;
    613  1.1  christos 	}
    614  1.1  christos       else
    615  1.1  christos 	cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, source);
    616  1.1  christos     }
    617  1.1  christos 
    618  1.1  christos   if (cpab == ARMul_CANT)
    619  1.1  christos     ARMul_Abort (state, ARMul_UndefinedInstrV);
    620  1.1  christos   else
    621  1.1  christos     {
    622  1.1  christos       BUSUSEDINCPCN;
    623  1.1  christos       ARMul_Ccycles (state, 1, 0);
    624  1.1  christos     }
    625  1.1  christos }
    626  1.1  christos 
    627  1.1  christos /* This function does the Busy-Waiting for an MRC instruction.  */
    628  1.1  christos 
    629  1.1  christos ARMword
    630  1.1  christos ARMul_MRC (ARMul_State * state, ARMword instr)
    631  1.1  christos {
    632  1.1  christos   unsigned cpab;
    633  1.1  christos   ARMword result = 0;
    634  1.1  christos 
    635  1.1  christos   if (! CP_ACCESS_ALLOWED (state, CPNum))
    636  1.1  christos     {
    637  1.1  christos       ARMul_UndefInstr (state, instr);
    638  1.1  christos       return result;
    639  1.1  christos     }
    640  1.1  christos 
    641  1.1  christos   cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
    642  1.1  christos   while (cpab == ARMul_BUSY)
    643  1.1  christos     {
    644  1.1  christos       ARMul_Icycles (state, 1, 0);
    645  1.1  christos       if (IntPending (state))
    646  1.1  christos 	{
    647  1.1  christos 	  cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
    648  1.1  christos 	  return (0);
    649  1.1  christos 	}
    650  1.1  christos       else
    651  1.1  christos 	cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, &result);
    652  1.1  christos     }
    653  1.1  christos   if (cpab == ARMul_CANT)
    654  1.1  christos     {
    655  1.1  christos       ARMul_Abort (state, ARMul_UndefinedInstrV);
    656  1.1  christos       /* Parent will destroy the flags otherwise.  */
    657  1.1  christos       result = ECC;
    658  1.1  christos     }
    659  1.1  christos   else
    660  1.1  christos     {
    661  1.1  christos       BUSUSEDINCPCN;
    662  1.1  christos       ARMul_Ccycles (state, 1, 0);
    663  1.1  christos       ARMul_Icycles (state, 1, 0);
    664  1.1  christos     }
    665  1.1  christos 
    666  1.1  christos   return result;
    667  1.1  christos }
    668  1.1  christos 
    669  1.1  christos /* This function does the Busy-Waiting for an CDP instruction.  */
    670  1.1  christos 
    671  1.1  christos void
    672  1.1  christos ARMul_CDP (ARMul_State * state, ARMword instr)
    673  1.1  christos {
    674  1.1  christos   unsigned cpab;
    675  1.1  christos 
    676  1.1  christos   if (! CP_ACCESS_ALLOWED (state, CPNum))
    677  1.1  christos     {
    678  1.1  christos       ARMul_UndefInstr (state, instr);
    679  1.1  christos       return;
    680  1.1  christos     }
    681  1.1  christos 
    682  1.1  christos   cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr);
    683  1.1  christos   while (cpab == ARMul_BUSY)
    684  1.1  christos     {
    685  1.1  christos       ARMul_Icycles (state, 1, 0);
    686  1.1  christos       if (IntPending (state))
    687  1.1  christos 	{
    688  1.1  christos 	  cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, instr);
    689  1.1  christos 	  return;
    690  1.1  christos 	}
    691  1.1  christos       else
    692  1.1  christos 	cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr);
    693  1.1  christos     }
    694  1.1  christos   if (cpab == ARMul_CANT)
    695  1.1  christos     ARMul_Abort (state, ARMul_UndefinedInstrV);
    696  1.1  christos   else
    697  1.1  christos     BUSUSEDN;
    698  1.1  christos }
    699  1.1  christos 
    700  1.1  christos /* This function handles Undefined instructions, as CP isntruction.  */
    701  1.1  christos 
    702  1.1  christos void
    703  1.1  christos ARMul_UndefInstr (ARMul_State * state, ARMword instr ATTRIBUTE_UNUSED)
    704  1.1  christos {
    705  1.1  christos   ARMul_Abort (state, ARMul_UndefinedInstrV);
    706  1.1  christos }
    707  1.1  christos 
    708  1.1  christos /* Return TRUE if an interrupt is pending, FALSE otherwise.  */
    709  1.1  christos 
    710  1.1  christos unsigned
    711  1.1  christos IntPending (ARMul_State * state)
    712  1.1  christos {
    713  1.1  christos   if (state->Exception)
    714  1.1  christos     {
    715  1.1  christos       /* Any exceptions.  */
    716  1.1  christos       if (state->NresetSig == LOW)
    717  1.1  christos 	{
    718  1.1  christos 	  ARMul_Abort (state, ARMul_ResetV);
    719  1.1  christos 	  return TRUE;
    720  1.1  christos 	}
    721  1.1  christos       else if (!state->NfiqSig && !FFLAG)
    722  1.1  christos 	{
    723  1.1  christos 	  ARMul_Abort (state, ARMul_FIQV);
    724  1.1  christos 	  return TRUE;
    725  1.1  christos 	}
    726  1.1  christos       else if (!state->NirqSig && !IFLAG)
    727  1.1  christos 	{
    728  1.1  christos 	  ARMul_Abort (state, ARMul_IRQV);
    729  1.1  christos 	  return TRUE;
    730  1.1  christos 	}
    731  1.1  christos     }
    732  1.1  christos 
    733  1.1  christos   return FALSE;
    734  1.1  christos }
    735  1.1  christos 
    736  1.1  christos /* Align a word access to a non word boundary.  */
    737  1.1  christos 
    738  1.1  christos ARMword
    739  1.1  christos ARMul_Align (state, address, data)
    740  1.1  christos      ARMul_State * state ATTRIBUTE_UNUSED;
    741  1.1  christos      ARMword address;
    742  1.1  christos      ARMword data;
    743  1.1  christos {
    744  1.1  christos   /* This code assumes the address is really unaligned,
    745  1.1  christos      as a shift by 32 is undefined in C.  */
    746  1.1  christos 
    747  1.1  christos   address = (address & 3) << 3;	/* Get the word address.  */
    748  1.1  christos   return ((data >> address) | (data << (32 - address)));	/* rot right */
    749  1.1  christos }
    750  1.1  christos 
    751  1.1  christos /* This routine is used to call another routine after a certain number of
    752  1.1  christos    cycles have been executed. The first parameter is the number of cycles
    753  1.1  christos    delay before the function is called, the second argument is a pointer
    754  1.1  christos    to the function. A delay of zero doesn't work, just call the function.  */
    755  1.1  christos 
    756  1.1  christos void
    757  1.1  christos ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
    758  1.1  christos 		     unsigned (*what) (ARMul_State *))
    759  1.1  christos {
    760  1.1  christos   unsigned long when;
    761  1.1  christos   struct EventNode *event;
    762  1.1  christos 
    763  1.1  christos   if (state->EventSet++ == 0)
    764  1.1  christos     state->Now = ARMul_Time (state);
    765  1.1  christos   when = (state->Now + delay) % EVENTLISTSIZE;
    766  1.1  christos   event = (struct EventNode *) malloc (sizeof (struct EventNode));
    767  1.1  christos   event->func = what;
    768  1.1  christos   event->next = *(state->EventPtr + when);
    769  1.1  christos   *(state->EventPtr + when) = event;
    770  1.1  christos }
    771  1.1  christos 
    772  1.1  christos /* This routine is called at the beginning of
    773  1.1  christos    every cycle, to envoke scheduled events.  */
    774  1.1  christos 
    775  1.1  christos void
    776  1.1  christos ARMul_EnvokeEvent (ARMul_State * state)
    777  1.1  christos {
    778  1.1  christos   static unsigned long then;
    779  1.1  christos 
    780  1.1  christos   then = state->Now;
    781  1.1  christos   state->Now = ARMul_Time (state) % EVENTLISTSIZE;
    782  1.1  christos   if (then < state->Now)
    783  1.1  christos     /* Schedule events.  */
    784  1.1  christos     EnvokeList (state, then, state->Now);
    785  1.1  christos   else if (then > state->Now)
    786  1.1  christos     {
    787  1.1  christos       /* Need to wrap around the list.  */
    788  1.1  christos       EnvokeList (state, then, EVENTLISTSIZE - 1L);
    789  1.1  christos       EnvokeList (state, 0L, state->Now);
    790  1.1  christos     }
    791  1.1  christos }
    792  1.1  christos 
    793  1.1  christos /* Envokes all the entries in a range.  */
    794  1.1  christos 
    795  1.1  christos static void
    796  1.1  christos EnvokeList (ARMul_State * state, unsigned long from, unsigned long to)
    797  1.1  christos {
    798  1.1  christos   for (; from <= to; from++)
    799  1.1  christos     {
    800  1.1  christos       struct EventNode *anevent;
    801  1.1  christos 
    802  1.1  christos       anevent = *(state->EventPtr + from);
    803  1.1  christos       while (anevent)
    804  1.1  christos 	{
    805  1.1  christos 	  (anevent->func) (state);
    806  1.1  christos 	  state->EventSet--;
    807  1.1  christos 	  anevent = anevent->next;
    808  1.1  christos 	}
    809  1.1  christos       *(state->EventPtr + from) = NULL;
    810  1.1  christos     }
    811  1.1  christos }
    812  1.1  christos 
    813  1.1  christos /* This routine is returns the number of clock ticks since the last reset.  */
    814  1.1  christos 
    815  1.1  christos unsigned long
    816  1.1  christos ARMul_Time (ARMul_State * state)
    817  1.1  christos {
    818  1.1  christos   return (state->NumScycles + state->NumNcycles +
    819  1.1  christos 	  state->NumIcycles + state->NumCcycles + state->NumFcycles);
    820  1.1  christos }
    821