#---------------------------------------------------------------------- # 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 #--------------------------------------------------------------------