# exceptions.s: # # This file contains the exception handler code for the I/O Lab. ###################################################################### # EXCEPTION HANDLER ###################################################################### .ktext 0x80000180 # Forces interrupt routine below to be # located at address 0x80000180. intrp: addiu $sp,$sp,-32 # Save registers. .set noat # Tell assembler to stop using $at... sw $at,28($sp) # so we can use it. .set at # Now give back $at to the assembler. # Save registers. Remember, this is an interrupt routine # so it has to save the $t registers. sw $ra,24($sp) sw $a0,20($sp) sw $t4,16($sp) sw $t3,12($sp) sw $t2,8($sp) sw $t1,4($sp) sw $t0,0($sp) li $a0,'J' jal trace # First attend to input lui $t1,0xffff # get base address of device lw $t3,0($t1) # get status word for input andi $t3,$t3,0x1 # mask ready bit beq $t3,$0,indone # if no char, all done li $a0,'R' jal trace lb $t3,4($t1) # else get the char lw $t0,rcvInput # Fetch current input index, and # compute new input index after we addiu $t1,$t0,1 # store the next character. andi $t1,$t1,15 # Wrap around from 16 back to 0. lw $t2,rcvOutput # Is buffer full? (i.e. is rcvInput # just before rcvOutput?) bne $t2,$t1,insertChar # If not, add new char to buffer. lw $t2,dropCount # If so, tally dropped char. addi $t2,$t2,1 sw $t2,dropCount j indone insertChar: la $t4,rcvBuf add $t4,$t4,$t0 sb $t3,0($t4) # Space in buffer: store character. sw $t1,rcvInput # Update index. # Next attend to output. indone: li $a0,'X' jal trace lw $t0,nextOut # Is buffer empty? lw $t1,nextIn # I.e. is nextOut equal to nextIn? bne $t0,$t1,notEmpty ### LAB: Exercise lui $t3,0xffff # $t3 points to base of I/O register sw $0,8($t3) # If so, disable terminal interrupts. # What happens if we don't disable # interrupts? j intDone .globl notEmpty notEmpty: li $a0,'I' jal trace lui $t1,0xffff # get base address of device registers. lw $t2,8($t1) # Get status word for output andi $t2,$t2,0x1 # mask out all but ready bit beq $t2,$0,intDone # return if not ready la $t2,buffer # get buffer base address addu $t3,$t2,$t0 # add offset lb $t2,0($t3) # get the char from the buffer sb $t2,12($t1) # Output character to term addiu $t1,$t0,1 # increment index andi $t1,$t1,31 # Wrap around from 32 back to 0. sw $t1,nextOut .globl intDone intDone: ## Clear Cause register mfc0 $t0,$13 # get Cause register, then clear it mtc0 $0, $13 ## restore registers lw $t0,0($sp) lw $t1,4($sp) lw $t2,8($sp) lw $t3,12($sp) lw $t4,16($sp) lw $a0,20($sp) lw $ra,24($sp) .set noat lw $at,28($sp) .set at addiu $sp,$sp,32 eret # Make note of the execution of the various i/o handling routines # by storing characters in the circular array named callSeq. .globl trace trace: addiu $sp,$sp,-8 sw $s0,0($sp) sw $s1,4($sp) la $s0,callSeq lw $s1,callSeqIndex add $s0,$s0,$s1 sb $a0,0($s0) addi $s1,$s1,1 andi $s1,$s1,31 sw $s1,callSeqIndex lw $s1,4($sp) lw $s0,0($sp) addiu $sp,$sp,8 jr $ra # Standard startup code. Invoke the routine "main" with arguments: # main(argc, argv, envp) # .ktext .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: .kdata .globl dropCount .globl callSeq .globl callSeqIndex dropCount: .word 0 callSeq: .space 32 callSeqIndex: .word 0