# File: /usr/local/spim//exceptions.s
# For use with the new version of 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
# 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: