beq $0 $0 __start add $0 $0 $0 lui $k1,0x9000 # For the purposes of our exception ori $k1,$k1,0x2000 # handler we are storing all data in # the kernel's data segment between # 0x90001000 and 0x90002000. addi $k1,$k1,-32 sw $at,28($k1) # 0x90001ffc sw $t6,24($k1) # 0x90001ff8 sw $t5,20($k1) # 0x90001ff4 sw $t4,16($k1) # 0x90001ff0 sw $t3,12($k1) # 0x90001fec sw $t2,8($k1) # 0x90001fe8 sw $t1,4($k1) # 0x90001fe4 sw $t0,0($k1) # 0x90001fe0 add $t6 $0 $0 mfc0 $k0,$13 # Move cause to $k0. andi $k0,$k0,0x3c # We only use the ExcCode. addi $k0,$k0,jumptable # $k0 = cause + jumptable jr $k0 # jumptable: # # $k0 = cause + jumptable. # if cause == 0 then jr $k0 jumps to beq $0,$0,intrp, # else if cause == 8 then jr $k0 jumps to beq $0,$0,syscl, # else jr $k0 jumps to beq $0,$0,otherexcptn. jumptable: beq $0,$0,intrp # 0 beq $0,$0,otherexcptn # 1 beq $0,$0,otherexcptn # 2 beq $0,$0,otherexcptn # 3 beq $0,$0,otherexcptn # 4 beq $0,$0,otherexcptn # 5 beq $0,$0,otherexcptn # 6 beq $0,$0,otherexcptn # 7 beq $0,$0,syscl # 8 beq $0,$0,otherexcptn # 9 beq $0,$0,otherexcptn # 10 beq $0,$0,otherexcptn # 11 beq $0,$0,otherexcptn # 12 beq $0,$0,otherexcptn # 13 beq $0,$0,otherexcptn # 14 beq $0,$0,otherexcptn # 15 # intrp: # # Handle receiver and transmitter interrupts. intrp: # rcvintrp: # # First handle receiver interrupts. The handler checks the receiver ready bit. # If ready is 1, the handler takes a character out of the receiver data # register (memory mapped io) and stores the character into the receiver # buffer. If the buffer is full then the character is dropped. rcvintrp: lui $t0,0xffff # Get base address of device. lw $t3,0($t0) # Get status word for input. andi $t3,$t3,1 # Mask ready bit. beq $t3,$0,xmtintrp # If no char then all done, lb $t4,4($t0) # else get the char. lui $t2, 0x9000 #load rcvInput into $t2 ori $t2,$t2,0x0298 lw $t2,0($t2) lui $t3, 0x9000 #load rcvOutput into $t3 ori $t3,$t3,0x029c lw $t3,0($t3) addi $t1,$t2,1 andi $t1,$t1,15 beq $t1,$t3,xmtintrp #bufferfull # lui $t1,0x9000 # la $t1,rcvRing ori $t1,$t1,0x0288 add $t1,$t1,$t2 sb $t4,0($t1) # Otherwise, there is space in buffer, # so store character. addi $t2,$t2,1 andi $t2,$t2,15 lui $t1, 0x9000 #load the address of rcvInput into $t1 ori $t1,$t1,0x0298 sw $t2, 0($t1) #bufferfull: lui $t5,0xffff # sw $0,0($t5) # xmtintrp: # # Next handle transmitter interrupts. The handler checks the transmitter ready # bit. If ready is 1 and the transmitter buffer is not empty, the handler # takes a character out of the transmitter buffer and stores the character # into the transmitter data register (memory mapped io). #version1 xmtintrp: lui $t0,0xffff lui $t2, 0x9000 #load xmtInput into $t2 ori $t2,$t2,0x0278 lw $t2,0($t2) lui $t3, 0x9000 #load xmtOutput into $t3 ori $t3,$t3,0x027c lw $t3,0($t3) # lw $t3,0($t2) # Is buffer empty? bne $t3,$t2,xmtnotempty # bne $t3,$0,xmtnotempty # If so sw $0,8($t0) # disable interrupts in the transmitter beq $0,$0,intrpdone # and return from handler #version2.1 xmtnotempty: lw $t3,8($t0) # Get status word for output. andi $t3,$t3,1 # Mask out all but ready bit. beq $t3,$0,intrpdone # Return from handler if not ready. # lui $t1,0x9000 # la $t1,xmtBuf # ori $t1,$t1,0x0280 lui $t1,0x9000 # la $t1,xmtRing ori $t1,$t1,0x0258 lui $t2, 0x9000 # load the address of xmtOutput into $t2 ori $t2,$t2,0x027c lw $t3,0($t2) # load xmtOutput into $t3 add $t1,$t1,$t3 lb $t3,0($t1) # Get the char from the buffer. sw $t3,12($t0) # Output character to terminal. # sw $0,0($t2) # Update xmtFull. lui $t2, 0x9000 # load the address of xmtOutput into $t2 ori $t2,$t2,0x027c lw $t3,0($t2) # load xmtOutput into $t3 addi $t3,$t3,1 andi $t3,$t3,31 # lui $t2, 0x9000 # load the address of xmtOutput into $t2 # ori $t2,$t2,0x027c sw $t3,0($t2) intrpdone: mfc0 $k0,$14 # Read the exception program counter. beq $0,$0,cleanup # Return from handler. # syscl: # # Handle readchar and print syscalls. syscl: addi $t0,$0,4 # If $v0 == 4, then handle print beq $v0,$t0,kprint # syscall. addi $t0,$0,12 # If $v0 == 12, then handle readchar beq $v0,$t0,kreadchar # syscall. beq $0,$0,syscldone # Unknown syscall, so return. # kprint: # # Takes each character of the string that $a0 points to and stores it into # the transmitter buffer. If the buffer is full, then the handler returns with # $a0 pointing to the first unhandled character in the string. kprint: addi $t6 $t6 1 andi $t6 $t6 1 beq $t6 $0 skip lb $t4,0($a0) # Fetch next character to store beq $t4,$0,syscldone # in buffer, check for end of string. # lui $t2,0x9000 # la $t2,xmtFull # ori $t2,$t2,0x0284 lui $t2, 0x9000 # load xmtInput into $t2 ori $t2,$t2,0x0278 lw $t2,0($t2) lui $t3, 0x9000 # load xmtOutput into $t3 ori $t3,$t3,0x027c lw $t3,0($t3) addi $t2,$t2,2 andi $t2,$t2,31 beq $t2,$t3,syscldone lui $t1,0x9000 # la $t1,xmtRing ori $t1,$t1,0x0258 lui $t2, 0x9000 # load xmtInput into $t2 ori $t2,$t2,0x0278 lw $t2,0($t2) add $t1,$t1,$t2 sb $t4,0($t1) # Otherwise, there is space in buffer, # so store character. # addi $t4 $0 32 # sb $t4,0($t1) # addi $t3,$0,1 # sw $t3,0($t2) # Update xmtFull. lui $t3, 0x9000 # load the address of xmtInput into $t3 ori $t3,$t3,0x0278 # lw $t2, 0($t3) addi $t2,$t2,1 andi $t2,$t2,31 sw $t2,0($t3) lui $t0,0xffff # Make sure interrupts are enabled addi $t3,$0,2 # in the transmitter. sw $t3,8($t0) skip: addi $a0,$a0,1 beq $0,$0,kprint # Go back for the next character. # kreadchar: # # If the receiver buffer is empty, then the handler returns with $v0 set to # zero. Otherwise, a character is read from the receiver buffer and returned # in $v0. kreadchar: # lui $t2,0x9000 # la $t2,rcvFull # ori $t2,$t2,0x02a4 # lw $t3,0($t2) # Is buffer empty? lui $t2, 0x9000 #load rcvInput into $t2 ori $t2,$t2,0x0298 lw $t2,0($t2) lui $t3, 0x9000 #load rcvOutput into $t3 ori $t3,$t3,0x029c lw $t3,0($t3) bne $t2,$t3,rcvnotempty # bne $t3,$0,rcvnotempty # If so, add $v0,$0,$0 # set $v0 set to zero. beq $0,$0,syscldone # and return from handler. rcvnotempty: # lui $t1,0x9000 # la $t1,rcvBuf # ori $t1,$t1,0x02a0 lui $t1,0x9000 ori $t1,$t1,0x0288 add $t1,$t1,$t3 lb $v0,0($t1) # Otherwise, fetch the character. addi $t3,$t3,1 andi $t3,$t3,15 lui $t2, 0x9000 #load rcvOutput into $t2 ori $t2,$t2,0x029c sw $t3,0($t2) # lui $t5, 0xffff # addiu $t2,$0,2 # sw $t2, 0($t4) # sw $0,0($t2) # Update rcvFull. # beq $0,$0,syscldone syscldone: otherexcptn: mfc0 $k0,$14 # Read the exception program counter. addi $k0,$k0,4 cleanup: lui $k1,0x9000 # Restore registers. ori $k1,$k1,0x2000 addi $k1,$k1,-32 lw $t0,0($k1) lw $t1,4($k1) lw $t2,8($k1) lw $t3,12($k1) lw $t4,16($k1) lw $t5,20($k1) lw $t6,24($k1) # .set noat lw $at,28($k1) # .set at rfe # Restore status bits on the way out. jr $k0 # Jump to $k0 which was set to EPC+4. __start: lui $t0,0xffff # Enable receiver interrupts. addi $t1,$0,2 sw $t1,0($t0) loop: readchar: addi $v0,$0,12 # readchar syscall syscall beq $v0,$0,readchar # if the result of the syscall is # zero, then try again. addi $s0, $0, 0xff beq $s0, $v0, fin lui $a0,0x1001 # la $a0,string ori $a0,$a0,0x0000 sb $v0, 20($a0) # Store char 'x' into output string. print: addi $v0,$0,4 # print syscall syscall lb $t0,0($a0) bne $t0,$0,print # if the result of the syscall is # not zero, then try again. beq $0,$0,loop fin: # [add this line] halt # [add this line]