Assignment 11 Solution
#----------------------------------------------------------------------
# Kernel code
# Please do not modify this part
# kernel file for assignment 11
# Please modify the code only where you are supposed to do. The parts
# where you are not allowed to do so, will be specified by "Kernel code"
# and "Please do not modify this part". Other parts of the code can
# be modified by you.
# The ".eq" instruction is used to assign a fixed
# address to a label. So "lw $5, KeyboardData2" loads
# a word from memory at address 0xbff0010 into register
# number 5.
# assign fixed addresses to labels
# You will load and store your I/O information through these labels
.eq KeyboardData 0xbfff0000 # the communication channel to
# input device 1
.eq KeyboardStatus 0xbfff0004 # the status of input device 1
.eq DisplayData 0xbfff0008 # the communication channel to
# output device 1
.eq DisplayStatus 0xbfff000c # the status of output device 1
.eq KeyboardData2 0xbfff0010 # the communication channel to
# input device 2
.eq KeyboardStatus2 0xbfff0014 # the status of input device 2
.eq DisplayData2 0xbfff0018 # the communication channel to
# output device 2
.eq DisplayStatus2 0xbfff001c # the status of output device 2
.eq ClockStatus 0xbfff0020 #this will be used in assignment 12
.kdata
Tmpat: .word 0 # temporary storage $at
#-----------------------------------------------------------------------
#
# other temporary register storage would be setup here...
#
tmpr2: .word 0 # Temporary storage for register 2
tmpr4: .word 0 # Temporary storage for register 4
tmpr5: .word 0 # Temporary storage for register 5
tmpr6: .word 0 # Temporary storage for register 6
tmpr7: .word 0 # Temporary storage for register 7
tmpr31: .word 0 # Temporary storage for register 31
#-----------------------------------------------------------------------
# Kernel code
# Please do not modify this part
.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...
#
sw $2, tmpr2
sw $4, tmpr4
sw $5, tmpr5
sw $6, tmpr6
sw $7, tmpr7
sw $31, tmpr31
#-----------------------------------------------------------------------
# Kernel code
# Please do not modify this part
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...
#
#----------------------------------------------------------------------
# Kernel code
# Please do not modify this part
mfc0 $5, $12 # Get the Status_Reg
and $5, 0xffff00fa # Turn off all interrupts
mtc0 $5, $12 # Set the Status_Reg
Return:
# restore registers
#----------------------------------------------------------------------
#
# other registers would be restored here...
#
lw $2, tmpr2
lw $4, tmpr4
lw $5, tmpr5
lw $6, tmpr6
lw $7, tmpr7
lw $31, tmpr31
#----------------------------------------------------------------------
# Kernel code
# Please do not modify this part
.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...
#
li $4, 11 # Is it putc?
beq $2, $4, Putc
li $4, 4 # Is it puts?
beq $2, $4, Puts
li $4, 12 # Is it getc?
beq $2, $4, Getc
j Out
#Handle the "getc" syscall
Getc: lw $4, KeyboardStatus # Spin-wait on keyboards
bgez $4, Getc
lw $4, KeyboardData
Echo:
sw $4, tmpr2 # Return character in $2
jal PutR4 # Echo the character
j Return
#Handle the "putc" syscall
Putc: lw $4, tmpr4
jal PutR4
j Return
#procedure to print out a character
PutR4: lw $2, DisplayStatus # Spin-wait on display
bgez $2, PutR4
add $6, $4, $0
# printout character on display
PutW1: sw $6, DisplayData
jr $31 # Return to caller
#Handle the "puts" syscall
Puts: lw $7, tmpr4 # Get pointer
Loop: lbu $4, ($7) # Get character
beqz $4, Return # quit on zero
jal PutR4 # Print character
addiu $7, $7, 1 # Update pointer
j Loop # loop
Out:
#-----------------------------------------------------------------------
# Kernel code
# Please do not modify this part
j Return # unknown syscall, do nothing and return
Exit:
# exit routine
li $2, 13 # special exit syscall
syscall # this syscall never returns
.text
.globl __start
__start:
# *****************************************************************
#
# MAL program to print a string forwards and backwards
#
# *****************************************************************
.data
array: .byte 0:80
enter_str: .asciiz "\n Enter string : "
cont_str: .asciiz "\n\n Do you want to continue(y/n):"
forward_str: .asciiz "\n Forward string: "
reverse_str: .asciiz "\n Reversed string: "
# $8 - Base address of array
# $9 - Array pointer used to print the string backwards
# $10 - Array pointer to print the string forwards
# $11 - String length
.text
__start:
la $8,array # Initializing the array pointer
move $9,$8
jal get_input
jal string_forward
jal string_reverse
la $9,cont_str # Loop for repeated input
li $2,4 # puts cont_str
move $4,$9
syscall
li $2,12 # getc $10
syscall
move $10,$2
li $15,'y'
beq $10,$15,__start
Done:
li $2,10
syscall
# Procedure get_input gets the input from the user as a
# sequence of characters, stores them in a byte array
# and ignores characters when the string length exceeds
# 80 characters. However the condition for termination
# is newline character
get_input:
li $11,0 # Initalizing string length
# to 0
la $12,enter_str
li $2,4 # puts enter_str
move $4,$12
syscall
loop:
li $2,12 # getc $12
syscall
move $12,$2
beq $12,'\n',end_input # Check if end of line
bge $11,80,loop # Check if string length > 80
sb $12,($9)
add $9,$9,1 # Store the character in the
add $11,$11,1 # byte array
b loop
end_input:
jr $ra
# Procedure string_reverse reverses the string by loading
# the bytes in the byte array. This is done until the
# array pointer becomes less the base address of the
# array when it means that all the characters in the
# string have been output
string_reverse:
la $13,reverse_str
li $2,4 # puts reverse_str
move $4,$13
syscall
bloop:
sub $9,$9,1
blt $9,$8,ret
lb $12,($9)
li $2,11 # putc $12
move $4,$12
syscall
b bloop
ret:
jr $ra
# Procedure string_forward prints the string by loading
# the bytes in the byte array. This is done until the
# array pointer becomes equal to the end of string pointer
# which means that all the characters in the string have been
# output
string_forward:
la $13,forward_str
li $2,4 # puts forward_str
move $4,$13
syscall
la $10,array
floop:
bge $10,$9,endf
lb $12,($10)
li $2,11 # putc $12
move $4,$12
syscall
add $10,$10,1
b floop
endf:
jr $ra
#--------------------------------------------------------------------