1 /* armos.c -- ARMulator OS interface: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd.
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.
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.
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. */
18 /* This file contains a model of Demon, ARM Ltd's Debug Monitor,
19 including all the SWI's required to support the C library. The code in
20 it is not really for the faint-hearted (especially the abort handling
21 code), but it is a complete example. Defining NOOS will disable all the
22 fun, and definign VAILDATE will define SWI 1 to enter SVC mode, and SWI
23 0x11 to halt the emulator. */
46 #define unlink(s) remove(s)
50 #include <unistd.h> /* For SEEK_SET etc */
54 extern int _fisatty(FILE *);
55 #define isatty_(f) _fisatty(f)
59 #define isatty_(f) isatty((f)->_file)
63 #define isatty_(f) (~ioctl((f)->_file,FIOINTERACTIVE,NULL))
65 #define isatty_(f) isatty(fileno(f))
80 /* For RDIError_BreakpointReached. */
83 extern unsigned ARMul_OSInit(ARMul_State
*state
) ;
84 extern void ARMul_OSExit(ARMul_State
*state
) ;
85 extern unsigned ARMul_OSHandleSWI(ARMul_State
*state
,ARMword number
) ;
86 extern unsigned ARMul_OSException(ARMul_State
*state
, ARMword vector
, ARMword pc
) ;
87 extern ARMword
ARMul_OSLastErrorP(ARMul_State
*state
) ;
88 extern ARMword
ARMul_Debug(ARMul_State
*state
, ARMword pc
, ARMword instr
) ;
90 #define BUFFERSIZE 4096
94 #define UNIQUETEMPS 256
97 static void UnwindDataAbort(ARMul_State
*state
, ARMword addr
);
98 static void getstring(ARMul_State
*state
, ARMword from
, char *to
) ;
101 /***************************************************************************\
102 * OS private Information *
103 \***************************************************************************/
109 FILE *FileTable
[FOPEN_MAX
] ;
110 char FileFlags
[FOPEN_MAX
] ;
111 char *tempnames
[UNIQUETEMPS
] ;
120 #define FIXCRLF(t,c) ((t & BINARY)?c:((c=='\n'||c=='\r')?(c ^ 7):c))
122 #define FIXCRLF(t,c) c
125 static ARMword softvectorcode
[] =
126 { /* basic: swi tidyexception + event; mov pc, lr;
127 ldmia r11,{r11,pc}; swi generateexception + event
129 0xef000090, 0xe1a0e00f, 0xe89b8800, 0xef000080, /*Reset*/
130 0xef000091, 0xe1a0e00f, 0xe89b8800, 0xef000081, /*Undef*/
131 0xef000092, 0xe1a0e00f, 0xe89b8800, 0xef000082, /*SWI */
132 0xef000093, 0xe1a0e00f, 0xe89b8800, 0xef000083, /*Prefetch abort*/
133 0xef000094, 0xe1a0e00f, 0xe89b8800, 0xef000084, /*Data abort*/
134 0xef000095, 0xe1a0e00f, 0xe89b8800, 0xef000085, /*Address exception*/
135 0xef000096, 0xe1a0e00f, 0xe89b8800, 0xef000086, /*IRQ*/
136 0xef000097, 0xe1a0e00f, 0xe89b8800, 0xef000087, /*FIQ*/
137 0xef000098, 0xe1a0e00f, 0xe89b8800, 0xef000088, /*Error*/
138 0xe1a0f00e /* default handler */
141 /***************************************************************************\
142 * Time for the Operating System to initialise itself. *
143 \***************************************************************************/
145 unsigned ARMul_OSInit(ARMul_State
*state
)
149 ARMword instr
, i
, j
;
150 struct OSblock
* OSptr
= (struct OSblock
*)state
->OSptr
;
152 if (state
->OSptr
== NULL
) {
153 state
->OSptr
= (unsigned char *)malloc(sizeof(struct OSblock
));
154 if (state
->OSptr
== NULL
) {
159 OSptr
= (struct OSblock
*)state
->OSptr
;
161 state
->Reg
[13] = ADDRSUPERSTACK
; /* set up a stack for the current mode */
162 ARMul_SetReg(state
,SVC32MODE
,13,ADDRSUPERSTACK
); /* and for supervisor mode */
163 ARMul_SetReg(state
,ABORT32MODE
,13,ADDRSUPERSTACK
); /* and for abort 32 mode */
164 ARMul_SetReg(state
,UNDEF32MODE
,13,ADDRSUPERSTACK
); /* and for undef 32 mode */
165 instr
= 0xe59ff000 | (ADDRSOFTVECTORS
- 8); /* load pc from soft vector */
166 for (i
= ARMul_ResetV
; i
<= ARMFIQV
; i
+= 4)
167 ARMul_WriteWord(state
, i
, instr
); /* write hardware vectors */
168 for (i
= ARMul_ResetV
; i
<= ARMFIQV
+ 4 ; i
+= 4) {
169 ARMul_WriteWord(state
, ADDRSOFTVECTORS
+ i
, SOFTVECTORCODE
+ i
* 4);
170 ARMul_WriteWord(state
, ADDRSOFHANDLERS
+ 2*i
+ 4L, SOFTVECTORCODE
+ sizeof(softvectorcode
) - 4L);
172 for (i
= 0 ; i
< sizeof(softvectorcode
) ; i
+= 4)
173 ARMul_WriteWord(state
, SOFTVECTORCODE
+ i
, softvectorcode
[i
/4]);
174 for (i
= 0 ; i
< FOPEN_MAX
; i
++)
175 OSptr
->FileTable
[i
] = NULL
;
176 for (i
= 0 ; i
< UNIQUETEMPS
; i
++)
177 OSptr
->tempnames
[i
] = NULL
;
178 ARMul_ConsolePrint (state
, ", Demon 1.01");
183 for (i
= 0 ; i
< fpesize
; i
+=4) /* copy the code */
184 ARMul_WriteWord(state
,FPESTART
+ i
,fpecode
[i
>> 2]) ;
185 for (i
= FPESTART
+ fpesize
; ; i
-=4) { /* reverse the error strings */
186 if ((j
= ARMul_ReadWord(state
,i
)) == 0xffffffff)
188 if (state
->bigendSig
&& j
< 0x80000000) { /* it's part of the string so swap it */
189 j
= ((j
>> 0x18) & 0x000000ff) |
190 ((j
>> 0x08) & 0x0000ff00) |
191 ((j
<< 0x08) & 0x00ff0000) |
192 ((j
<< 0x18) & 0xff000000) ;
193 ARMul_WriteWord(state
,i
,j
) ;
196 ARMul_WriteWord(state
,FPEOLDVECT
,ARMul_ReadWord(state
,4)) ; /* copy old illegal instr vector */
197 ARMul_WriteWord(state
,4,FPENEWVECT(ARMul_ReadWord(state
,i
-4))) ; /* install new vector */
198 ARMul_ConsolePrint (state
, ", FPE") ;
201 #endif /* VALIDATE */
207 void ARMul_OSExit(ARMul_State
*state
)
209 free((char *)state
->OSptr
) ;
213 /***************************************************************************\
214 * Return the last Operating System Error. *
215 \***************************************************************************/
217 ARMword
ARMul_OSLastErrorP(ARMul_State
*state
)
219 return ((struct OSblock
*)state
->OSptr
)->ErrorP
;
222 /***************************************************************************\
223 * The emulator calls this routine when a SWI instruction is encuntered. The *
224 * parameter passed is the SWI number (lower 24 bits of the instruction). *
225 \***************************************************************************/
228 /* This is the cygnus way of doing it, which makes it simple
232 static int translate_open_mode
[] =
235 O_RDONLY
+O_BINARY
, /* "rb" */
237 O_RDWR
+O_BINARY
, /* "r+b" */
238 O_WRONLY
+O_CREAT
+O_TRUNC
, /* "w" */
239 O_WRONLY
+O_BINARY
+O_CREAT
+O_TRUNC
, /* "wb" */
240 O_RDWR
+O_CREAT
+O_TRUNC
, /* "w+" */
241 O_RDWR
+O_BINARY
+O_CREAT
+O_TRUNC
, /* "w+b" */
242 O_WRONLY
+O_APPEND
+O_CREAT
,/* "a" */
243 O_WRONLY
+O_BINARY
+O_APPEND
+O_CREAT
,/* "ab" */
244 O_RDWR
+O_APPEND
+O_CREAT
,/* "a+" */
245 O_RDWR
+O_BINARY
+O_APPEND
+O_CREAT
/* "a+b" */
248 unsigned ARMul_OSHandleSWI(ARMul_State
*state
,ARMword number
)
250 ARMword addr
, temp
, fildes
;
251 char buffer
[BUFFERSIZE
], *cptr
;
253 struct OSblock
* OSptr
= (struct OSblock
*)state
->OSptr
;
259 int f
= state
->Reg
[0];
260 int ptr
= state
->Reg
[1];
261 int len
= state
->Reg
[2];
264 char *local
= malloc (len
);
265 res
= read (f
,local
, len
);
267 for (i
= 0; i
< res
; i
++)
268 ARMul_WriteByte(state
, ptr
+ i
, local
[i
]) ;
270 state
->Reg
[0] = res
== -1 ? -1 : len
- res
;
271 OSptr
->ErrorNo
= errno
;
277 int f
= state
->Reg
[0];
278 int ptr
= state
->Reg
[1];
279 int len
= state
->Reg
[2];
282 char *local
= malloc (len
);
284 for (i
= 0; i
< len
; i
++)
286 local
[i
] = ARMul_ReadByte(state
, ptr
+ i
);
288 res
= write (f
, local
, len
);
289 state
->Reg
[0] = res
== -1 ? -1 : len
- res
;
291 OSptr
->ErrorNo
= errno
;
300 dummy
[i
] = ARMul_ReadByte(state
, state
->Reg
[0] + i
);
304 /* Now we need to decode the Demon open mode */
305 flags
= translate_open_mode
[state
->Reg
[1]];
307 /* Filename ":tt" is special: it denotes stdin/out */
308 if (strcmp (dummy
, ":tt") == 0)
310 if (flags
== O_RDONLY
) /* opening tty "r" */
311 state
->Reg
[0] = 0 /* stdin */ ;
313 state
->Reg
[0] = 1 /* stdout */ ;
317 state
->Reg
[0] = (int) open (dummy
, flags
);
318 OSptr
->ErrorNo
= errno
;
325 /* return number of centi-seconds... */
327 #ifdef CLOCKS_PER_SEC
328 (CLOCKS_PER_SEC
>= 100)
329 ? (ARMword
) (clock() / (CLOCKS_PER_SEC
/ 100))
330 : (ARMword
) ((clock() * 100) / CLOCKS_PER_SEC
) ;
332 /* presume unix... clock() returns microseconds */
333 (ARMword
) (clock() / 10000) ;
335 OSptr
->ErrorNo
= errno
;
339 state
->Reg
[0] = (ARMword
)time(NULL
) ;
340 OSptr
->ErrorNo
= errno
;
344 state
->Reg
[0] = close (state
->Reg
[0]);
345 OSptr
->ErrorNo
= errno
;
349 if (state
->Reg
[0] == 0 || state
->Reg
[0] > FOPEN_MAX
)
351 OSptr
->ErrorNo
= EBADF
;
352 state
->Reg
[0] = -1L ;
355 fildes
= state
->Reg
[0];
356 addr
= lseek(fildes
, 0, SEEK_CUR
);
358 state
->Reg
[0] = -1L ;
361 state
->Reg
[0] = lseek(fildes
, 0L, SEEK_END
);
362 (void)lseek(fildes
, addr
, SEEK_SET
);
364 OSptr
->ErrorNo
= errno
;
369 state
->Emulate
= FALSE
;
374 /* We must return non-zero for failure */
375 state
->Reg
[0] = -1 >= lseek (state
->Reg
[0],
378 OSptr
->ErrorNo
= errno
;
383 (void)fputc((int)state
->Reg
[0],stderr
) ;
384 OSptr
->ErrorNo
= errno
;
388 addr
= state
->Reg
[0] ;
389 while ((temp
= ARMul_ReadByte(state
,addr
++)) != 0)
390 (void)fputc((char)temp
,stderr
) ;
391 OSptr
->ErrorNo
= errno
;
395 state
->Reg
[0] = OSptr
->ErrorNo
;
398 case SWI_Breakpoint
:
399 state
->EndCondition
= RDIError_BreakpointReached
;
400 state
->Emulate
= FALSE
;
404 state
->Reg
[0] = ADDRCMDLINE
;
406 state
->Reg
[1] = state
->MemSize
;
408 state
->Reg
[1] = ADDRUSERSTACK
;
410 addr
= state
->Reg
[0] ;
411 cptr
= state
->CommandLine
;
415 temp
= (ARMword
)*cptr
++ ;
416 ARMul_WriteByte(state
,addr
++,temp
) ;
417 } while (temp
!= 0) ;
421 state
->Emulate
= FALSE
;
426 unsigned ARMul_OSHandleSWI(ARMul_State
*state
,ARMword number
)
434 state
->Emulate
= FALSE
;
438 ARMul_SetCPSR(state
, (ARMul_GetCPSR(state
) & 0xffffffc0) | 0x13) ;
440 ARMul_SetCPSR(state
, (ARMul_GetCPSR(state
) & 0xffffffc0) | 0x3) ;
447 char buffer
[BUFFERSIZE
], *cptr
;
449 struct OSblock
* OSptr
= (struct OSblock
*)state
->OSptr
;
453 (void)fputc((int)state
->Reg
[0],stderr
) ;
454 OSptr
->ErrorNo
= errno
;
458 addr
= state
->Reg
[0] ;
459 while ((temp
= ARMul_ReadByte(state
,addr
++)) != 0)
460 fputc((char)temp
,stderr
) ;
461 OSptr
->ErrorNo
= errno
;
465 state
->Reg
[0] = (ARMword
)fgetc(stdin
) ;
466 OSptr
->ErrorNo
= errno
;
470 addr
= state
->Reg
[0] ;
471 getstring(state
,state
->Reg
[0],buffer
) ;
472 state
->Reg
[0] = (ARMword
)system(buffer
) ;
473 OSptr
->ErrorNo
= errno
;
477 state
->Reg
[0] = ADDRCMDLINE
;
479 state
->Reg
[1] = state
->MemSize
;
481 state
->Reg
[1] = ADDRUSERSTACK
;
483 addr
= state
->Reg
[0] ;
484 cptr
= state
->CommandLine
;
488 temp
= (ARMword
)*cptr
++ ;
489 ARMul_WriteByte(state
,addr
++,temp
) ;
490 } while (temp
!= 0) ;
495 simkernel1_abort_run() ;
497 state
->Emulate
= FALSE
;
503 ARMul_SetCPSR(state
, (ARMul_GetCPSR(state
) & 0xffffffc0) | 0x13) ;
505 ARMul_SetCPSR(state
, (ARMul_GetCPSR(state
) & 0xffffffc0) | 0x3) ;
509 state
->Reg
[0] = OSptr
->ErrorNo
;
513 /* return muber of centi-seconds... */
515 #ifdef CLOCKS_PER_SEC
516 (CLOCKS_PER_SEC
>= 100)
517 ? (ARMword
) (clock() / (CLOCKS_PER_SEC
/ 100))
518 : (ARMword
) ((clock() * 100) / CLOCKS_PER_SEC
) ;
520 /* presume unix... clock() returns microseconds */
521 (ARMword
) (clock() / 10000) ;
523 OSptr
->ErrorNo
= errno
;
527 state
->Reg
[0] = (ARMword
)time(NULL
) ;
528 OSptr
->ErrorNo
= errno
;
532 getstring(state
,state
->Reg
[0],buffer
) ;
533 state
->Reg
[0] = unlink(buffer
) ;
534 OSptr
->ErrorNo
= errno
;
538 char buffer2
[BUFFERSIZE
] ;
540 getstring(state
,state
->Reg
[0],buffer
) ;
541 getstring(state
,state
->Reg
[1],buffer2
) ;
542 state
->Reg
[0] = rename(buffer
,buffer2
) ;
543 OSptr
->ErrorNo
= errno
;
549 /* It seems to me that these are in the wrong order
550 sac@cygnus.com, so I've redone it to use the
551 flags instead, with the functionality which was already
552 there -- ahh, perhaps the TRUNC bit is in a different
553 place on the original host ?*/
554 static char* fmode
[] = {"r","rb","r+","r+b",
557 "r","r","r","r"} /* last 4 are illegal */ ;
562 type
= (unsigned)(state
->Reg
[1] & 3L) ;
563 getstring(state
,state
->Reg
[0],buffer
) ;
564 if (strcmp(buffer
,":tt")==0 && (type
== O_RDONLY
)) /* opening tty "r" */
566 else if (strcmp(buffer
,":tt")==0 && (type
== O_WRONLY
)) /* opening tty "w" */
573 fptr
= fopen(buffer
,"r") ;
576 fptr
= fopen(buffer
,"w") ;
579 fptr
= fopen(buffer
,"rw") ;
586 for (temp
= 0 ; temp
< FOPEN_MAX
; temp
++)
587 if (OSptr
->FileTable
[temp
] == NULL
) {
588 OSptr
->FileTable
[temp
] = fptr
;
589 OSptr
->FileFlags
[temp
] = type
& 1 ; /* preserve the binary bit */
590 state
->Reg
[0] = (ARMword
)(temp
+ 1) ;
593 if (state
->Reg
[0] == 0)
594 OSptr
->ErrorNo
= EMFILE
; /* too many open files */
596 OSptr
->ErrorNo
= errno
;
599 OSptr
->ErrorNo
= errno
;
604 temp
= state
->Reg
[0] ;
605 if (temp
== 0 || temp
> FOPEN_MAX
|| OSptr
->FileTable
[temp
- 1] == 0) {
606 OSptr
->ErrorNo
= EBADF
;
607 state
->Reg
[0] = -1L ;
611 fptr
= OSptr
->FileTable
[temp
] ;
612 if (fptr
== stdin
|| fptr
== stderr
)
615 state
->Reg
[0] = fclose(fptr
) ;
616 OSptr
->FileTable
[temp
] = NULL
;
617 OSptr
->ErrorNo
= errno
;
621 unsigned size
, upto
, type
;
624 temp
= state
->Reg
[0] ;
625 if (temp
== 0 || temp
> FOPEN_MAX
|| OSptr
->FileTable
[temp
- 1] == 0) {
626 OSptr
->ErrorNo
= EBADF
;
627 state
->Reg
[0] = -1L ;
631 fptr
= OSptr
->FileTable
[temp
] ;
632 type
= OSptr
->FileFlags
[temp
] ;
633 addr
= state
->Reg
[1] ;
634 size
= (unsigned)state
->Reg
[2] ;
637 fseek(fptr
,0L,SEEK_CUR
) ;
638 OSptr
->FileFlags
[temp
] = (type
& BINARY
) | WRITEOP
; ;
640 if (size
>= BUFFERSIZE
)
644 for (cptr
= buffer
; (cptr
- buffer
) < upto
; cptr
++) {
645 ch
= (char)ARMul_ReadByte(state
,(ARMword
)addr
++) ;
646 *cptr
= FIXCRLF(type
,ch
) ;
648 temp
= fwrite(buffer
,1,upto
,fptr
) ;
650 state
->Reg
[0] = (ARMword
)(size
- temp
) ;
651 OSptr
->ErrorNo
= errno
;
657 OSptr
->ErrorNo
= errno
;
662 unsigned size
, upto
, type
;
665 temp
= state
->Reg
[0] ;
666 if (temp
== 0 || temp
> FOPEN_MAX
|| OSptr
->FileTable
[temp
- 1] == 0) {
667 OSptr
->ErrorNo
= EBADF
;
668 state
->Reg
[0] = -1L ;
672 fptr
= OSptr
->FileTable
[temp
] ;
673 addr
= state
->Reg
[1] ;
674 size
= (unsigned)state
->Reg
[2] ;
675 type
= OSptr
->FileFlags
[temp
] ;
678 fseek(fptr
,0L,SEEK_CUR
) ;
679 OSptr
->FileFlags
[temp
] = (type
& BINARY
) | READOP
; ;
682 upto
= (size
>= BUFFERSIZE
)?BUFFERSIZE
:size
+ 1 ;
683 if (fgets(buffer
, upto
, fptr
) != 0)
684 temp
= strlen(buffer
) ;
687 upto
-- ; /* 1 char used for terminating null */
690 upto
= (size
>=BUFFERSIZE
)?BUFFERSIZE
:size
;
691 temp
= fread(buffer
,1,upto
,fptr
) ;
693 for (cptr
= buffer
; (cptr
- buffer
) < temp
; cptr
++) {
695 ARMul_WriteByte(state
,(ARMword
)addr
++,FIXCRLF(type
,ch
)) ;
698 state
->Reg
[0] = (ARMword
)(size
- temp
) ;
699 OSptr
->ErrorNo
= errno
;
705 OSptr
->ErrorNo
= errno
;
710 if (state
->Reg
[0] == 0 || state
->Reg
[0] > FOPEN_MAX
711 || OSptr
->FileTable
[state
->Reg
[0] - 1] == 0) {
712 OSptr
->ErrorNo
= EBADF
;
713 state
->Reg
[0] = -1L ;
716 fptr
= OSptr
->FileTable
[state
->Reg
[0] - 1] ;
717 state
->Reg
[0] = fseek(fptr
,(long)state
->Reg
[1],SEEK_SET
) ;
718 OSptr
->ErrorNo
= errno
;
722 if (state
->Reg
[0] == 0 || state
->Reg
[0] > FOPEN_MAX
723 || OSptr
->FileTable
[state
->Reg
[0] - 1] == 0) {
724 OSptr
->ErrorNo
= EBADF
;
725 state
->Reg
[0] = -1L ;
728 fptr
= OSptr
->FileTable
[state
->Reg
[0] - 1] ;
729 addr
= (ARMword
)ftell(fptr
) ;
730 if (fseek(fptr
,0L,SEEK_END
) < 0)
733 state
->Reg
[0] = (ARMword
)ftell(fptr
) ;
734 (void)fseek(fptr
,addr
,SEEK_SET
) ;
736 OSptr
->ErrorNo
= errno
;
740 if (state
->Reg
[0] == 0 || state
->Reg
[0] > FOPEN_MAX
741 || OSptr
->FileTable
[state
->Reg
[0] - 1] == 0) {
742 OSptr
->ErrorNo
= EBADF
;
743 state
->Reg
[0] = -1L ;
746 fptr
= OSptr
->FileTable
[state
->Reg
[0] - 1] ;
747 state
->Reg
[0] = isatty_(fptr
) ;
748 OSptr
->ErrorNo
= errno
;
754 addr
= state
->Reg
[0] ;
755 temp
= state
->Reg
[1] & 0xff ;
756 size
= state
->Reg
[2] ;
757 if (OSptr
->tempnames
[temp
] == NULL
) {
758 if ((OSptr
->tempnames
[temp
] = malloc(L_tmpnam
)) == NULL
) {
762 (void)tmpnam(OSptr
->tempnames
[temp
]) ;
764 cptr
= OSptr
->tempnames
[temp
] ;
765 if (strlen(cptr
) > state
->Reg
[2])
769 ARMul_WriteByte(state
,addr
++,*cptr
) ;
770 } while (*cptr
++ != 0) ;
771 OSptr
->ErrorNo
= errno
;
775 case SWI_InstallHandler
:
776 { ARMword handlerp
= ADDRSOFHANDLERS
+ state
->Reg
[0] * 8;
777 ARMword oldr1
= ARMul_ReadWord(state
, handlerp
),
778 oldr2
= ARMul_ReadWord(state
, handlerp
+ 4);
779 ARMul_WriteWord(state
, handlerp
, state
->Reg
[1]);
780 ARMul_WriteWord(state
, handlerp
+ 4, state
->Reg
[2]);
781 state
->Reg
[1] = oldr1
;
782 state
->Reg
[2] = oldr2
;
786 case SWI_GenerateError
:
787 ARMul_Abort(state
, ARMSWIV
) ;
789 ARMul_SetR15(state
, ARMul_ReadWord(state
, ADDRSOFTVECTORS
+ ARMErrorV
));
792 /* SWI's 0x9x unwind the state of the CPU after an abort of type x */
794 case 0x90: /* Branch through zero */
795 { ARMword oldpsr
= ARMul_GetCPSR(state
) ;
796 ARMul_SetCPSR(state
, (oldpsr
& 0xffffffc0) | 0x13) ;
797 ARMul_SetSPSR(state
, SVC32MODE
, oldpsr
) ;
802 case 0x98: /* Error */
803 { ARMword errorp
= state
->Reg
[0],
804 regp
= state
->Reg
[1];
806 ARMword errorpsr
= ARMul_ReadWord(state
, regp
+ 16*4);
807 for (i
= 0; i
< 15; i
++)
808 ARMul_SetReg(state
,errorpsr
,i
,ARMul_ReadWord(state
, regp
+ i
*4L)) ;
809 state
->Reg
[14] = ARMul_ReadWord(state
, regp
+ 15*4L);
810 state
->Reg
[10] = errorp
;
811 ARMul_SetSPSR(state
,state
->Mode
,errorpsr
) ;
812 OSptr
->ErrorP
= errorp
;
816 case 0x94: /* Data abort */
817 { ARMword addr
= state
->Reg
[14] - 8;
818 ARMword cpsr
= ARMul_GetCPSR(state
) ;
820 addr
= addr
& 0x3fffffc ;
821 ARMul_SetCPSR(state
,ARMul_GetSPSR(state
,cpsr
)) ;
822 UnwindDataAbort(state
, addr
);
823 if (addr
>= FPESTART
&& addr
< FPEEND
) { /* in the FPE */
827 sp
= state
->Reg
[13] ;
828 state
->Reg
[13] += 64 ; /* fix the aborting mode sp */
829 state
->Reg
[14] = ARMul_ReadWord(state
,sp
+ 60) ; /* and its lr */
830 spsr
= ARMul_GetSPSR(state
,state
->Mode
) ;
831 state
->Mode
= ARMul_SwitchMode(state
, state
->Mode
, spsr
);
832 for (i
= 0 ; i
< 15 ; i
++) {
833 ARMul_SetReg(state
,spsr
,i
,ARMul_ReadWord(state
,sp
)) ;
836 ARMul_SetCPSR(state
,cpsr
) ;
837 state
->Reg
[14] = ARMul_ReadWord(state
,sp
) + 4 ; /* botch it */
838 ARMul_SetSPSR(state
,state
->Mode
,spsr
) ;
841 ARMul_SetCPSR(state
,cpsr
) ;
843 /* and fall through to correct r14 */
845 case 0x95: /* Address Exception */
847 case 0x91: /* Undefined instruction */
849 case 0x93: /* Prefetch abort */
854 if (state
->VectorCatch
& (1 << (number
- 0x90))) {
855 ARMul_SetR15(state
, state
->Reg
[14] + 8) ; /* the 8 is the pipelining the the RDI will undo */
856 ARMul_SetCPSR(state
,ARMul_GetSPSR(state
,ARMul_GetCPSR(state
))) ;
858 state
->EndCondition
= 10 ; /* Branch through Zero Error */
860 state
->EndCondition
= (unsigned)number
- 0x8f;
861 state
->Emulate
= FALSE
;
864 ARMword sp
= state
->Reg
[13];
865 ARMul_WriteWord(state
, sp
- 4, state
->Reg
[14]);
866 ARMul_WriteWord(state
, sp
- 8, state
->Reg
[12]);
867 ARMul_WriteWord(state
, sp
- 12, state
->Reg
[11]);
868 ARMul_WriteWord(state
, sp
- 16, state
->Reg
[10]);
869 state
->Reg
[13] = sp
- 16;
870 state
->Reg
[11] = ADDRSOFHANDLERS
+ 8 * (number
- 0x90);
874 /* SWI's 0x8x pass an abort of type x to the debugger if a handler returns */
876 case 0x80: case 0x81: case 0x82: case 0x83:
877 case 0x84: case 0x85: case 0x86: case 0x87: case 0x88:
878 { ARMword sp
= state
->Reg
[13];
879 state
->Reg
[10] = ARMul_ReadWord(state
, sp
);
880 state
->Reg
[11] = ARMul_ReadWord(state
, sp
+ 4);
881 state
->Reg
[12] = ARMul_ReadWord(state
, sp
+ 8);
882 state
->Reg
[14] = ARMul_ReadWord(state
, sp
+ 12);
883 state
->Reg
[13] = sp
+ 16;
884 ARMul_SetR15(state
, state
->Reg
[14] + 8) ; /* the 8 is the pipelining the the RDI will undo */
885 ARMul_SetCPSR(state
,ARMul_GetSPSR(state
,ARMul_GetCPSR(state
))) ;
887 state
->EndCondition
= 10 ; /* Branch through Zero Error */
889 state
->EndCondition
= (unsigned)number
- 0x7f;
890 state
->Emulate
= FALSE
;
895 state
->Emulate
= FALSE
;
906 /***************************************************************************\
907 * The emulator calls this routine when an Exception occurs. The second *
908 * parameter is the address of the relevant exception vector. Returning *
909 * FALSE from this routine causes the trap to be taken, TRUE causes it to *
910 * be ignored (so set state->Emulate to FALSE!). *
911 \***************************************************************************/
913 unsigned ARMul_OSException(ARMul_State
*state
, ARMword vector
, ARMword pc
)
914 { /* don't use this here */
920 /***************************************************************************\
921 * Unwind a data abort *
922 \***************************************************************************/
924 static void UnwindDataAbort(ARMul_State
*state
, ARMword addr
)
926 ARMword instr
= ARMul_ReadWord(state
, addr
);
927 ARMword rn
= BITS(16, 19);
928 ARMword itype
= BITS(24, 27);
930 if (rn
== 15) return;
931 if (itype
== 8 || itype
== 9) {
933 unsigned long regs
= BITS(0, 15);
935 if (!BIT(21)) return; /* no wb */
936 for (; regs
!= 0; offset
++)
937 regs
^= (regs
& -regs
);
938 if (offset
== 0) offset
= 16;
939 } else if (itype
== 12 || /* post-indexed CPDT */
940 (itype
== 13 && BIT(21))) { /* pre_indexed CPDT with WB */
946 state
->Reg
[rn
] -= offset
* 4;
948 state
->Reg
[rn
] += offset
* 4;
951 /***************************************************************************\
952 * Copy a string from the debuggee's memory to the host's *
953 \***************************************************************************/
955 static void getstring(ARMul_State
*state
, ARMword from
, char *to
)
957 *to
= (char)ARMul_ReadByte(state
,from
++) ;
958 } while (*to
++ != '\0') ;