###############################################################################
# Name:		Kernel code for a spin-wait programming assignment
#
# Description:	The purpose of this program is to provide an understanding of
#		spin-waiting for I/O.
#
# Class:	CS354
#
# Written by:	YOUR NAME???
# Section :	???
#
# Date:		WHAT'S THE DATE???
###############################################################################


# assign fixed addresses to labels
    .eq KeyboardData    0xbfff0000
    .eq	KeyboardStatus  0xbfff0004
    .eq	DisplayData     0xbfff0008
    .eq	DisplayStatus   0xbfff000c
    .eq	KeyboardData2   0xbfff0010
    .eq	KeyboardStatus2 0xbfff0014
    .eq	DisplayData2    0xbfff0018
    .eq	DisplayStatus2  0xbfff001c
    .eq ClockStatus     0xbfff0020

    .kdata


Tmpat: .word 0                  # temporary storage $at

     #
     # other temporary register storage would be setup here...
     #


    .ktext

    .space 0x80                 # skip space so kernel starts at 0x80000080

Service:
                                # save registers

    .set noat                   # turn off assembler warnings for $at
     move $k1, $at              # move $at
    .set at                     # turn on assembler warnings for $at
     sw	$k1, Tmpat              # save $at register

     #
     # other registers would be saved here...
     #

     mfc0 $k0, $13              # get the Cause register
     and  $k0, 0x3c             # mask out the ExcCode bits in the Cause register
     beq  $k0, 0x20, HandleSys  # is it a syscall exception?
                                # if the exception is some other type
                                # do nothing and return to the user
     #
     # other exception tests would go here...
     #

    mfc0	$5, $12			# Get the Status_Reg
    and		$5, 0xffff00fa		# Turn off all interrupts
    ori		$5, $5, 0x00000008	# Return in user mode
    mtc0	$5, $12			# Set the Status_Reg

Return:
                                # restore registers

     #
     # other registers would be restored here...
     #

    .set noat                   # turn off assembler warnings for $at
     lw	$at, Tmpat              # restore $at
    .set at                     # turn on assembler warnings for $at

     mfc0 $k0, $14              # get the EPC register
     rfe                        # return from exception
     jr $k0

HandleSys:
                                # syscall

     mfc0 $k1, $14              # get the EPC register
     add  $k1, 4                # increment PC past syscall instruction
     mtc0 $k1, $14              # set the EPC register

     beq  $2, 10, Exit          # is it a done syscall?

     #
     # other tests for syscalls would go here...
     #

     j     Return               # unknown syscall, do nothing and return

Exit:
                                # exit routine

     li $2, 13                  # special exit syscall
     syscall                    # this syscall never returns
     #
     # other syscalls could be added here...
     #

    .text
    .globl __start

     #
     # the user program will be added here...
     #

