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
;
302 dummy
[i
] = ARMul_ReadByte(state
, state
->Reg
[0] + i
);
306 /* Now we need to decode the Demon open mode */
307 flags
= translate_open_mode
[state
->Reg
[1]];
309 /* Filename ":tt" is special: it denotes stdin/out */
310 if (strcmp (dummy
, ":tt") == 0)
312 if (flags
== O_RDONLY
) /* opening tty "r" */
313 state
->Reg
[0] = 0 /* stdin */ ;
315 state
->Reg
[0] = 1 /* stdout */ ;
319 state
->Reg
[0] = (int) open (dummy
, flags
);
320 OSptr
->ErrorNo
= errno
;
327 /* return number of centi-seconds... */
329 #ifdef CLOCKS_PER_SEC
330 (CLOCKS_PER_SEC
>= 100)
331 ? (ARMword
) (clock() / (CLOCKS_PER_SEC
/ 100))
332 : (ARMword
) ((clock() * 100) / CLOCKS_PER_SEC
) ;
334 /* presume unix... clock() returns microseconds */
335 (ARMword
) (clock() / 10000) ;
337 OSptr
->ErrorNo
= errno
;
341 state
->Reg
[0] = (ARMword
)time(NULL
) ;
342 OSptr
->ErrorNo
= errno
;
346 state
->Reg
[0] = close (state
->Reg
[0]);
347 OSptr
->ErrorNo
= errno
;
351 if (state
->Reg
[0] == 0 || state
->Reg
[0] > FOPEN_MAX
)
353 OSptr
->ErrorNo
= EBADF
;
354 state
->Reg
[0] = -1L ;
357 fildes
= state
->Reg
[0];
358 addr
= lseek(fildes
, 0, SEEK_CUR
);
360 state
->Reg
[0] = -1L ;
363 state
->Reg
[0] = lseek(fildes
, 0L, SEEK_END
);
364 (void)lseek(fildes
, addr
, SEEK_SET
);
366 OSptr
->ErrorNo
= errno
;
371 state
->Emulate
= FALSE
;
376 /* We must return non-zero for failure */
377 state
->Reg
[0] = -1 >= lseek (state
->Reg
[0],
380 OSptr
->ErrorNo
= errno
;
385 (void)fputc((int)state
->Reg
[0],stderr
) ;
386 OSptr
->ErrorNo
= errno
;
390 addr
= state
->Reg
[0] ;
391 while ((temp
= ARMul_ReadByte(state
,addr
++)) != 0)
392 (void)fputc((char)temp
,stderr
) ;
393 OSptr
->ErrorNo
= errno
;
397 state
->Reg
[0] = OSptr
->ErrorNo
;
400 case SWI_Breakpoint
:
401 state
->EndCondition
= RDIError_BreakpointReached
;
402 state
->Emulate
= FALSE
;
406 state
->Reg
[0] = ADDRCMDLINE
;
408 state
->Reg
[1] = state
->MemSize
;
410 state
->Reg
[1] = ADDRUSERSTACK
;
412 addr
= state
->Reg
[0] ;
413 cptr
= state
->CommandLine
;
417 temp
= (ARMword
)*cptr
++ ;
418 ARMul_WriteByte(state
,addr
++,temp
) ;
419 } while (temp
!= 0) ;
424 /* Ignore these SWIs (for now). */
428 state
->Emulate
= FALSE
;
433 unsigned ARMul_OSHandleSWI(ARMul_State
*state
,ARMword number
)
441 state
->Emulate
= FALSE
;
445 ARMul_SetCPSR(state
, (ARMul_GetCPSR(state
) & 0xffffffc0) | 0x13) ;
447 ARMul_SetCPSR(state
, (ARMul_GetCPSR(state
) & 0xffffffc0) | 0x3) ;
454 char buffer
[BUFFERSIZE
], *cptr
;
456 struct OSblock
* OSptr
= (struct OSblock
*)state
->OSptr
;
460 (void)fputc((int)state
->Reg
[0],stderr
) ;
461 OSptr
->ErrorNo
= errno
;
465 addr
= state
->Reg
[0] ;
466 while ((temp
= ARMul_ReadByte(state
,addr
++)) != 0)
467 fputc((char)temp
,stderr
) ;
468 OSptr
->ErrorNo
= errno
;
472 state
->Reg
[0] = (ARMword
)fgetc(stdin
) ;
473 OSptr
->ErrorNo
= errno
;
477 addr
= state
->Reg
[0] ;
478 getstring(state
,state
->Reg
[0],buffer
) ;
479 state
->Reg
[0] = (ARMword
)system(buffer
) ;
480 OSptr
->ErrorNo
= errno
;
484 state
->Reg
[0] = ADDRCMDLINE
;
486 state
->Reg
[1] = state
->MemSize
;
488 state
->Reg
[1] = ADDRUSERSTACK
;
490 addr
= state
->Reg
[0] ;
491 cptr
= state
->CommandLine
;
495 temp
= (ARMword
)*cptr
++ ;
496 ARMul_WriteByte(state
,addr
++,temp
) ;
497 } while (temp
!= 0) ;
502 simkernel1_abort_run() ;
504 state
->Emulate
= FALSE
;
510 ARMul_SetCPSR(state
, (ARMul_GetCPSR(state
) & 0xffffffc0) | 0x13) ;
512 ARMul_SetCPSR(state
, (ARMul_GetCPSR(state
) & 0xffffffc0) | 0x3) ;
516 state
->Reg
[0] = OSptr
->ErrorNo
;
520 /* return muber of centi-seconds... */
522 #ifdef CLOCKS_PER_SEC
523 (CLOCKS_PER_SEC
>= 100)
524 ? (ARMword
) (clock() / (CLOCKS_PER_SEC
/ 100))
525 : (ARMword
) ((clock() * 100) / CLOCKS_PER_SEC
) ;
527 /* presume unix... clock() returns microseconds */
528 (ARMword
) (clock() / 10000) ;
530 OSptr
->ErrorNo
= errno
;
534 state
->Reg
[0] = (ARMword
)time(NULL
) ;
535 OSptr
->ErrorNo
= errno
;
539 getstring(state
,state
->Reg
[0],buffer
) ;
540 state
->Reg
[0] = unlink(buffer
) ;
541 OSptr
->ErrorNo
= errno
;
545 char buffer2
[BUFFERSIZE
] ;
547 getstring(state
,state
->Reg
[0],buffer
) ;
548 getstring(state
,state
->Reg
[1],buffer2
) ;
549 state
->Reg
[0] = rename(buffer
,buffer2
) ;
550 OSptr
->ErrorNo
= errno
;
556 /* It seems to me that these are in the wrong order
557 sac@cygnus.com, so I've redone it to use the
558 flags instead, with the functionality which was already
559 there -- ahh, perhaps the TRUNC bit is in a different
560 place on the original host ?*/
561 static char* fmode
[] = {"r","rb","r+","r+b",
564 "r","r","r","r"} /* last 4 are illegal */ ;
569 type
= (unsigned)(state
->Reg
[1] & 3L) ;
570 getstring(state
,state
->Reg
[0],buffer
) ;
571 if (strcmp(buffer
,":tt")==0 && (type
== O_RDONLY
)) /* opening tty "r" */
573 else if (strcmp(buffer
,":tt")==0 && (type
== O_WRONLY
)) /* opening tty "w" */
580 fptr
= fopen(buffer
,"r") ;
583 fptr
= fopen(buffer
,"w") ;
586 fptr
= fopen(buffer
,"rw") ;
593 for (temp
= 0 ; temp
< FOPEN_MAX
; temp
++)
594 if (OSptr
->FileTable
[temp
] == NULL
) {
595 OSptr
->FileTable
[temp
] = fptr
;
596 OSptr
->FileFlags
[temp
] = type
& 1 ; /* preserve the binary bit */
597 state
->Reg
[0] = (ARMword
)(temp
+ 1) ;
600 if (state
->Reg
[0] == 0)
601 OSptr
->ErrorNo
= EMFILE
; /* too many open files */
603 OSptr
->ErrorNo
= errno
;
606 OSptr
->ErrorNo
= errno
;
611 temp
= state
->Reg
[0] ;
612 if (temp
== 0 || temp
> FOPEN_MAX
|| OSptr
->FileTable
[temp
- 1] == 0) {
613 OSptr
->ErrorNo
= EBADF
;
614 state
->Reg
[0] = -1L ;
618 fptr
= OSptr
->FileTable
[temp
] ;
619 if (fptr
== stdin
|| fptr
== stderr
)
622 state
->Reg
[0] = fclose(fptr
) ;
623 OSptr
->FileTable
[temp
] = NULL
;
624 OSptr
->ErrorNo
= errno
;
628 unsigned size
, upto
, type
;
631 temp
= state
->Reg
[0] ;
632 if (temp
== 0 || temp
> FOPEN_MAX
|| OSptr
->FileTable
[temp
- 1] == 0) {
633 OSptr
->ErrorNo
= EBADF
;
634 state
->Reg
[0] = -1L ;
638 fptr
= OSptr
->FileTable
[temp
] ;
639 type
= OSptr
->FileFlags
[temp
] ;
640 addr
= state
->Reg
[1] ;
641 size
= (unsigned)state
->Reg
[2] ;
644 fseek(fptr
,0L,SEEK_CUR
) ;
645 OSptr
->FileFlags
[temp
] = (type
& BINARY
) | WRITEOP
; ;
647 if (size
>= BUFFERSIZE
)
651 for (cptr
= buffer
; (cptr
- buffer
) < upto
; cptr
++) {
652 ch
= (char)ARMul_ReadByte(state
,(ARMword
)addr
++) ;
653 *cptr
= FIXCRLF(type
,ch
) ;
655 temp
= fwrite(buffer
,1,upto
,fptr
) ;
657 state
->Reg
[0] = (ARMword
)(size
- temp
) ;
658 OSptr
->ErrorNo
= errno
;
664 OSptr
->ErrorNo
= errno
;
669 unsigned size
, upto
, type
;
672 temp
= state
->Reg
[0] ;
673 if (temp
== 0 || temp
> FOPEN_MAX
|| OSptr
->FileTable
[temp
- 1] == 0) {
674 OSptr
->ErrorNo
= EBADF
;
675 state
->Reg
[0] = -1L ;
679 fptr
= OSptr
->FileTable
[temp
] ;
680 addr
= state
->Reg
[1] ;
681 size
= (unsigned)state
->Reg
[2] ;
682 type
= OSptr
->FileFlags
[temp
] ;
685 fseek(fptr
,0L,SEEK_CUR
) ;
686 OSptr
->FileFlags
[temp
] = (type
& BINARY
) | READOP
; ;
689 upto
= (size
>= BUFFERSIZE
)?BUFFERSIZE
:size
+ 1 ;
690 if (fgets(buffer
, upto
, fptr
) != 0)
691 temp
= strlen(buffer
) ;
694 upto
-- ; /* 1 char used for terminating null */
697 upto
= (size
>=BUFFERSIZE
)?BUFFERSIZE
:size
;
698 temp
= fread(buffer
,1,upto
,fptr
) ;
700 for (cptr
= buffer
; (cptr
- buffer
) < temp
; cptr
++) {
702 ARMul_WriteByte(state
,(ARMword
)addr
++,FIXCRLF(type
,ch
)) ;
705 state
->Reg
[0] = (ARMword
)(size
- temp
) ;
706 OSptr
->ErrorNo
= errno
;
712 OSptr
->ErrorNo
= errno
;
717 if (state
->Reg
[0] == 0 || state
->Reg
[0] > FOPEN_MAX
718 || OSptr
->FileTable
[state
->Reg
[0] - 1] == 0) {
719 OSptr
->ErrorNo
= EBADF
;
720 state
->Reg
[0] = -1L ;
723 fptr
= OSptr
->FileTable
[state
->Reg
[0] - 1] ;
724 state
->Reg
[0] = fseek(fptr
,(long)state
->Reg
[1],SEEK_SET
) ;
725 OSptr
->ErrorNo
= errno
;
729 if (state
->Reg
[0] == 0 || state
->Reg
[0] > FOPEN_MAX
730 || OSptr
->FileTable
[state
->Reg
[0] - 1] == 0) {
731 OSptr
->ErrorNo
= EBADF
;
732 state
->Reg
[0] = -1L ;
735 fptr
= OSptr
->FileTable
[state
->Reg
[0] - 1] ;
736 addr
= (ARMword
)ftell(fptr
) ;
737 if (fseek(fptr
,0L,SEEK_END
) < 0)
740 state
->Reg
[0] = (ARMword
)ftell(fptr
) ;
741 (void)fseek(fptr
,addr
,SEEK_SET
) ;
743 OSptr
->ErrorNo
= errno
;
747 if (state
->Reg
[0] == 0 || state
->Reg
[0] > FOPEN_MAX
748 || OSptr
->FileTable
[state
->Reg
[0] - 1] == 0) {
749 OSptr
->ErrorNo
= EBADF
;
750 state
->Reg
[0] = -1L ;
753 fptr
= OSptr
->FileTable
[state
->Reg
[0] - 1] ;
754 state
->Reg
[0] = isatty_(fptr
) ;
755 OSptr
->ErrorNo
= errno
;
761 addr
= state
->Reg
[0] ;
762 temp
= state
->Reg
[1] & 0xff ;
763 size
= state
->Reg
[2] ;
764 if (OSptr
->tempnames
[temp
] == NULL
) {
765 if ((OSptr
->tempnames
[temp
] = malloc(L_tmpnam
)) == NULL
) {
769 (void)tmpnam(OSptr
->tempnames
[temp
]) ;
771 cptr
= OSptr
->tempnames
[temp
] ;
772 if (strlen(cptr
) > state
->Reg
[2])
776 ARMul_WriteByte(state
,addr
++,*cptr
) ;
777 } while (*cptr
++ != 0) ;
778 OSptr
->ErrorNo
= errno
;
782 case SWI_InstallHandler
:
783 { ARMword handlerp
= ADDRSOFHANDLERS
+ state
->Reg
[0] * 8;
784 ARMword oldr1
= ARMul_ReadWord(state
, handlerp
),
785 oldr2
= ARMul_ReadWord(state
, handlerp
+ 4);
786 ARMul_WriteWord(state
, handlerp
, state
->Reg
[1]);
787 ARMul_WriteWord(state
, handlerp
+ 4, state
->Reg
[2]);
788 state
->Reg
[1] = oldr1
;
789 state
->Reg
[2] = oldr2
;
793 case SWI_GenerateError
:
794 ARMul_Abort(state
, ARMSWIV
) ;
796 ARMul_SetR15(state
, ARMul_ReadWord(state
, ADDRSOFTVECTORS
+ ARMErrorV
));
799 /* SWI's 0x9x unwind the state of the CPU after an abort of type x */
801 case 0x90: /* Branch through zero */
802 { ARMword oldpsr
= ARMul_GetCPSR(state
) ;
803 ARMul_SetCPSR(state
, (oldpsr
& 0xffffffc0) | 0x13) ;
804 ARMul_SetSPSR(state
, SVC32MODE
, oldpsr
) ;
809 case 0x98: /* Error */
810 { ARMword errorp
= state
->Reg
[0],
811 regp
= state
->Reg
[1];
813 ARMword errorpsr
= ARMul_ReadWord(state
, regp
+ 16*4);
814 for (i
= 0; i
< 15; i
++)
815 ARMul_SetReg(state
,errorpsr
,i
,ARMul_ReadWord(state
, regp
+ i
*4L)) ;
816 state
->Reg
[14] = ARMul_ReadWord(state
, regp
+ 15*4L);
817 state
->Reg
[10] = errorp
;
818 ARMul_SetSPSR(state
,state
->Mode
,errorpsr
) ;
819 OSptr
->ErrorP
= errorp
;
823 case 0x94: /* Data abort */
824 { ARMword addr
= state
->Reg
[14] - 8;
825 ARMword cpsr
= ARMul_GetCPSR(state
) ;
827 addr
= addr
& 0x3fffffc ;
828 ARMul_SetCPSR(state
,ARMul_GetSPSR(state
,cpsr
)) ;
829 UnwindDataAbort(state
, addr
);
830 if (addr
>= FPESTART
&& addr
< FPEEND
) { /* in the FPE */
834 sp
= state
->Reg
[13] ;
835 state
->Reg
[13] += 64 ; /* fix the aborting mode sp */
836 state
->Reg
[14] = ARMul_ReadWord(state
,sp
+ 60) ; /* and its lr */
837 spsr
= ARMul_GetSPSR(state
,state
->Mode
) ;
838 state
->Mode
= ARMul_SwitchMode(state
, state
->Mode
, spsr
);
839 for (i
= 0 ; i
< 15 ; i
++) {
840 ARMul_SetReg(state
,spsr
,i
,ARMul_ReadWord(state
,sp
)) ;
843 ARMul_SetCPSR(state
,cpsr
) ;
844 state
->Reg
[14] = ARMul_ReadWord(state
,sp
) + 4 ; /* botch it */
845 ARMul_SetSPSR(state
,state
->Mode
,spsr
) ;
848 ARMul_SetCPSR(state
,cpsr
) ;
850 /* and fall through to correct r14 */
852 case 0x95: /* Address Exception */
854 case 0x91: /* Undefined instruction */
856 case 0x93: /* Prefetch abort */
861 if (state
->VectorCatch
& (1 << (number
- 0x90))) {
862 ARMul_SetR15(state
, state
->Reg
[14] + 8) ; /* the 8 is the pipelining the the RDI will undo */
863 ARMul_SetCPSR(state
,ARMul_GetSPSR(state
,ARMul_GetCPSR(state
))) ;
865 state
->EndCondition
= 10 ; /* Branch through Zero Error */
867 state
->EndCondition
= (unsigned)number
- 0x8f;
868 state
->Emulate
= FALSE
;
871 ARMword sp
= state
->Reg
[13];
872 ARMul_WriteWord(state
, sp
- 4, state
->Reg
[14]);
873 ARMul_WriteWord(state
, sp
- 8, state
->Reg
[12]);
874 ARMul_WriteWord(state
, sp
- 12, state
->Reg
[11]);
875 ARMul_WriteWord(state
, sp
- 16, state
->Reg
[10]);
876 state
->Reg
[13] = sp
- 16;
877 state
->Reg
[11] = ADDRSOFHANDLERS
+ 8 * (number
- 0x90);
881 /* SWI's 0x8x pass an abort of type x to the debugger if a handler returns */
883 case 0x80: case 0x81: case 0x82: case 0x83:
884 case 0x84: case 0x85: case 0x86: case 0x87: case 0x88:
885 { ARMword sp
= state
->Reg
[13];
886 state
->Reg
[10] = ARMul_ReadWord(state
, sp
);
887 state
->Reg
[11] = ARMul_ReadWord(state
, sp
+ 4);
888 state
->Reg
[12] = ARMul_ReadWord(state
, sp
+ 8);
889 state
->Reg
[14] = ARMul_ReadWord(state
, sp
+ 12);
890 state
->Reg
[13] = sp
+ 16;
891 ARMul_SetR15(state
, state
->Reg
[14] + 8) ; /* the 8 is the pipelining the the RDI will undo */
892 ARMul_SetCPSR(state
,ARMul_GetSPSR(state
,ARMul_GetCPSR(state
))) ;
894 state
->EndCondition
= 10 ; /* Branch through Zero Error */
896 state
->EndCondition
= (unsigned)number
- 0x7f;
897 state
->Emulate
= FALSE
;
902 state
->Emulate
= FALSE
;
913 /***************************************************************************\
914 * The emulator calls this routine when an Exception occurs. The second *
915 * parameter is the address of the relevant exception vector. Returning *
916 * FALSE from this routine causes the trap to be taken, TRUE causes it to *
917 * be ignored (so set state->Emulate to FALSE!). *
918 \***************************************************************************/
920 unsigned ARMul_OSException(ARMul_State
*state
, ARMword vector
, ARMword pc
)
921 { /* don't use this here */
927 /***************************************************************************\
928 * Unwind a data abort *
929 \***************************************************************************/
931 static void UnwindDataAbort(ARMul_State
*state
, ARMword addr
)
933 ARMword instr
= ARMul_ReadWord(state
, addr
);
934 ARMword rn
= BITS(16, 19);
935 ARMword itype
= BITS(24, 27);
937 if (rn
== 15) return;
938 if (itype
== 8 || itype
== 9) {
940 unsigned long regs
= BITS(0, 15);
942 if (!BIT(21)) return; /* no wb */
943 for (; regs
!= 0; offset
++)
944 regs
^= (regs
& -regs
);
945 if (offset
== 0) offset
= 16;
946 } else if (itype
== 12 || /* post-indexed CPDT */
947 (itype
== 13 && BIT(21))) { /* pre_indexed CPDT with WB */
953 state
->Reg
[rn
] -= offset
* 4;
955 state
->Reg
[rn
] += offset
* 4;
958 /***************************************************************************\
959 * Copy a string from the debuggee's memory to the host's *
960 \***************************************************************************/
962 static void getstring(ARMul_State
*state
, ARMword from
, char *to
)
964 *to
= (char)ARMul_ReadByte(state
,from
++) ;
965 } while (*to
++ != '\0') ;