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