# This program includes a variety of procedures for managing # 2-dimensional vectors (point coordinates). # A v2 object is two words long. The first word is the x-coordinate, # the second word is the y-coordinate. .data # The following entries go in the data segment strName: .asciiz "Author: Doug Johnson, Rob Nash, et al.\n\n" strTaskA: .asciiz "\nVector Addition\n\n" strTaskB: .asciiz "\nVector Equality\n\n" strComma: .asciiz "," strSeparator: .asciiz " -> " strNewline: .asciiz "\n" strInitComplete: .asciiz "Init Complete\n\n" coords: .word 0,1,2,2,5,2,8,8,0,-10 endtag: # must be the address after the array origin: # the point (0,0) .word 0,0 delta: # offset amount added to each original vector .word 0,0 # stack frame layout - This is a convention we *could* follow, where we'd need to pass all arguments on the stack # if we followed this convention, our stack (including our argument "build area") would look like below # 28($sp) unused # 24($sp) $ra # 20($sp) $s1 # 16($sp) $s0 # 12($sp) some architectures pass all on the stack - this is $a3 save space # 8($sp) some architectures pass all on the stack - this is $a2 save space # 4($sp) some architectures pass all on the stack - this is $a1 save space # 0($sp) some architectures pass all on the stack - this is $a0 save space .text # The following entries go in the text (program code) segment main: # Function Prologue: (aka, stack frame construction)############################### # the first few lines of code within a function that prepare the stack and registers for use within the function # note that this "convention" is *required* if this function (main) will call other functions subu $sp,$sp,32 # create stack frame sw $ra,24($sp) # save return address sw $s1,20($sp) # save $s1 - note for this example:We didn't need to save these-these are callee saved! sw $s0,16($sp) # save $s0 ################################################################################## #Task 0: bounds check------------------------------------------------------------- la $s0,coords # $s0 = next = address(coords) la $s1,endtag # $s1 = endtag = address(endtag) beq $s0,$s1,mainEpilogue # if array length is zero, then quit - non SESE #--------------------------------------------------------------------------------- #Task 1: initialize--------------------------------------------------------------- la $a0, strInitComplete jal Init # print program author and first task, prep the gravity vector #what would have happened if we didn't store $ra on the stack in the prologue, and we just jal-ed above? #--------------------------------------------------------------------------------- #Task 2: Add Gravity to each vector in the array---------------------------------- jal AddGravity #--------------------------------------------------------------------------------- #Task 3: Display the updated coords (skipping origin pairs)----------------------- jal ShowCoordsNotAtOrigin #--------------------------------------------------------------------------------- mainEpilogue: # Function Epilog: (aka, stack frame deallocate)############################### # the last few lines of code within a function that restore the stack and registers to the state before the # function was called. # note that this "convention" is *required* if this function (main) will call other functions, as our $ra has # been overwritten by the other functions we have called, as have any arguments ($a0-$a4) that were passed to # the other functions, etc. lw $ra,24($sp) # restore return address lw $s1,20($sp) # restore $s1 lw $s0,16($sp) # restore $s0 addu $sp,$sp,32 # release stack frame jr $ra # return ################################################################################### #-----------------------------------------------------------------------------(leaf) # v2Set(int *vec,x,y) # Set the contents of a vector in memory # $a0 - vec - address of a 2-element word vector # $a1 - x - value to put in the first element of vec # $a2 - y - value to put in the second element of vec v2Set: sw $a1,0($a0) # store the first value in vec[0] sw $a2,4($a0) # store the second value in vec[1] jr $ra #-----------------------------------------------------------------------------(leaf) # v2Print(int *vec) # Print the contents of a vector in memory # $a0 - vec - address of the 2-element word vector to print v2Print: move $t0,$a0 # remember address of vec lw $a0,0($t0) # load the x coordinate li $v0,1 # load print_integer code syscall # print la $a0,strComma # load address of the string to print li $v0,4 # load print_string code syscall # print lw $a0,4($t0) # load the y coordinate li $v0,1 # load print_integer code syscall # print jr $ra #------------------------------------------------------------------------------(leaf) # v2Add(int *a,int *b,int *c) # Add the contents of two vectors and store the result in # a third vector # $a0 - a - address of one vector operand # $a1 - b - address of another vector operand # $a2 - c - address of the vector in which to store the sum a+b. v2Add: lw $t0,0($a0) # get a[0] lw $t1,0($a1) # get b[0] add $t2,$t0,$t1 # add sw $t2,0($a2) # store result in c[0] lw $t0,4($a0) # get a[1] lw $t1,4($a1) # get b[1] add $t2,$t0,$t1 # add sw $t2,4($a2) # store result in c[1] jr $ra #-------------------------------------------------------------------------------(leaf) # int v2Equal(int *a,int *b) # Compare the contents of two vectors # Return 1 if equal, 0 if not equal # $a0 - a - address of one 2-element word vector # $a1 - b - address of another 2-element word vector # $v0 - 1 (true) if equal, 0 (false) if not equal v2Equal: move $v0,$zero # return false by default lw $t0,0($a0) # get a[0] lw $t1,0($a1) # get b[0] bne $t0,$t1,v2EqualReturn lw $t0,4($a0) # get a[1] lw $t1,4($a1) # get b[1] bne $t0,$t1,v2EqualReturn li $v0,1 # return true v2EqualReturn: jr $ra #---------------------------------------------------------------------------------(nonleaf) # void Init(int* a) # a - $a0 - address of string to print upon completion # Some simple syscalls to print initial text (and move this code from main) # as well as initialize our "gravity" vector Init: #Function prologue ####################################################### subu $sp,$sp,32 # create stack frame sw $ra,24($sp) # save return address sw $a2, 8($sp) sw $a1, 4($sp) # save $a1 - note for this function we're not using s0, s1, so we don't have to save those sw $a0, 0($sp) # save $a0 - We were passed input as $a0 and if we needed to call a ftn, it too might need # some input and would expect it in $a0. If we overwrite and never save our first $a0 value # (the input to this function, we'll print out garbage as we've lost our initial input due # to a nested procedure and not watching what we're doing ########################################################################### la $a0,strName # load name string address li $v0,4 # load print_string code syscall # print # set the delta vector to (dx,dy) la $a0,delta # delta vector address li $a1,0 # dx = 0 li $a2,10 # dy = 10, which is just ceiling of (9.8), so rounded ##Notice the nested function call! This is why we need to build a frame for this function jal v2Set # set delta #if we just called jr $ra right now (without the function epilog restoring our values for us), we would return to? #jr $ra #(example1) # Print our status ####################################################### # We lifted this line out of the epilog, as the value of $a0 that we were passed as input to this function has been # written over each time we had to call a function from within this function. Good thing we saved it on the stack. lw $a0,0($sp) # (2) restore $a0 ####################################################### li $v0,4 # print_string syscall #Function Epilogue ######################################################## lw $ra,24($sp) # restore return address (3) Why Mem out of bounds! Check out the kernel space call above! lw $a2,8($sp) # restore $a2 - since we really didn't need these like $a0 above, we could have not restored lw $a1,4($sp) # restore $a1 lw $a0,0($sp) # restore $a0 - could remove this line, as it was accomplished above addu $sp,$sp,32 # release stack frame jr $ra # return ########################################################################### #---------------------------------------------------------------------------------(nonleaf) # void AddGravity(void) # Iterates through the array adding the delta vector to every vector and storing the result back in the same place # in memory. # AddGravity: #Function prologue ####################################################### subu $sp,$sp,32 # create stack frame sw $ra,24($sp) # save return address sw $s1, 20($sp) # save $s1 sw $s0, 16($sp) # save $s0 ########################################################################## # print the name of the first task la $a0,strTaskA # load task label address li $v0,4 # load print_string code syscall # print # look at each vector in the array # print the vector, add the gravity delta to the vector, print the result vector la $s0,coords # $s0 = next = address(coords) la $s1,endtag # $s1 = endtag = address(endtag) mainLoopA: move $a0,$s0 # address of next vector jal v2Print # print the vector la $a0,strSeparator # separator string address li $v0,4 # print_string code syscall # print move $a0,$s0 # reload source vector address la $a1,delta # load address of offset amount move $a2,$a0 # a2 = a0, meaning store the sum at the current index in the array (a0 has it now) jal v2Add # add the vectors move $a0,$a2 # address of result vector jal v2Print # print the result vector la $a0,strNewline # newline address li $v0,4 # print_string code syscall # print addi $s0,8 # point to next vector in array bne $s0,$s1,mainLoopA # loop if more data in array #Function Epilogue ######################################################## lw $ra,24($sp) # restore return address lw $s1,20($sp) # restore $a1 lw $s0,16($sp) # restore $a0 addu $sp,$sp,32 # release stack frame jr $ra # return ########################################################################### #---------------------------------------------------------------------------------(nonleaf) # void ShowCoordsNotAtOrigin(void) # Iterates through the array and prints those coordinates that aren't equal to (0,0) # ShowCoordsNotAtOrigin: #Function prologue ####################################################### subu $sp,$sp,32 # create stack frame sw $ra,24($sp) # save return address sw $s1, 20($sp) # save $s1 sw $s0, 16($sp) # save $s0 ########################################################################## # print the name of the second task la $a0,strTaskB # load task label address li $v0,4 # load print_string code syscall # print # look at each vector in the array # if the vector is not the origin, print the vector la $s0,coords # $s0 = next = address(coords) la $s1,endtag # $s1 = endtag = address(endtag) mainLoopB: move $a0,$s0 # address of current vector la $a1,origin # address of origin vector jal v2Equal # check for equal bnez $v0,mainIfSkip # skip if vector is equal to origin move $a0,$s0 # address of vector jal v2Print # print the vector la $a0,strNewline # newline address li $v0,4 # print_string code syscall # print mainIfSkip: addi $s0,8 # point to next vector in array bne $s0,$s1,mainLoopB # loop if more data in array #Function Epilogue ######################################################## lw $ra,24($sp) # restore return address lw $s1,20($sp) # restore $a1 lw $s0,16($sp) # restore $a0 addu $sp,$sp,32 # release stack frame jr $ra # return ###########################################################################