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