Initial creation of sourceware repository
[deliverable/binutils-gdb.git] / sim / arm / armsupp.c
CommitLineData
c906108c
SS
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
25ARMword ARMul_GetReg(ARMul_State *state, unsigned mode, unsigned reg) ;
26void ARMul_SetReg(ARMul_State *state, unsigned mode, unsigned reg, ARMword value) ;
27ARMword ARMul_GetPC(ARMul_State *state) ;
28ARMword ARMul_GetNextPC(ARMul_State *state) ;
29void ARMul_SetPC(ARMul_State *state, ARMword value) ;
30ARMword ARMul_GetR15(ARMul_State *state) ;
31void ARMul_SetR15(ARMul_State *state, ARMword value) ;
32
33ARMword ARMul_GetCPSR(ARMul_State *state) ;
34void ARMul_SetCPSR(ARMul_State *state, ARMword value) ;
35void ARMul_FixCPSR(ARMul_State *state, ARMword instr, ARMword rhs) ;
36ARMword ARMul_GetSPSR(ARMul_State *state, ARMword mode) ;
37void ARMul_SetSPSR(ARMul_State *state, ARMword mode, ARMword value) ;
38void ARMul_FixSPSR(ARMul_State *state, ARMword instr, ARMword rhs) ;
39
40void ARMul_CPSRAltered(ARMul_State *state) ;
41void ARMul_R15Altered(ARMul_State *state) ;
42
43ARMword ARMul_SwitchMode(ARMul_State *state,ARMword oldmode, ARMword newmode) ;
44static ARMword ModeToBank(ARMul_State *state,ARMword mode) ;
45
46unsigned ARMul_NthReg(ARMword instr, unsigned number) ;
47
48void ARMul_NegZero(ARMul_State *state, ARMword result) ;
49void ARMul_AddCarry(ARMul_State *state, ARMword a, ARMword b, ARMword result) ;
50void ARMul_AddOverflow(ARMul_State *state, ARMword a, ARMword b, ARMword result) ;
51void ARMul_SubCarry(ARMul_State *state, ARMword a, ARMword b, ARMword result) ;
52void ARMul_SubOverflow(ARMul_State *state, ARMword a, ARMword b, ARMword result) ;
53
54void ARMul_LDC(ARMul_State *state,ARMword instr,ARMword address) ;
55void ARMul_STC(ARMul_State *state,ARMword instr,ARMword address) ;
56void ARMul_MCR(ARMul_State *state,ARMword instr, ARMword source) ;
57ARMword ARMul_MRC(ARMul_State *state,ARMword instr) ;
58void ARMul_CDP(ARMul_State *state,ARMword instr) ;
59void ARMul_UndefInstr(ARMul_State *state,ARMword instr) ;
60unsigned IntPending(ARMul_State *state) ;
61
62ARMword ARMul_Align(ARMul_State *state, ARMword address, ARMword data) ;
63
64void ARMul_ScheduleEvent(ARMul_State *state, unsigned long delay,
65 unsigned (*what)()) ;
66void ARMul_EnvokeEvent(ARMul_State *state) ;
67unsigned long ARMul_Time(ARMul_State *state) ;
68static void EnvokeList(ARMul_State *state, unsigned long from, unsigned long to) ;
69
70struct 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
79ARMword 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
91void 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
103ARMword 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
114ARMword 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
125void 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
137ARMword 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
148void 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
163ARMword ARMul_GetCPSR(ARMul_State *state)
164{
165 return(CPSR) ;
166 }
167
168/***************************************************************************\
169* This routine sets the value of the CPSR *
170\***************************************************************************/
171
172void 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
183void 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
202ARMword 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
214void 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
224void 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
237void 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
280void 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
303ARMword 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
355static 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
375unsigned 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
387void 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
398void 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
409void 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
419void ARMul_SubCarry(ARMul_State *state, ARMword a,ARMword b,ARMword result)
420{
421ASSIGNC( (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
430void ARMul_SubOverflow(ARMul_State *state,ARMword a,ARMword b,ARMword result)
431{
432ASSIGNV( (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
443void 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
488void 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
534void 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
559ARMword 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
589void 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
612void 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
621unsigned 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
644ARMword 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
659void 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
677void 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
690static 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
709unsigned long ARMul_Time(ARMul_State *state)
710{return(state->NumScycles + state->NumNcycles +
711 state->NumIcycles + state->NumCcycles + state->NumFcycles) ;
712}
This page took 0.049545 seconds and 4 git commands to generate.