# SPIM runtime system for Espresso-compiler generated code # Has different main than default one # Has some other functions defined too. # Keeps all the exception-handling code of default spim # SPIM S20 MIPS simulator. # The default exception handler for spim. # # Copyright (C) 1990-2004 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: $ # Define the exception handling code. This must go first! .kdata __m1_: .asciiz " Exception " __m2_: .asciiz " occurred and ignored\n" __e0_: .asciiz " [Interrupt] " __e1_: .asciiz " [TLB]" __e2_: .asciiz " [TLB]" __e3_: .asciiz " [TLB]" __e4_: .asciiz " [Address error in inst/data fetch] " __e5_: .asciiz " [Address error in store] " __e6_: .asciiz " [Bad instruction address] " __e7_: .asciiz " [Bad data address] " __e8_: .asciiz " [Error in syscall] " __e9_: .asciiz " [Breakpoint] " __e10_: .asciiz " [Reserved instruction] " __e11_: .asciiz "" __e12_: .asciiz " [Arithmetic overflow] " __e13_: .asciiz " [Trap] " __e14_: .asciiz "" __e15_: .asciiz " [Floating point] " __e16_: .asciiz "" __e17_: .asciiz "" __e18_: .asciiz " [Coproc 2]" __e19_: .asciiz "" __e20_: .asciiz "" __e21_: .asciiz "" __e22_: .asciiz " [MDMX]" __e23_: .asciiz " [Watch]" __e24_: .asciiz " [Machine check]" __e25_: .asciiz "" __e26_: .asciiz "" __e27_: .asciiz "" __e28_: .asciiz "" __e29_: .asciiz "" __e30_: .asciiz " [Cache]" __e31_: .asciiz "" __excp: .word __e0_, __e1_, __e2_, __e3_, __e4_, __e5_, __e6_, __e7_, __e8_, __e9_ .word __e10_, __e11_, __e12_, __e13_, __e14_, __e15_, __e16_, __e17_, __e18_, .word __e19_, __e20_, __e21_, __e22_, __e23_, __e24_, __e25_, __e26_, __e27_, .word __e28_, __e29_, __e30_, __e31_ s1: .word 0 s2: .word 0 # This is the exception handler code that the processor runs when # an exception occurs. It only prints some information about the # exception, but can server as a model of how to write a handler. # # Because we are running in the kernel, we can use $k0/$k1 without # saving their old values. # This is the exception vector address for MIPS-1 (R2000): # .ktext 0x80000080 # This is the exception vector address for MIPS32: .ktext 0x80000180 # Select the appropriate one for the mode in which SPIM is compiled. .set noat move $k1 $at # Save $at .set at sw $v0 s1 # Not re-entrent and we can't trust $sp sw $a0 s2 # But, we need to use these registers mfc0 $k0 $13 # Cause register srl $a0 $k0 2 # Extract ExcCode Field andi $a0 $a0 0xf # Print information about exception. # li $v0 4 # syscall 4 (print_str) la $a0 __m1_ syscall li $v0 1 # syscall 1 (print_int) srl $a0 $k0 2 # Extract ExcCode Field andi $a0 $a0 0xf syscall li $v0 4 # syscall 4 (print_str) andi $a0 $k0 0x3c lw $a0 __excp($a0) nop syscall bne $k0 0x18 ok_pc # Bad PC exception requires special checks nop mfc0 $a0 $14 # EPC andi $a0 $a0 0x3 # Is EPC word-aligned? beq $a0 0 ok_pc nop li $v0 10 # Exit on really bad PC syscall ok_pc: li $v0 4 # syscall 4 (print_str) la $a0 __m2_ syscall srl $a0 $k0 2 # Extract ExcCode Field andi $a0 $a0 0xf bne $a0 0 ret # 0 means exception was an interrupt nop # Interrupt-specific code goes here! # Don't skip instruction at EPC since it has not executed. ret: # Return from (non-interrupt) exception. Skip offending instruction # at EPC to avoid infinite loop. # mfc0 $k0 $14 # Bump EPC register addiu $k0 $k0 4 # Skip faulting instruction # (Need to handle delayed branch case here) mtc0 $k0 $14 # Restore registers and reset procesor state # .set noat move $at $k1 # Restore $at .set at lw $v0 s1 # Restore other registers lw $a0 s2 mtc0 $0 $13 # Clear Cause register mfc0 $k0 $12 # Set Status register ori $k0 0x1 # Interrupts enabled mtc0 $k0 $12 # Return from exception on MIPS32: eret # Return sequence for MIPS-I (R2000): # rfe # Return from exception handler # Should be in jr's delay slot # jr $k0 # nop ######## BEGINNING OF ESPRESSO-SPECIFIC CODE # Strings used in runtime system .data _newline: .asciiz "\n" _null_call_msg: .asciiz "Error: Attempted method call on null pointer at line number " _exit_msg: .asciiz "Expresso program successfully executed.\n" # Startup code. Invoke the routine "main" with no arguments # .text .globl __start __start: lw $a0 0($sp) # argc addiu $a1 $sp 4 # argv addiu $a2 $a1 4 # envp sll $v0 $a0 2 addu $a2 $a2 $v0 jal main nop li $v0, 4 # code "4" is print_string function la $a0, _exit_msg # load address of _exit_msg string syscall # call print_string li $v0 10 syscall # syscall 10 (exit) .globl __eoth __eoth: # _println # Prints a newline (takes no args) # does not write $a0 # writes scratch register $v0 .globl _println _println: addiu $sp $sp -4 # push $a0 to stack sw $a0 4($sp) li $v0, 4 # code "4" is print_string function la $a0, _newline # load address of newline string syscall # call print_string lw $a0 4($sp) # restore $a0 addiu $sp $sp 4 # pop jr $ra # _int_println gets its arg in $a0 # does not write $a0 # writes scratch register $v0 .globl _int_println _int_println: addiu $sp $sp -4 # push $a0 to stack sw $a0 4($sp) li $v0, 1 # code "1" is print_int function syscall # call print_int on number passed in $a0 li $v0, 4 # code "4" is print_string function la $a0, _newline # load address of newline string syscall # call print_string lw $a0 4($sp) # restore $a0 addiu $sp $sp 4 # pop jr $ra # return # _walloc # allocate n WORDS on the heap # inits all words to zero # n is passed in $a0 # pointer to newly allocated memory is returned in $a0 # writes scratch register $v0 .globl _walloc _walloc: sll $a0 $a0 2 # $a0*4 to convert to value in bytes li $v0 9 # code "9" is sbrk syscall move $a0 $v0 # put result in $a0 jr $ra # return # _null_abort # For use when a method call is attempted on a null object # Prints line number and error message and aborts program # Parameter: $a0 is the source code line number of the method call # .globl _null_abort _null_abort: move $t0 $a0 # save line number li $v0, 4 # code "4" is print_string function la $a0, _null_call_msg # print error message syscall # call print_string move $a0 $t0 # put line number in $a0 to pass to print jal _int_println li $v0, 10 # code "10" is exit function syscall # abort program