# 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 # Standard startup code. Invoke the routine "main" with arguments: # main(argc, argv, envp) # .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 10 syscall # syscall 10 (exit) .globl __eoth __eoth: