/* SPIM S20 MIPS simulator. Execute SPIM syscalls, both in simulator and bare mode. Execute MIPS syscalls in bare mode, when running on MIPS systems. Copyright (C) 1990-2004 by James Larus (larus@cs.wisc.edu). ALL RIGHTS RESERVED. SPIM is distributed under the following conditions: You may make copies of SPIM for your own use and modify those copies. All copies of SPIM must retain my name and copyright notice. You may not sell SPIM or distributed SPIM in conjunction with a commerical product or service without the expressed written consent of James Larus. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* $Header: /Software/SPIM/src/syscall.c 4 3/27/04 4:50p Larus $ */ #ifndef WIN32 #include #endif #include #include #include #include #include #ifdef WIN32 #include #endif #include "spim.h" #include "string-stream.h" #include "inst.h" #include "reg.h" #include "mem.h" #include "sym-tbl.h" #include "syscall.h" /* Decides which syscall to execute or simulate. Returns zero upon exit syscall and non-zero to continue execution. */ int do_syscall () { /* Syscalls for the source-language version of SPIM. These are easier to use than the real syscall and are portable to non-MIPS operating systems. */ switch (R[REG_V0]) { case PRINT_INT_SYSCALL: write_output (console_out, "%d", R[REG_A0]); break; case PRINT_FLOAT_SYSCALL: { float val = FPR_S (REG_FA0); write_output (console_out, "%.8f", val); break; } case PRINT_DOUBLE_SYSCALL: write_output (console_out, "%.18g", FPR[REG_FA0 / 2]); break; case PRINT_STRING_SYSCALL: write_output (console_out, "%s", mem_reference (R[REG_A0])); break; case READ_INT_SYSCALL: { static char str [256]; read_input (str, 256); R[REG_RES] = atol (str); break; } case READ_FLOAT_SYSCALL: { static char str [256]; read_input (str, 256); FPR_S (REG_FRES) = (float) atof (str); break; } case READ_DOUBLE_SYSCALL: { static char str [256]; read_input (str, 256); FPR [REG_FRES] = atof (str); break; } case READ_STRING_SYSCALL: { read_input ( (char *) mem_reference (R[REG_A0]), R[REG_A1]); data_modified = 1; break; } case SBRK_SYSCALL: { mem_addr x = data_top; expand_data (R[REG_A0]); R[REG_RES] = x; data_modified = 1; break; } case PRINT_CHARACTER_SYSCALL: write_output (console_out, "%c", R[REG_A0]); break; case READ_CHARACTER_SYSCALL: { static char str [2]; read_input (str, 2); if (*str == '\0') *str = '\n'; /* makes xspim = spim */ R[REG_RES] = (long) str[0]; break; } case EXIT_SYSCALL: spim_return_value = 0; return (0); case EXIT2_SYSCALL: spim_return_value = R[REG_A0]; /* value passed to spim's exit() call */ return (0); case OPEN_SYSCALL: { #ifdef WIN32 R[REG_RES] = _open(mem_reference (R[REG_A0]), R[REG_A1], R[REG_A2]); #else R[REG_RES] = open(mem_reference (R[REG_A0]), R[REG_A1], R[REG_A2]); #endif break; } case READ_SYSCALL: { /* Test if address is valid */ (void)mem_reference (R[REG_A1] + R[REG_A2] - 1); #ifdef WIN32 R[REG_RES] = _read(R[REG_A0], mem_reference (R[REG_A1]), R[REG_A2]); #else R[REG_RES] = read(R[REG_A0], mem_reference (R[REG_A1]), R[REG_A2]); #endif data_modified = 1; break; } case WRITE_SYSCALL: { /* Test if address is valid */ (void)mem_reference (R[REG_A1] + R[REG_A2] - 1); #ifdef WIN32 R[REG_RES] = _write(R[REG_A0], mem_reference (R[REG_A1]), R[REG_A2]); #else R[REG_RES] = write(R[REG_A0], mem_reference (R[REG_A1]), R[REG_A2]); #endif break; } case CLOSE_SYSCALL: { #ifdef WIN32 R[REG_RES] = _close(R[REG_A0]); #else R[REG_RES] = close(R[REG_A0]); #endif break; } default: run_error ("Unknown system call: %d\n", R[REG_V0]); break; } return (1); } void handle_exception () { if (!quiet && CP0_ExCode != ExcCode_Int) error ("Exception occurred at PC=0x%08x\n", CP0_EPC); exception_occurred = 0; PC = EXCEPTION_ADDR; switch (CP0_ExCode) { case ExcCode_Int: break; case ExcCode_AdEL: if (!quiet) error (" Unaligned address in inst/data fetch: 0x%08x\n", CP0_BadVAddr); break; case ExcCode_AdES: if (!quiet) error (" Unaligned address in store: 0x%08x\n", CP0_BadVAddr); break; case ExcCode_IBE: if (!quiet) error (" Bad address in text read: 0x%08x\n", CP0_BadVAddr); break; case ExcCode_DBE: if (!quiet) error (" Bad address in data/stack read: 0x%08x\n", CP0_BadVAddr); break; case ExcCode_Sys: if (!quiet) error (" Error in syscall\n"); break; case ExcCode_Bp: exception_occurred = 0; return; case ExcCode_RI: if (!quiet) error (" Reserved instruction execution\n"); break; case ExcCode_CpU: if (!quiet) error (" Coprocessor unuable\n"); break; case ExcCode_Ov: if (!quiet) error (" Arithmetic overflow\n"); break; case ExcCode_Tr: if (!quiet) error (" Trap\n"); break; case ExcCode_FPE: if (!quiet) error (" Floating point\n"); break; default: if (!quiet) error ("Unknown exception: %d\n", CP0_ExCode); break; } }