#Solution to programming assignment 2, question 3. #Look for "change:" to see the changes made to the code. # #The subroutine calls are no longer commented out ; that change is not marked #below. # #Note that I had left in some code that I meant to take out (leaving it as an exercise for you). #Those were the lines that said "remove this! for their sample code". Oops. # #Make sure you understand and trace this code, and go through it in Mars. #Exam 2 will assume you understand this code. # .data nums: .word 5,0x50,0x40,0x30,0x20,0x10 array1: .word 5, 0x100, 0x25, -1, 100,10000 #static output strings follow str1: .asciiz "\n\nThe array1 has " str2: .asciiz " elements.\r\n" str3: .asciiz "They are " str4: .asciiz "." str5: .asciiz ", " .text # # The main program uses the stack to reverse the values stored in # array nums. Subroutine selectionSort is repeatedly called on # array1, while we are pushing and popping the elements of nums on the stack. # This doesn't make much sense, but allows us to demonstate the # register calling-convention issues question 3 is about. # # Start by commenting out the calls to selectionSort and printArray, # assemble and run the program, and make sure you understand what the # main program does. # # Then, uncomment the calls to selectionSort and printArray, and # assemble and run the program. You'll see that the subroutines still # work, but the main program doesn't work anymore. # # Now modify the subroutine(s) so that they follow the calling # conventions. Don't change anything in the main program. In your # final version, both the main program code and the subroutines should # work. # main: la $s0,nums lw $s1,0($s0) #$s1 number of elements in array nums addi $s0,$s0,4 #$s0 base address of the actual array nums li $s2,0 pushes: beq $s2,$s1,pops lw $t0,0($s0) addi $sp,$sp,-4 sw $t0,0($sp) #Take a break, and call selection sort la $a0, array1 #load the address of "array1" into parameter0 jal selectionSort #call the selection sort procedure la $a0, array1 #load the address of "array1" into parameter0 jal printArray #call the printarray procedure #Now, back to pushing array nums onto the stack addi $s2,$s2,1 addi $s0,$s0,4 j pushes pops: la $s0,nums lw $s1,0($s0) #$s1 number of elements in array nums addi $s0,$s0,4 #$s0 base address of the actual array nums li $s2,0 popsloop: beq $s2,$s1,finish lw $t0,0($sp) addi $sp,$sp,4 sw $t0,0($s0) #Take a break, and call selection sort la $a0, array1 #load the address of "array1" into parameter0 jal selectionSort #call the selection sort procedure la $a0, array1 #load the address of "array1" into parameter0 jal printArray #call the printarray procedure #Now, back to popping the stack into array nums addi $s2,$s2,1 addi $s0,$s0,4 j popsloop finish: # #exit from the program # li $v0,10 syscall selectionSort: #selectionSort $a0 has the base address of the array datastructure, where the first # word of that datastructure contains the number of elements in the array, and the # remaining words contain the elements themselves. This subroutine sorts the # elements in increasing order. #change: $s0-$s7 should be preserved across a call. #So, push the ones used by the subroutine on the stack. #TO STUDY FOR THE EXAM: draw what you think is on the stack #as this code is executed, then trace through in Mars. # addi $sp,$sp,-4 sw $s0,0($sp) addi $sp,$sp,-4 sw $s1,0($sp) addi $sp,$sp,-4 sw $s3,0($sp) addi $sp,$sp,-4 sw $s5,0($sp) addi $sp,$sp,-4 sw $s6,0($sp) move $s0, $a0 #load the array into $s0 lw $s1, 0($s0) #$s1 is the number of elements in the array add $s3, $zero, $s1 #$s3 = curTop, $s1 = numElems loop: addi $s6, $zero, 1 #s6 is maxpos, maxpos = 1 addi $s5, $zero, 1 #$s5=i, i = 1 inner: sll $t2, $s5, 2 #multiply i by 4 to get the offset of array[i] sll $t3, $s6, 2 #multiply maxpos by 4 to get the offset of array[maxpos] add $t2, $t2, $s0 #add the offset of array[i] to the base addr of arry add $t3, $t3, $s0 #add the offset of array[maxpos] to the base addr of arry lw $t2 0($t2) #retreive the value stored in array[i] lw $t3 0($t3) #retreive the value stored in array[maxpos] slt $t4, $t3, $t2 #if array[maxpos] < array[i], $t4 = 1 beq $t4, 1, assign #if array[maxpos] < array[i], set maxpos=i j endassign #if we don't need to set maxpos=i, jump past that instruction assign: addi $s6, $s5, 0 #set maxpos = i endassign: beq $s3, $s5, exitinner #if i = curtop we are done, go to exitinner addi $s5, $s5, 1 #increment i j inner #restart the inner loop exitinner: sll $t5, $s6, 2 #multiply maxpos by 4 to get the offset of array[maxpos] add $t9, $s0, $t5 #t9 = array[maxpos] address addi $sp,$sp,-4 sw $ra,0($sp) move $a0,$t9 sll $t3, $s3, 2 #multiply curtop by 4 to get the offset of array[curtop] add $t2, $s0, $t3 #t2 = array[curtop] address move $a1,$t2 jal swap lw $ra,0($sp) addi $sp,$sp,4 beq $s3, 1, endsort #if curtop = 1 we are finished, jump to exit addi $s3, $s3, -1 #decrement curTop j loop ##iterate over all elements in the array up to curtop ($s3) endsort: # restore the values to the $S registers. lw $s6,0($sp) addi $sp,$sp,4 lw $s5,0($sp) addi $sp,$sp,4 lw $s3,0($sp) addi $sp,$sp,4 lw $s1,0($sp) addi $sp,$sp,4 lw $s0,0($sp) addi $sp,$sp,4 jr $ra swap: ## $a0 and $a1 contain addresses of memory locations. Swap swaps their values. lw $t0,0($a0) lw $t1,0($a1) sw $t1,0($a0) sw $t0,0($a1) jr $ra printArray: #prints the contents of the array, whose base address is passed as an #argument in $a0 #change: the original version of printArray uses $s0, and $s1 without preserving #Their values. This messed up the code in the main program. So, push them on the stack #upon entering printArray, and then restore their values when leaving. # #NOTE: another option would be to simply use $t registers, since they do not need to be preserved #across calls. addi $sp,$sp,-4 sw $s0,0($sp) addi $sp,$sp,-4 sw $s1,0($sp) move $s0, $a0 li $v0, 4 #prints str1: "The array has" la $a0, str1 syscall lw $s1, 0($s0) li $v0, 1 move $a0, $s1 #prints the number of elements syscall li $v0, 4 #prints str2: "elements." la $a0, str2 syscall li $v0, 4 #prints str3: "They are" la $a0, str3 syscall addi $t1, $zero, 1 addi $t2, $s1, 1 exitloop: #prints all of the elements in the array beq $t1, $t2, endPrintArray #if we are done looping, jump to endPrintArray sll $t6, $t1, 2 add $t4, $s0, $t6 lw $t5, 0($t4) li $v0, 1 move $a0, $t5 #prints an element in the array syscall addi $t1, $t1, 1 beq $t1, $t2, endPrintArray li $v0, 4 #prints str5: ", " la $a0, str5 syscall j exitloop endPrintArray: li $v0, 4 #prints str4: "." la $a0, str4 syscall # restore values of $s0 and $s1 lw $s1,0($sp) addi $sp,$sp,4 lw $s0,0($sp) addi $sp,$sp,4 jr $ra #procedure is complete, return to calling address