This commit was generated by cvs2svn to track changes on a CVS vendor
[platform/upstream/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 /***************************************************************************\
395 * Assigns the C flag after an addition of a and b to give result            *
396 \***************************************************************************/
397
398 void ARMul_AddCarry(ARMul_State *state, ARMword a,ARMword b,ARMword result)
399 {
400  ASSIGNC( (NEG(a) && NEG(b)) ||
401           (NEG(a) && POS(result)) ||
402           (NEG(b) && POS(result)) ) ;
403  }
404
405 /***************************************************************************\
406 * Assigns the V flag after an addition of a and b to give result            *
407 \***************************************************************************/
408
409 void ARMul_AddOverflow(ARMul_State *state, ARMword a,ARMword b,ARMword result)
410 {
411  ASSIGNV( (NEG(a) && NEG(b) && POS(result)) ||
412           (POS(a) && POS(b) && NEG(result)) ) ;
413  }
414
415 /***************************************************************************\
416 * Assigns the C flag after an subtraction of a and b to give result         *
417 \***************************************************************************/
418
419 void ARMul_SubCarry(ARMul_State *state, ARMword a,ARMword b,ARMword result)
420 {
421 ASSIGNC( (NEG(a) && POS(b)) ||
422          (NEG(a) && POS(result)) ||
423          (POS(b) && POS(result)) ) ;
424 }
425
426 /***************************************************************************\
427 * Assigns the V flag after an subtraction of a and b to give result         *
428 \***************************************************************************/
429
430 void ARMul_SubOverflow(ARMul_State *state,ARMword a,ARMword b,ARMword result)
431 {
432 ASSIGNV( (NEG(a) && POS(b) && POS(result)) ||
433          (POS(a) && NEG(b) && NEG(result)) ) ;
434 }
435
436 /***************************************************************************\
437 * This function does the work of generating the addresses used in an        *
438 * LDC instruction.  The code here is always post-indexed, it's up to the    *
439 * caller to get the input address correct and to handle base register       *
440 * modification. It also handles the Busy-Waiting.                           *
441 \***************************************************************************/
442
443 void ARMul_LDC(ARMul_State *state,ARMword instr,ARMword address)
444 {unsigned cpab ;
445  ARMword data ;
446
447  UNDEF_LSCPCBaseWb ;
448  if (ADDREXCEPT(address)) {
449     INTERNALABORT(address) ;
450     }
451  cpab = (state->LDC[CPNum])(state,ARMul_FIRST,instr,0) ;
452  while (cpab == ARMul_BUSY) {
453     ARMul_Icycles(state,1,0) ;
454     if (IntPending(state)) {
455        cpab = (state->LDC[CPNum])(state,ARMul_INTERRUPT,instr,0) ;
456        return ;
457        }
458     else
459        cpab = (state->LDC[CPNum])(state,ARMul_BUSY,instr,0) ;
460     }
461  if (cpab == ARMul_CANT) {
462     CPTAKEABORT ;
463     return ;
464     }
465  cpab = (state->LDC[CPNum])(state,ARMul_TRANSFER,instr,0) ;
466  data = ARMul_LoadWordN(state,address) ;
467  BUSUSEDINCPCN ;
468  if (BIT(21))
469     LSBase = state->Base ;
470  cpab = (state->LDC[CPNum])(state,ARMul_DATA,instr,data) ;
471  while (cpab == ARMul_INC) {
472     address += 4 ;
473     data = ARMul_LoadWordN(state,address) ;
474     cpab = (state->LDC[CPNum])(state,ARMul_DATA,instr,data) ;
475     }
476  if (state->abortSig || state->Aborted) {
477     TAKEABORT ;
478     }
479  }
480
481 /***************************************************************************\
482 * This function does the work of generating the addresses used in an        *
483 * STC instruction.  The code here is always post-indexed, it's up to the    *
484 * caller to get the input address correct and to handle base register       *
485 * modification. It also handles the Busy-Waiting.                           *
486 \***************************************************************************/
487
488 void ARMul_STC(ARMul_State *state,ARMword instr,ARMword address)
489 {unsigned cpab ;
490  ARMword data ;
491
492  UNDEF_LSCPCBaseWb ;
493  if (ADDREXCEPT(address) || VECTORACCESS(address)) {
494     INTERNALABORT(address) ;
495     }
496  cpab = (state->STC[CPNum])(state,ARMul_FIRST,instr,&data) ;
497  while (cpab == ARMul_BUSY) {
498     ARMul_Icycles(state,1,0) ;
499     if (IntPending(state)) {
500        cpab = (state->STC[CPNum])(state,ARMul_INTERRUPT,instr,0) ;
501        return ;
502        }
503     else
504        cpab = (state->STC[CPNum])(state,ARMul_BUSY,instr,&data) ;
505     }
506  if (cpab == ARMul_CANT) {
507     CPTAKEABORT ;
508     return ;
509     }
510 #ifndef MODE32
511  if (ADDREXCEPT(address) || VECTORACCESS(address)) {
512     INTERNALABORT(address) ;
513     }
514 #endif
515  BUSUSEDINCPCN ;
516  if (BIT(21))
517     LSBase = state->Base ;
518  cpab = (state->STC[CPNum])(state,ARMul_DATA,instr,&data) ;
519  ARMul_StoreWordN(state,address,data) ;
520  while (cpab == ARMul_INC) {
521     address += 4 ;
522     cpab = (state->STC[CPNum])(state,ARMul_DATA,instr,&data) ;
523     ARMul_StoreWordN(state,address,data) ;
524     }
525  if (state->abortSig || state->Aborted) {
526     TAKEABORT ;
527     }
528  }
529
530 /***************************************************************************\
531 *        This function does the Busy-Waiting for an MCR instruction.        *
532 \***************************************************************************/
533
534 void ARMul_MCR(ARMul_State *state,ARMword instr, ARMword source)
535 {unsigned cpab ;
536
537  cpab = (state->MCR[CPNum])(state,ARMul_FIRST,instr,source) ;
538  while (cpab == ARMul_BUSY) {
539     ARMul_Icycles(state,1,0) ;
540     if (IntPending(state)) {
541        cpab = (state->MCR[CPNum])(state,ARMul_INTERRUPT,instr,0) ;
542        return ;
543        }
544     else
545        cpab = (state->MCR[CPNum])(state,ARMul_BUSY,instr,source) ;
546     }
547  if (cpab == ARMul_CANT)
548     ARMul_Abort(state,ARMul_UndefinedInstrV) ;
549  else {
550     BUSUSEDINCPCN ;
551     ARMul_Ccycles(state,1,0) ;
552     }
553  }
554
555 /***************************************************************************\
556 *        This function does the Busy-Waiting for an MRC instruction.        *
557 \***************************************************************************/
558
559 ARMword ARMul_MRC(ARMul_State *state,ARMword instr)
560 {unsigned cpab ;
561  ARMword result = 0 ;
562
563  cpab = (state->MRC[CPNum])(state,ARMul_FIRST,instr,&result) ;
564  while (cpab == ARMul_BUSY) {
565     ARMul_Icycles(state,1,0) ;
566     if (IntPending(state)) {
567        cpab = (state->MRC[CPNum])(state,ARMul_INTERRUPT,instr,0) ;
568        return(0) ;
569        }
570     else
571        cpab = (state->MRC[CPNum])(state,ARMul_BUSY,instr,&result) ;
572     }
573  if (cpab == ARMul_CANT) {
574     ARMul_Abort(state,ARMul_UndefinedInstrV) ;
575     result = ECC ; /* Parent will destroy the flags otherwise */
576     }
577  else {
578     BUSUSEDINCPCN ;
579     ARMul_Ccycles(state,1,0) ;
580     ARMul_Icycles(state,1,0) ;
581     }
582  return(result) ;
583 }
584
585 /***************************************************************************\
586 *        This function does the Busy-Waiting for an CDP instruction.        *
587 \***************************************************************************/
588
589 void ARMul_CDP(ARMul_State *state,ARMword instr)
590 {unsigned cpab ;
591
592  cpab = (state->CDP[CPNum])(state,ARMul_FIRST,instr) ;
593  while (cpab == ARMul_BUSY) {
594     ARMul_Icycles(state,1,0) ;
595     if (IntPending(state)) {
596        cpab = (state->CDP[CPNum])(state,ARMul_INTERRUPT,instr) ;
597        return ;
598        }
599     else
600        cpab = (state->CDP[CPNum])(state,ARMul_BUSY,instr) ;
601     }
602  if (cpab == ARMul_CANT)
603     ARMul_Abort(state,ARMul_UndefinedInstrV) ;
604  else
605     BUSUSEDN ;
606 }
607
608 /***************************************************************************\
609 *      This function handles Undefined instructions, as CP isntruction      *
610 \***************************************************************************/
611
612 void ARMul_UndefInstr(ARMul_State *state,ARMword instr)
613 {
614  ARMul_Abort(state,ARMul_UndefinedInstrV) ;
615 }
616
617 /***************************************************************************\
618 *           Return TRUE if an interrupt is pending, FALSE otherwise.        *
619 \***************************************************************************/
620
621 unsigned IntPending(ARMul_State *state)
622 {
623  if (state->Exception) { /* Any exceptions */
624     if (state->NresetSig == LOW) {
625        ARMul_Abort(state,ARMul_ResetV) ;
626        return(TRUE) ;
627        }
628     else if (!state->NfiqSig && !FFLAG) {
629        ARMul_Abort(state,ARMul_FIQV) ;
630        return(TRUE) ;
631        }
632     else if (!state->NirqSig && !IFLAG) {
633        ARMul_Abort(state,ARMul_IRQV) ;
634        return(TRUE) ;
635        }
636     }
637  return(FALSE) ;
638  }
639
640 /***************************************************************************\
641 *               Align a word access to a non word boundary                  *
642 \***************************************************************************/
643
644 ARMword ARMul_Align(ARMul_State *state, ARMword address, ARMword data)
645 {/* this code assumes the address is really unaligned,
646     as a shift by 32 is undefined in C */
647
648  address = (address & 3) << 3 ; /* get the word address */
649  return( ( data >> address) | (data << (32 - address)) ) ; /* rot right */
650 }
651
652 /***************************************************************************\
653 * This routine is used to call another routine after a certain number of    *
654 * cycles have been executed. The first parameter is the number of cycles    *
655 * delay before the function is called, the second argument is a pointer     *
656 * to the function. A delay of zero doesn't work, just call the function.    *
657 \***************************************************************************/
658
659 void ARMul_ScheduleEvent(ARMul_State *state, unsigned long delay, unsigned (*what)())
660 {unsigned long when ;
661  struct EventNode *event ;
662
663  if (state->EventSet++ == 0)
664     state->Now = ARMul_Time(state) ;
665  when = (state->Now + delay) % EVENTLISTSIZE ;
666  event = (struct EventNode *)malloc(sizeof(struct EventNode)) ;
667  event->func = what ;
668  event->next = *(state->EventPtr + when) ;
669  *(state->EventPtr + when) = event ;
670 }
671
672 /***************************************************************************\
673 * This routine is called at the beginning of every cycle, to envoke         *
674 * scheduled events.                                                         *
675 \***************************************************************************/
676
677 void ARMul_EnvokeEvent(ARMul_State *state)
678 {static unsigned long then ;
679
680  then = state->Now ;
681  state->Now = ARMul_Time(state) % EVENTLISTSIZE ;
682  if (then < state->Now) /* schedule events */
683     EnvokeList(state,then,state->Now) ;
684  else if (then > state->Now) { /* need to wrap around the list */
685     EnvokeList(state,then,EVENTLISTSIZE-1L) ;
686     EnvokeList(state,0L,state->Now) ;
687     }
688  }
689
690 static void EnvokeList(ARMul_State *state, unsigned long from, unsigned long to)
691 /* envokes all the entries in a range */
692 {struct EventNode *anevent ;
693
694  for (; from <= to ; from++) {
695     anevent = *(state->EventPtr + from) ;
696     while (anevent) {
697        (anevent->func)(state) ;
698        state->EventSet-- ;
699        anevent = anevent->next ;
700        }
701     *(state->EventPtr + from) = NULL ;
702     }
703  }
704
705 /***************************************************************************\
706 * This routine is returns the number of clock ticks since the last reset.   *
707 \***************************************************************************/
708
709 unsigned long ARMul_Time(ARMul_State *state)
710 {return(state->NumScycles + state->NumNcycles +
711         state->NumIcycles + state->NumCcycles + state->NumFcycles) ;
712 }