--- /dev/null
+/* armos.c -- ARMulator OS interface: ARM6 Instruction Emulator.
+ Copyright (C) 1994 Advanced RISC Machines Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* This file contains a model of Demon, ARM Ltd's Debug Monitor,
+including all the SWI's required to support the C library. The code in
+it is not really for the faint-hearted (especially the abort handling
+code), but it is a complete example. Defining NOOS will disable all the
+fun, and definign VAILDATE will define SWI 1 to enter SVC mode, and SWI
+0x11 to halt the emulator. */
+
+#include "config.h"
+
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+#ifndef O_WRONLY
+#define O_WRONLY 1
+#endif
+#ifndef O_RDWR
+#define O_RDWR 2
+#endif
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#ifdef __STDC__
+#define unlink(s) remove(s)
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* For SEEK_SET etc */
+#endif
+
+#ifdef __riscos
+extern int _fisatty(FILE *);
+#define isatty_(f) _fisatty(f)
+#else
+#ifdef __ZTC__
+#include <io.h>
+#define isatty_(f) isatty((f)->_file)
+#else
+#ifdef macintosh
+#include <ioctl.h>
+#define isatty_(f) (~ioctl((f)->_file,FIOINTERACTIVE,NULL))
+#else
+#define isatty_(f) isatty(fileno(f))
+#endif
+#endif
+#endif
+
+#include "armdefs.h"
+#include "armos.h"
+#ifndef NOOS
+#ifndef VALIDATE
+/* #ifndef ASIM */
+#include "armfpe.h"
+/* #endif */
+#endif
+#endif
+
+/* For RDIError_BreakpointReached. */
+#include "dbg_rdi.h"
+
+extern unsigned ARMul_OSInit(ARMul_State *state) ;
+extern void ARMul_OSExit(ARMul_State *state) ;
+extern unsigned ARMul_OSHandleSWI(ARMul_State *state,ARMword number) ;
+extern unsigned ARMul_OSException(ARMul_State *state, ARMword vector, ARMword pc) ;
+extern ARMword ARMul_OSLastErrorP(ARMul_State *state) ;
+extern ARMword ARMul_Debug(ARMul_State *state, ARMword pc, ARMword instr) ;
+
+#define BUFFERSIZE 4096
+#ifndef FOPEN_MAX
+#define FOPEN_MAX 64
+#endif
+#define UNIQUETEMPS 256
+
+#ifndef NOOS
+static void UnwindDataAbort(ARMul_State *state, ARMword addr);
+static void getstring(ARMul_State *state, ARMword from, char *to) ;
+#endif
+
+/***************************************************************************\
+* OS private Information *
+\***************************************************************************/
+
+struct OSblock {
+ ARMword Time0 ;
+ ARMword ErrorP ;
+ ARMword ErrorNo ;
+ FILE *FileTable[FOPEN_MAX] ;
+ char FileFlags[FOPEN_MAX] ;
+ char *tempnames[UNIQUETEMPS] ;
+ } ;
+
+#define NOOP 0
+#define BINARY 1
+#define READOP 2
+#define WRITEOP 4
+
+#ifdef macintosh
+#define FIXCRLF(t,c) ((t & BINARY)?c:((c=='\n'||c=='\r')?(c ^ 7):c))
+#else
+#define FIXCRLF(t,c) c
+#endif
+
+static ARMword softvectorcode[] =
+{ /* basic: swi tidyexception + event; mov pc, lr;
+ ldmia r11,{r11,pc}; swi generateexception + event
+ */
+ 0xef000090, 0xe1a0e00f, 0xe89b8800, 0xef000080, /*Reset*/
+ 0xef000091, 0xe1a0e00f, 0xe89b8800, 0xef000081, /*Undef*/
+ 0xef000092, 0xe1a0e00f, 0xe89b8800, 0xef000082, /*SWI */
+ 0xef000093, 0xe1a0e00f, 0xe89b8800, 0xef000083, /*Prefetch abort*/
+ 0xef000094, 0xe1a0e00f, 0xe89b8800, 0xef000084, /*Data abort*/
+ 0xef000095, 0xe1a0e00f, 0xe89b8800, 0xef000085, /*Address exception*/
+ 0xef000096, 0xe1a0e00f, 0xe89b8800, 0xef000086, /*IRQ*/
+ 0xef000097, 0xe1a0e00f, 0xe89b8800, 0xef000087, /*FIQ*/
+ 0xef000098, 0xe1a0e00f, 0xe89b8800, 0xef000088, /*Error*/
+ 0xe1a0f00e /* default handler */
+};
+
+/***************************************************************************\
+* Time for the Operating System to initialise itself. *
+\***************************************************************************/
+
+unsigned ARMul_OSInit(ARMul_State *state)
+{
+#ifndef NOOS
+#ifndef VALIDATE
+ ARMword instr, i , j ;
+ struct OSblock* OSptr = (struct OSblock*)state->OSptr;
+
+ if (state->OSptr == NULL) {
+ state->OSptr = (unsigned char *)malloc(sizeof(struct OSblock));
+ if (state->OSptr == NULL) {
+ perror("OS Memory");
+ exit(15);
+ }
+ }
+ OSptr = (struct OSblock*)state->OSptr;
+ OSptr->ErrorP = 0;
+ state->Reg[13] = ADDRSUPERSTACK; /* set up a stack for the current mode */
+ ARMul_SetReg(state,SVC32MODE,13,ADDRSUPERSTACK); /* and for supervisor mode */
+ ARMul_SetReg(state,ABORT32MODE,13,ADDRSUPERSTACK); /* and for abort 32 mode */
+ ARMul_SetReg(state,UNDEF32MODE,13,ADDRSUPERSTACK); /* and for undef 32 mode */
+ instr = 0xe59ff000 | (ADDRSOFTVECTORS - 8); /* load pc from soft vector */
+ for (i = ARMul_ResetV ; i <= ARMFIQV ; i += 4)
+ ARMul_WriteWord(state, i, instr); /* write hardware vectors */
+ for (i = ARMul_ResetV ; i <= ARMFIQV + 4 ; i += 4) {
+ ARMul_WriteWord(state, ADDRSOFTVECTORS + i, SOFTVECTORCODE + i * 4);
+ ARMul_WriteWord(state, ADDRSOFHANDLERS + 2*i + 4L, SOFTVECTORCODE + sizeof(softvectorcode) - 4L);
+ }
+ for (i = 0 ; i < sizeof(softvectorcode) ; i += 4)
+ ARMul_WriteWord(state, SOFTVECTORCODE + i, softvectorcode[i/4]);
+ for (i = 0 ; i < FOPEN_MAX ; i++)
+ OSptr->FileTable[i] = NULL ;
+ for (i = 0 ; i < UNIQUETEMPS ; i++)
+ OSptr->tempnames[i] = NULL ;
+ ARMul_ConsolePrint (state, ", Demon 1.01");
+
+/* #ifndef ASIM */
+
+ /* install fpe */
+ for (i = 0 ; i < fpesize ; i+=4) /* copy the code */
+ ARMul_WriteWord(state,FPESTART + i,fpecode[i >> 2]) ;
+ for (i = FPESTART + fpesize ; ; i-=4) { /* reverse the error strings */
+ if ((j = ARMul_ReadWord(state,i)) == 0xffffffff)
+ break ;
+ if (state->bigendSig && j < 0x80000000) { /* it's part of the string so swap it */
+ j = ((j >> 0x18) & 0x000000ff) |
+ ((j >> 0x08) & 0x0000ff00) |
+ ((j << 0x08) & 0x00ff0000) |
+ ((j << 0x18) & 0xff000000) ;
+ ARMul_WriteWord(state,i,j) ;
+ }
+ }
+ ARMul_WriteWord(state,FPEOLDVECT,ARMul_ReadWord(state,4)) ; /* copy old illegal instr vector */
+ ARMul_WriteWord(state,4,FPENEWVECT(ARMul_ReadWord(state,i-4))) ; /* install new vector */
+ ARMul_ConsolePrint (state, ", FPE") ;
+
+/* #endif /* ASIM */
+#endif /* VALIDATE */
+#endif /* NOOS */
+
+ return(TRUE) ;
+}
+
+void ARMul_OSExit(ARMul_State *state)
+{
+ free((char *)state->OSptr) ;
+}
+
+
+/***************************************************************************\
+* Return the last Operating System Error. *
+\***************************************************************************/
+
+ARMword ARMul_OSLastErrorP(ARMul_State *state)
+{
+ return ((struct OSblock *)state->OSptr)->ErrorP;
+}
+
+/***************************************************************************\
+* The emulator calls this routine when a SWI instruction is encuntered. The *
+* parameter passed is the SWI number (lower 24 bits of the instruction). *
+\***************************************************************************/
+
+#if 1
+/* This is the cygnus way of doing it, which makes it simple
+ to do our tests */
+
+
+static int translate_open_mode[] =
+{
+ O_RDONLY, /* "r" */
+ O_RDONLY+O_BINARY, /* "rb" */
+ O_RDWR, /* "r+" */
+ O_RDWR +O_BINARY, /* "r+b" */
+ O_WRONLY +O_CREAT+O_TRUNC, /* "w" */
+ O_WRONLY+O_BINARY+O_CREAT+O_TRUNC, /* "wb" */
+ O_RDWR +O_CREAT+O_TRUNC, /* "w+" */
+ O_RDWR +O_BINARY+O_CREAT+O_TRUNC, /* "w+b" */
+ O_WRONLY +O_APPEND+O_CREAT,/* "a" */
+ O_WRONLY+O_BINARY+O_APPEND+O_CREAT,/* "ab" */
+ O_RDWR +O_APPEND+O_CREAT,/* "a+" */
+ O_RDWR +O_BINARY+O_APPEND+O_CREAT /* "a+b" */
+};
+
+unsigned ARMul_OSHandleSWI(ARMul_State *state,ARMword number)
+{
+ ARMword addr, temp, fildes ;
+ char buffer[BUFFERSIZE], *cptr ;
+ FILE *fptr ;
+ struct OSblock* OSptr = (struct OSblock*)state->OSptr ;
+
+ switch (number)
+ {
+ case SWI_Read:
+ {
+ int f = state->Reg[0];
+ int ptr = state->Reg[1];
+ int len = state->Reg[2];
+ int res;
+ int i;
+ char *local = malloc (len);
+ res = read (f,local, len);
+ if (res > 0)
+ for (i = 0; i < res; i++)
+ ARMul_WriteByte(state, ptr + i, local[i]) ;
+ free (local);
+ state->Reg[0] = res == -1 ? -1 : len - res;
+ OSptr->ErrorNo = errno;
+ return TRUE;
+ }
+
+ case SWI_Write:
+ {
+ int f = state->Reg[0];
+ int ptr = state->Reg[1];
+ int len = state->Reg[2];
+ int res;
+ int i;
+ char *local = malloc (len);
+
+ for (i = 0; i < len; i++)
+ {
+ local[i] = ARMul_ReadByte(state, ptr + i);
+ }
+ res = write (f, local, len);
+ state->Reg[0] = res == -1 ? -1 : len - res;
+ free (local);
+ OSptr->ErrorNo = errno;
+ return TRUE;
+ }
+
+ case SWI_Open:
+ {
+ char dummy[2000];
+ int i;
+ for (i = 0;
+ dummy[i] = ARMul_ReadByte(state, state->Reg[0] + i);
+ i++)
+ ;
+
+ /* Now we need to decode the Demon open mode */
+ flags = translate_open_mode[state->Reg[1]];
+
+ /* Filename ":tt" is special: it denotes stdin/out */
+ if (strcmp (dummy, ":tt") == 0)
+ {
+ if (flags == O_RDONLY) /* opening tty "r" */
+ state->Reg[0] = 0 /* stdin */ ;
+ else
+ state->Reg[0] = 1 /* stdout */ ;
+ }
+ else
+ {
+ state->Reg[0] = (int) open (dummy, flags);
+ OSptr->ErrorNo = errno;
+ }
+
+ return TRUE;
+ }
+
+ case SWI_Clock :
+ /* return number of centi-seconds... */
+ state->Reg[0] =
+#ifdef CLOCKS_PER_SEC
+ (CLOCKS_PER_SEC >= 100)
+ ? (ARMword) (clock() / (CLOCKS_PER_SEC / 100))
+ : (ARMword) ((clock() * 100) / CLOCKS_PER_SEC) ;
+#else
+ /* presume unix... clock() returns microseconds */
+ (ARMword) (clock() / 10000) ;
+#endif
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_Time :
+ state->Reg[0] = (ARMword)time(NULL) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_Close:
+ state->Reg[0] = close (state->Reg[0]);
+ OSptr->ErrorNo = errno;
+ return TRUE;
+
+ case SWI_Flen :
+ if (state->Reg[0] == 0 || state->Reg[0] > FOPEN_MAX)
+ {
+ OSptr->ErrorNo = EBADF ;
+ state->Reg[0] = -1L ;
+ return(TRUE) ;
+ }
+ fildes = state->Reg[0];
+ addr = lseek(fildes, 0, SEEK_CUR);
+ if (addr < 0)
+ state->Reg[0] = -1L ;
+ else
+ {
+ state->Reg[0] = lseek(fildes, 0L, SEEK_END);
+ (void)lseek(fildes, addr, SEEK_SET);
+ }
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+
+ case SWI_Exit:
+ state->Emulate = FALSE ;
+ return TRUE;
+
+ case SWI_Seek:
+ {
+ /* We must return non-zero for failure */
+ state->Reg[0] = -1 >= lseek (state->Reg[0],
+ state->Reg[1],
+ SEEK_SET);
+ OSptr->ErrorNo = errno;
+ return TRUE;
+ }
+
+ case SWI_WriteC :
+ (void)fputc((int)state->Reg[0],stderr) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_Write0 :
+ addr = state->Reg[0] ;
+ while ((temp = ARMul_ReadByte(state,addr++)) != 0)
+ (void)fputc((char)temp,stderr) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_GetErrno :
+ state->Reg[0] = OSptr->ErrorNo ;
+ return(TRUE) ;
+
+ case SWI_Breakpoint :
+ state->EndCondition = RDIError_BreakpointReached ;
+ state->Emulate = FALSE ;
+ return(TRUE) ;
+
+ case SWI_GetEnv :
+ state->Reg[0] = ADDRCMDLINE ;
+ if (state->MemSize)
+ state->Reg[1] = state->MemSize ;
+ else
+ state->Reg[1] = ADDRUSERSTACK ;
+
+ addr = state->Reg[0] ;
+ cptr = state->CommandLine ;
+ if (cptr == NULL)
+ cptr = "\0" ;
+ do {
+ temp = (ARMword)*cptr++ ;
+ ARMul_WriteByte(state,addr++,temp) ;
+ } while (temp != 0) ;
+ return(TRUE) ;
+
+ default :
+ state->Emulate = FALSE ;
+ return(FALSE) ;
+ }
+}
+#else
+unsigned ARMul_OSHandleSWI(ARMul_State *state,ARMword number)
+{
+#ifdef NOOS
+ return(FALSE) ;
+#else
+#ifdef VALIDATE
+ switch (number) {
+ case 0x11 :
+ state->Emulate = FALSE ;
+ return(TRUE) ;
+ case 0x01 :
+ if (ARM32BITMODE)
+ ARMul_SetCPSR(state, (ARMul_GetCPSR(state) & 0xffffffc0) | 0x13) ;
+ else
+ ARMul_SetCPSR(state, (ARMul_GetCPSR(state) & 0xffffffc0) | 0x3) ;
+ return(TRUE) ;
+ default :
+ return(FALSE) ;
+ }
+#else
+ ARMword addr, temp ;
+ char buffer[BUFFERSIZE], *cptr ;
+ FILE *fptr ;
+ struct OSblock* OSptr = (struct OSblock*)state->OSptr ;
+
+ switch (number) {
+ case SWI_WriteC :
+ (void)fputc((int)state->Reg[0],stderr) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_Write0 :
+ addr = state->Reg[0] ;
+ while ((temp = ARMul_ReadByte(state,addr++)) != 0)
+ fputc((char)temp,stderr) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_ReadC :
+ state->Reg[0] = (ARMword)fgetc(stdin) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_CLI :
+ addr = state->Reg[0] ;
+ getstring(state,state->Reg[0],buffer) ;
+ state->Reg[0] = (ARMword)system(buffer) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_GetEnv :
+ state->Reg[0] = ADDRCMDLINE ;
+ if (state->MemSize)
+ state->Reg[1] = state->MemSize ;
+ else
+ state->Reg[1] = ADDRUSERSTACK ;
+
+ addr = state->Reg[0] ;
+ cptr = state->CommandLine ;
+ if (cptr == NULL)
+ cptr = "\0" ;
+ do {
+ temp = (ARMword)*cptr++ ;
+ ARMul_WriteByte(state,addr++,temp) ;
+ } while (temp != 0) ;
+ return(TRUE) ;
+
+ case SWI_Exit :
+#ifdef ASIM
+ simkernel1_abort_run() ;
+#else
+ state->Emulate = FALSE ;
+#endif
+ return(TRUE) ;
+
+ case SWI_EnterOS :
+ if (ARM32BITMODE)
+ ARMul_SetCPSR(state, (ARMul_GetCPSR(state) & 0xffffffc0) | 0x13) ;
+ else
+ ARMul_SetCPSR(state, (ARMul_GetCPSR(state) & 0xffffffc0) | 0x3) ;
+ return(TRUE) ;
+
+ case SWI_GetErrno :
+ state->Reg[0] = OSptr->ErrorNo ;
+ return(TRUE) ;
+
+ case SWI_Clock :
+ /* return muber of centi-seconds... */
+ state->Reg[0] =
+#ifdef CLOCKS_PER_SEC
+ (CLOCKS_PER_SEC >= 100)
+ ? (ARMword) (clock() / (CLOCKS_PER_SEC / 100))
+ : (ARMword) ((clock() * 100) / CLOCKS_PER_SEC) ;
+#else
+ /* presume unix... clock() returns microseconds */
+ (ARMword) (clock() / 10000) ;
+#endif
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_Time :
+ state->Reg[0] = (ARMword)time(NULL) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_Remove :
+ getstring(state,state->Reg[0],buffer) ;
+ state->Reg[0] = unlink(buffer) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_Rename : {
+ char buffer2[BUFFERSIZE] ;
+
+ getstring(state,state->Reg[0],buffer) ;
+ getstring(state,state->Reg[1],buffer2) ;
+ state->Reg[0] = rename(buffer,buffer2) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+ }
+
+ case SWI_Open : {
+#if 0
+ /* It seems to me that these are in the wrong order
+ sac@cygnus.com, so I've redone it to use the
+ flags instead, with the functionality which was already
+ there -- ahh, perhaps the TRUNC bit is in a different
+ place on the original host ?*/
+ static char* fmode[] = {"r","rb","r+","r+b",
+ "w","wb","w+","w+b",
+ "a","ab","a+","a+b",
+ "r","r","r","r"} /* last 4 are illegal */ ;
+#endif
+
+ unsigned type ;
+
+ type = (unsigned)(state->Reg[1] & 3L) ;
+ getstring(state,state->Reg[0],buffer) ;
+ if (strcmp(buffer,":tt")==0 && (type == O_RDONLY )) /* opening tty "r" */
+ fptr = stdin ;
+ else if (strcmp(buffer,":tt")==0 && (type == O_WRONLY)) /* opening tty "w" */
+ fptr = stderr ;
+ else
+ {
+ switch (type)
+ {
+ case O_RDONLY:
+ fptr = fopen(buffer,"r") ;
+ break;
+ case O_WRONLY:
+ fptr = fopen(buffer,"w") ;
+ break;
+ case O_RDWR:
+ fptr = fopen(buffer,"rw") ;
+ break;
+ }
+ }
+
+ state->Reg[0] = 0 ;
+ if (fptr != NULL) {
+ for (temp = 0 ; temp < FOPEN_MAX ; temp++)
+ if (OSptr->FileTable[temp] == NULL) {
+ OSptr->FileTable[temp] = fptr ;
+ OSptr->FileFlags[temp] = type & 1 ; /* preserve the binary bit */
+ state->Reg[0] = (ARMword)(temp + 1) ;
+ break ;
+ }
+ if (state->Reg[0] == 0)
+ OSptr->ErrorNo = EMFILE ; /* too many open files */
+ else
+ OSptr->ErrorNo = errno ;
+ }
+ else
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+ }
+
+ case SWI_Close :
+ temp = state->Reg[0] ;
+ if (temp == 0 || temp > FOPEN_MAX || OSptr->FileTable[temp - 1] == 0) {
+ OSptr->ErrorNo = EBADF ;
+ state->Reg[0] = -1L ;
+ return(TRUE) ;
+ }
+ temp-- ;
+ fptr = OSptr->FileTable[temp] ;
+ if (fptr == stdin || fptr == stderr)
+ state->Reg[0] = 0 ;
+ else
+ state->Reg[0] = fclose(fptr) ;
+ OSptr->FileTable[temp] = NULL ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_Write : {
+ unsigned size, upto, type ;
+ char ch ;
+
+ temp = state->Reg[0] ;
+ if (temp == 0 || temp > FOPEN_MAX || OSptr->FileTable[temp - 1] == 0) {
+ OSptr->ErrorNo = EBADF ;
+ state->Reg[0] = -1L ;
+ return(TRUE) ;
+ }
+ temp-- ;
+ fptr = OSptr->FileTable[temp] ;
+ type = OSptr->FileFlags[temp] ;
+ addr = state->Reg[1] ;
+ size = (unsigned)state->Reg[2] ;
+
+ if (type & READOP)
+ fseek(fptr,0L,SEEK_CUR) ;
+ OSptr->FileFlags[temp] = (type & BINARY) | WRITEOP ; ;
+ while (size > 0) {
+ if (size >= BUFFERSIZE)
+ upto = BUFFERSIZE ;
+ else
+ upto = size ;
+ for (cptr = buffer ; (cptr - buffer) < upto ; cptr++) {
+ ch = (char)ARMul_ReadByte(state,(ARMword)addr++) ;
+ *cptr = FIXCRLF(type,ch) ;
+ }
+ temp = fwrite(buffer,1,upto,fptr) ;
+ if (temp < upto) {
+ state->Reg[0] = (ARMword)(size - temp) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+ }
+ size -= upto ;
+ }
+ state->Reg[0] = 0 ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+ }
+
+ case SWI_Read : {
+ unsigned size, upto, type ;
+ char ch ;
+
+ temp = state->Reg[0] ;
+ if (temp == 0 || temp > FOPEN_MAX || OSptr->FileTable[temp - 1] == 0) {
+ OSptr->ErrorNo = EBADF ;
+ state->Reg[0] = -1L ;
+ return(TRUE) ;
+ }
+ temp-- ;
+ fptr = OSptr->FileTable[temp] ;
+ addr = state->Reg[1] ;
+ size = (unsigned)state->Reg[2] ;
+ type = OSptr->FileFlags[temp] ;
+
+ if (type & WRITEOP)
+ fseek(fptr,0L,SEEK_CUR) ;
+ OSptr->FileFlags[temp] = (type & BINARY) | READOP ; ;
+ while (size > 0) {
+ if (isatty_(fptr)) {
+ upto = (size >= BUFFERSIZE)?BUFFERSIZE:size + 1 ;
+ if (fgets(buffer, upto, fptr) != 0)
+ temp = strlen(buffer) ;
+ else
+ temp = 0 ;
+ upto-- ; /* 1 char used for terminating null */
+ }
+ else {
+ upto = (size>=BUFFERSIZE)?BUFFERSIZE:size ;
+ temp = fread(buffer,1,upto,fptr) ;
+ }
+ for (cptr = buffer ; (cptr - buffer) < temp ; cptr++) {
+ ch = *cptr ;
+ ARMul_WriteByte(state,(ARMword)addr++,FIXCRLF(type,ch)) ;
+ }
+ if (temp < upto) {
+ state->Reg[0] = (ARMword)(size - temp) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+ }
+ size -= upto ;
+ }
+ state->Reg[0] = 0 ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+ }
+
+ case SWI_Seek :
+ if (state->Reg[0] == 0 || state->Reg[0] > FOPEN_MAX
+ || OSptr->FileTable[state->Reg[0] - 1] == 0) {
+ OSptr->ErrorNo = EBADF ;
+ state->Reg[0] = -1L ;
+ return(TRUE) ;
+ }
+ fptr = OSptr->FileTable[state->Reg[0] - 1] ;
+ state->Reg[0] = fseek(fptr,(long)state->Reg[1],SEEK_SET) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_Flen :
+ if (state->Reg[0] == 0 || state->Reg[0] > FOPEN_MAX
+ || OSptr->FileTable[state->Reg[0] - 1] == 0) {
+ OSptr->ErrorNo = EBADF ;
+ state->Reg[0] = -1L ;
+ return(TRUE) ;
+ }
+ fptr = OSptr->FileTable[state->Reg[0] - 1] ;
+ addr = (ARMword)ftell(fptr) ;
+ if (fseek(fptr,0L,SEEK_END) < 0)
+ state->Reg[0] = -1 ;
+ else {
+ state->Reg[0] = (ARMword)ftell(fptr) ;
+ (void)fseek(fptr,addr,SEEK_SET) ;
+ }
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_IsTTY :
+ if (state->Reg[0] == 0 || state->Reg[0] > FOPEN_MAX
+ || OSptr->FileTable[state->Reg[0] - 1] == 0) {
+ OSptr->ErrorNo = EBADF ;
+ state->Reg[0] = -1L ;
+ return(TRUE) ;
+ }
+ fptr = OSptr->FileTable[state->Reg[0] - 1] ;
+ state->Reg[0] = isatty_(fptr) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+
+ case SWI_TmpNam :{
+ ARMword size ;
+
+ addr = state->Reg[0] ;
+ temp = state->Reg[1] & 0xff ;
+ size = state->Reg[2] ;
+ if (OSptr->tempnames[temp] == NULL) {
+ if ((OSptr->tempnames[temp] = malloc(L_tmpnam)) == NULL) {
+ state->Reg[0] = 0 ;
+ return(TRUE) ;
+ }
+ (void)tmpnam(OSptr->tempnames[temp]) ;
+ }
+ cptr = OSptr->tempnames[temp] ;
+ if (strlen(cptr) > state->Reg[2])
+ state->Reg[0] = 0 ;
+ else
+ do {
+ ARMul_WriteByte(state,addr++,*cptr) ;
+ } while (*cptr++ != 0) ;
+ OSptr->ErrorNo = errno ;
+ return(TRUE) ;
+ }
+
+ case SWI_InstallHandler:
+ { ARMword handlerp = ADDRSOFHANDLERS + state->Reg[0] * 8;
+ ARMword oldr1 = ARMul_ReadWord(state, handlerp),
+ oldr2 = ARMul_ReadWord(state, handlerp + 4);
+ ARMul_WriteWord(state, handlerp, state->Reg[1]);
+ ARMul_WriteWord(state, handlerp + 4, state->Reg[2]);
+ state->Reg[1] = oldr1;
+ state->Reg[2] = oldr2;
+ return(TRUE);
+ }
+
+ case SWI_GenerateError:
+ ARMul_Abort(state, ARMSWIV) ;
+ if (state->Emulate)
+ ARMul_SetR15(state, ARMul_ReadWord(state, ADDRSOFTVECTORS + ARMErrorV));
+ return(TRUE);
+
+/* SWI's 0x9x unwind the state of the CPU after an abort of type x */
+
+ case 0x90: /* Branch through zero */
+ { ARMword oldpsr = ARMul_GetCPSR(state) ;
+ ARMul_SetCPSR(state, (oldpsr & 0xffffffc0) | 0x13) ;
+ ARMul_SetSPSR(state, SVC32MODE, oldpsr) ;
+ state->Reg[14] = 0;
+ goto TidyCommon;
+ }
+
+ case 0x98: /* Error */
+ { ARMword errorp = state->Reg[0],
+ regp = state->Reg[1];
+ unsigned i;
+ ARMword errorpsr = ARMul_ReadWord(state, regp + 16*4);
+ for (i = 0; i < 15; i++)
+ ARMul_SetReg(state,errorpsr,i,ARMul_ReadWord(state, regp + i*4L)) ;
+ state->Reg[14] = ARMul_ReadWord(state, regp + 15*4L);
+ state->Reg[10] = errorp;
+ ARMul_SetSPSR(state,state->Mode,errorpsr) ;
+ OSptr->ErrorP = errorp;
+ goto TidyCommon;
+ }
+
+ case 0x94: /* Data abort */
+ { ARMword addr = state->Reg[14] - 8;
+ ARMword cpsr = ARMul_GetCPSR(state) ;
+ if (ARM26BITMODE)
+ addr = addr & 0x3fffffc ;
+ ARMul_SetCPSR(state,ARMul_GetSPSR(state,cpsr)) ;
+ UnwindDataAbort(state, addr);
+ if (addr >= FPESTART && addr < FPEEND) { /* in the FPE */
+ ARMword sp, spsr ;
+ unsigned i ;
+
+ sp = state->Reg[13] ;
+ state->Reg[13] += 64 ; /* fix the aborting mode sp */
+ state->Reg[14] = ARMul_ReadWord(state,sp + 60) ; /* and its lr */
+ spsr = ARMul_GetSPSR(state,state->Mode) ;
+ state->Mode = ARMul_SwitchMode(state, state->Mode, spsr);
+ for (i = 0 ; i < 15 ; i++) {
+ ARMul_SetReg(state,spsr,i,ARMul_ReadWord(state,sp)) ;
+ sp += 4 ;
+ }
+ ARMul_SetCPSR(state,cpsr) ;
+ state->Reg[14] = ARMul_ReadWord(state,sp) + 4 ; /* botch it */
+ ARMul_SetSPSR(state,state->Mode,spsr) ;
+ }
+ else
+ ARMul_SetCPSR(state,cpsr) ;
+
+ /* and fall through to correct r14 */
+ }
+ case 0x95: /* Address Exception */
+ state->Reg[14] -= 4;
+ case 0x91: /* Undefined instruction */
+ case 0x92: /* SWI */
+ case 0x93: /* Prefetch abort */
+ case 0x96: /* IRQ */
+ case 0x97: /* FIQ */
+ state->Reg[14] -= 4;
+ TidyCommon:
+ if (state->VectorCatch & (1 << (number - 0x90))) {
+ ARMul_SetR15(state, state->Reg[14] + 8) ; /* the 8 is the pipelining the the RDI will undo */
+ ARMul_SetCPSR(state,ARMul_GetSPSR(state,ARMul_GetCPSR(state))) ;
+ if (number == 0x90)
+ state->EndCondition = 10 ; /* Branch through Zero Error */
+ else
+ state->EndCondition = (unsigned)number - 0x8f;
+ state->Emulate = FALSE ;
+ }
+ else {
+ ARMword sp = state->Reg[13];
+ ARMul_WriteWord(state, sp - 4, state->Reg[14]);
+ ARMul_WriteWord(state, sp - 8, state->Reg[12]);
+ ARMul_WriteWord(state, sp - 12, state->Reg[11]);
+ ARMul_WriteWord(state, sp - 16, state->Reg[10]);
+ state->Reg[13] = sp - 16;
+ state->Reg[11] = ADDRSOFHANDLERS + 8 * (number - 0x90);
+ }
+ return(TRUE);
+
+/* SWI's 0x8x pass an abort of type x to the debugger if a handler returns */
+
+ case 0x80: case 0x81: case 0x82: case 0x83:
+ case 0x84: case 0x85: case 0x86: case 0x87: case 0x88:
+ { ARMword sp = state->Reg[13];
+ state->Reg[10] = ARMul_ReadWord(state, sp);
+ state->Reg[11] = ARMul_ReadWord(state, sp + 4);
+ state->Reg[12] = ARMul_ReadWord(state, sp + 8);
+ state->Reg[14] = ARMul_ReadWord(state, sp + 12);
+ state->Reg[13] = sp + 16;
+ ARMul_SetR15(state, state->Reg[14] + 8) ; /* the 8 is the pipelining the the RDI will undo */
+ ARMul_SetCPSR(state,ARMul_GetSPSR(state,ARMul_GetCPSR(state))) ;
+ if (number == 0x80)
+ state->EndCondition = 10 ; /* Branch through Zero Error */
+ else
+ state->EndCondition = (unsigned)number - 0x7f;
+ state->Emulate = FALSE ;
+ return(TRUE);
+ }
+
+ default :
+ state->Emulate = FALSE ;
+ return(FALSE) ;
+ }
+#endif
+#endif
+ }
+#endif
+
+#ifndef NOOS
+#ifndef ASIM
+
+/***************************************************************************\
+* The emulator calls this routine when an Exception occurs. The second *
+* parameter is the address of the relevant exception vector. Returning *
+* FALSE from this routine causes the trap to be taken, TRUE causes it to *
+* be ignored (so set state->Emulate to FALSE!). *
+\***************************************************************************/
+
+unsigned ARMul_OSException(ARMul_State *state, ARMword vector, ARMword pc)
+{ /* don't use this here */
+ return(FALSE) ;
+}
+
+#endif
+
+/***************************************************************************\
+* Unwind a data abort *
+\***************************************************************************/
+
+static void UnwindDataAbort(ARMul_State *state, ARMword addr)
+{
+ ARMword instr = ARMul_ReadWord(state, addr);
+ ARMword rn = BITS(16, 19);
+ ARMword itype = BITS(24, 27);
+ ARMword offset;
+ if (rn == 15) return;
+ if (itype == 8 || itype == 9) {
+ /* LDM or STM */
+ unsigned long regs = BITS(0, 15);
+ offset = 0;
+ if (!BIT(21)) return; /* no wb */
+ for (; regs != 0; offset++)
+ regs ^= (regs & -regs);
+ if (offset == 0) offset = 16;
+ } else if (itype == 12 || /* post-indexed CPDT */
+ (itype == 13 && BIT(21))) { /* pre_indexed CPDT with WB */
+ offset = BITS(0, 7);
+ } else
+ return;
+
+ if (BIT(23))
+ state->Reg[rn] -= offset * 4;
+ else
+ state->Reg[rn] += offset * 4;
+}
+
+/***************************************************************************\
+* Copy a string from the debuggee's memory to the host's *
+\***************************************************************************/
+
+static void getstring(ARMul_State *state, ARMword from, char *to)
+{do {
+ *to = (char)ARMul_ReadByte(state,from++) ;
+ } while (*to++ != '\0') ;
+ }
+
+#endif /* NOOS */