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

#--------------------------------------------------------------------