diff --git a/lab03/cc_test.s b/lab03/cc_test.s new file mode 100644 index 0000000..36f1363 --- /dev/null +++ b/lab03/cc_test.s @@ -0,0 +1,177 @@ +.globl simple_fn naive_pow inc_arr + +.data +failure_message: .asciiz "Test failed for some reason.\n" +success_message: .asciiz "Sanity checks passed! Make sure there are no CC violations.\n" +array: + .word 1 2 3 4 5 +exp_inc_array_result: + .word 2 3 4 5 6 + +.text +main: + # We test our program by loading a bunch of random values + # into a few saved registers - if any of these are modified + # after these functions return, then we know calling + # convention was broken by one of these functions + li s0, 2623 + li s1, 2910 + # ... skipping middle registers so the file isn't too long + # If we wanted to be rigorous, we would add checks for + # s2-s20 as well + li s11, 134 + # Now, we call some functions + # simple_fn: should return 1 + jal simple_fn # Shorthand for "jal ra, simple_fn" + li t0, 1 + bne a0, t0, failure + # naive_pow: should return 2 ** 7 = 128 + li a0, 2 + li a1, 7 + jal naive_pow + li t0, 128 + bne a0, t0, failure + # inc_arr: increments "array" in place + la a0, array + li a1, 5 + jal inc_arr + jal check_arr # Verifies inc_arr and jumps to "failure" on failure + # Check the values in the saved registers for sanity + li t0, 2623 + li t1, 2910 + li t2, 134 + bne s0, t0, failure + bne s1, t1, failure + bne s11, t2, failure + # If none of those branches were hit, print a message and exit normally + li a0, 4 + la a1, success_message + ecall + li a0, 10 + ecall + +# Just a simple function. Returns 1. +# +# FIXME Fix the reported error in this function (you can delete lines +# if necessary, as long as the function still returns 1 in a0). +simple_fn: + mv a0, t0 + li a0, 1 + ret + +# Computes a0 to the power of a1. +# This is analogous to the following C pseudocode: +# +# uint32_t naive_pow(uint32_t a0, uint32_t a1) { +# uint32_t s0 = 1; +# while (a1 != 0) { +# s0 *= a0; +# a1 -= 1; +# } +# return s0; +# } +# +# FIXME There's a CC error with this function! +# The big all-caps comments should give you a hint about what's +# missing. Another hint: what does the "s" in "s0" stand for? +naive_pow: + # BEGIN PROLOGUE + # END PROLOGUE + li s0, 1 +naive_pow_loop: + beq a1, zero, naive_pow_end + mul s0, s0, a0 + addi a1, a1, -1 + j naive_pow_loop +naive_pow_end: + mv a0, s0 + # BEGIN EPILOGUE + # END EPILOGUE + ret + +# Increments the elements of an array in-place. +# a0 holds the address of the start of the array, and a1 holds +# the number of elements it contains. +# +# This function calls the "helper_fn" function, which takes in an +# address as argument and increments the 32-bit value stored there. +inc_arr: + # BEGIN PROLOGUE + # + # FIXME What other registers need to be saved? + # + addi sp, sp, -4 + sw ra, 0(sp) + # END PROLOGUE + mv s0, a0 # Copy start of array to saved register + mv s1, a1 # Copy length of array to saved register + li t0, 0 # Initialize counter to 0 +inc_arr_loop: + beq t0, s1, inc_arr_end + slli t1, t0, 2 # Convert array index to byte offset + add a0, s0, t1 # Add offset to start of array + # Prepare to call helper_fn + # + # FIXME Add code to preserve the value in t0 before we call helper_fn + # Hint: What does the "t" in "t0" stand for? + # Also ask yourself this: why don't we need to preserve t1? + # + jal helper_fn + # Finished call for helper_fn + addi t0, t0, 1 # Increment counter + j inc_arr_loop +inc_arr_end: + # BEGIN EPILOGUE + lw ra, 0(sp) + addi sp, sp, 4 + # END EPILOGUE + ret + +# This helper function adds 1 to the value at the memory address in a0. +# It doesn't return anything. +# C pseudocode for what it does: "*a0 = *a0 + 1" +# +# FIXME This function also violates calling convention, but it might not +# be reported by the Venus CC checker (try and figure out why). +# You should fix the bug anyway by filling in the prologue and epilogue +# as appropriate. +helper_fn: + # BEGIN PROLOGUE + # END PROLOGUE + lw t1, 0(a0) + addi s0, t1, 1 + sw s0, 0(a0) + # BEGIN EPILOGUE + # END EPILOGUE + ret + +# YOU CAN IGNORE EVERYTHING BELOW THIS COMMENT + +# Checks the result of inc_arr, which should contain 2 3 4 5 6 after +# one call. +# You can safely ignore this function; it has no errors. +check_arr: + la t0, exp_inc_array_result + la t1, array + addi t2, t1, 20 # Last element is 5*4 bytes off +check_arr_loop: + beq t1, t2, check_arr_end + lw t3, 0(t0) + lw t4, 0(t1) + bne t3, t4, failure + addi t0, t0, 4 + addi t1, t1, 4 + j check_arr_loop +check_arr_end: + ret + + +# This isn't really a function - it just prints a message, then +# terminates the program on failure. Think of it like an exception. +failure: + li a0, 4 # String print ecall + la a1, failure_message + ecall + li a0, 10 # Exit ecall + ecall + diff --git a/lab03/ex1.s b/lab03/ex1.s new file mode 100644 index 0000000..afe31a8 --- /dev/null +++ b/lab03/ex1.s @@ -0,0 +1,23 @@ +.data +.word 2, 4, 6, 8 +n: .word 9 + +.text +main: + add t0, x0, x0 + addi t1, x0, 1 + la t3, n + lw t3, 0(t3) +fib: + beq t3, x0, finish + add t2, t1, t0 + mv t0, t1 + mv t1, t2 + addi t3, t3, -1 + j fib +finish: + addi a0, x0, 1 + addi a1, t0, 0 + ecall # print integer ecall + addi a0, x0, 10 + ecall # terminate ecall diff --git a/lab03/ex2.c b/lab03/ex2.c new file mode 100644 index 0000000..9ecb1be --- /dev/null +++ b/lab03/ex2.c @@ -0,0 +1,16 @@ +int source[] = {3, 1, 4, 1, 5, 9, 0}; +int dest[10]; + +int fun(int x) { + return -x * (x + 1); +} + +int main() { + int k; + int sum = 0; + for (k = 0; source[k] != 0; k++) { + dest[k] = fun(source[k]); + sum += dest[k]; + } + return sum; +} \ No newline at end of file diff --git a/lab03/ex2.s b/lab03/ex2.s new file mode 100644 index 0000000..5fde342 --- /dev/null +++ b/lab03/ex2.s @@ -0,0 +1,71 @@ +.globl main + +.data +source: + .word 3 + .word 1 + .word 4 + .word 1 + .word 5 + .word 9 + .word 0 +dest: + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + +.text +fun: + addi t0, a0, 1 + sub t1, x0, a0 + mul a0, t0, t1 + jr ra + +main: + # BEGIN PROLOGUE + addi sp, sp, -16 + sw s0, 0(sp) + sw s1, 4(sp) + sw s2, 4(sp) + sw ra, 8(sp) + # END PROLOGUE + addi t0, x0, 0 + addi s0, x0, 0 + la s1, source + la s2, dest +loop: + slli s3, t0, 2 + add t1, s1, s3 + lw t2, 0(t1) + beq t2, x0, exit + add a0, x0, t2 + addi sp, sp, -8 + sw t0, 0(sp) + sw t2, 4(sp) + jal fun + lw t0, 0(sp) + lw t2, 4(sp) + addi sp, sp, 8 + add t2, x0, a0 + add t3, s2, s3 + sw t2, 0(t3) + add s0, s0, t2 + addi t0, t0, 1 + jal x0, loop +exit: + add a0, x0, s0 + # BEGIN EPILOGUE + lw s0, 0(sp) + lw s1, 4(sp) + lw s2, 4(sp) + lw ra, 8(sp) + addi sp, sp, 16 + # END EPILOGUE + jr ra diff --git a/lab03/factorial.s b/lab03/factorial.s new file mode 100644 index 0000000..15056eb --- /dev/null +++ b/lab03/factorial.s @@ -0,0 +1,24 @@ +.globl factorial + +.data +n: .word 8 + +.text +main: + la t0, n + lw a0, 0(t0) + jal ra, factorial + + addi a1, a0, 0 + addi a0, x0, 1 + ecall # Print Result + + addi a1, x0, '\n' + addi a0, x0, 11 + ecall # Print newline + + addi a0, x0, 10 + ecall # Exit + +factorial: + # YOUR CODE HERE \ No newline at end of file diff --git a/lab03/list_map.s b/lab03/list_map.s new file mode 100644 index 0000000..87acdd3 --- /dev/null +++ b/lab03/list_map.s @@ -0,0 +1,126 @@ +.globl map + +.text +main: + jal ra, create_default_list + add s0, a0, x0 # a0 = s0 is head of node list + + #print the list + add a0, s0, x0 + jal ra, print_list + + # print a newline + jal ra, print_newline + + # load your args + add a0, s0, x0 # load the address of the first node into a0 + + # load the address of the function in question into a1 (check out la on the green sheet) + ### YOUR CODE HERE ### + + # issue the call to map + jal ra, map + + # print the list + add a0, s0, x0 + jal ra, print_list + + # print another newline + jal ra, print_newline + + addi a0, x0, 10 + ecall #Terminate the program + +map: + # Prologue: Make space on the stack and back-up registers + ### YOUR CODE HERE ### + + beq a0, x0, done # If we were given a null pointer (address 0), we're done. + + add s0, a0, x0 # Save address of this node in s0 + add s1, a1, x0 # Save address of function in s1 + + # Remember that each node is 8 bytes long: 4 for the value followed by 4 for the pointer to next. + # What does this tell you about how you access the value and how you access the pointer to next? + + # load the value of the current node into a0 + # THINK: why a0? + ### YOUR CODE HERE ### + + # Call the function in question on that value. DO NOT use a label (be prepared to answer why). + # What function? Recall the parameters of "map" + ### YOUR CODE HERE ### + + # store the returned value back into the node + # Where can you assume the returned value is? + ### YOUR CODE HERE ### + + # Load the address of the next node into a0 + # The Address of the next node is an attribute of the current node. + # Think about how structs are organized in memory. + ### YOUR CODE HERE ### + + # Put the address of the function back into a1 to prepare for the recursion + # THINK: why a1? What about a0? + ### YOUR CODE HERE ### + + # recurse + ### YOUR CODE HERE ### + +done: + # Epilogue: Restore register values and free space from the stack + ### YOUR CODE HERE ### + + jr ra # Return to caller + +square: + mul a0 ,a0, a0 + jr ra + +create_default_list: + addi sp, sp, -12 + sw ra, 0(sp) + sw s0, 4(sp) + sw s1, 8(sp) + li s0, 0 # pointer to the last node we handled + li s1, 0 # number of nodes handled +loop: #do... + li a0, 8 + jal ra, malloc # get memory for the next node + sw s1, 0(a0) # node->value = i + sw s0, 4(a0) # node->next = last + add s0, a0, x0 # last = node + addi s1, s1, 1 # i++ + addi t0, x0, 10 + bne s1, t0, loop # ... while i!= 10 + lw ra, 0(sp) + lw s0, 4(sp) + lw s1, 8(sp) + addi sp, sp, 12 + jr ra + +print_list: + bne a0, x0, printMeAndRecurse + jr ra # nothing to print +printMeAndRecurse: + add t0, a0, x0 # t0 gets current node address + lw a1, 0(t0) # a1 gets value in current node + addi a0, x0, 1 # prepare for print integer ecall + ecall + addi a1, x0, ' ' # a0 gets address of string containing space + addi a0, x0, 11 # prepare for print string syscall + ecall + lw a0, 4(t0) # a0 gets address of next node + jal x0, print_list # recurse. We don't have to use jal because we already have where we want to return to in ra + +print_newline: + addi a1, x0, '\n' # Load in ascii code for newline + addi a0, x0, 11 + ecall + jr ra + +malloc: + addi a1, a0, 0 + addi a0, x0 9 + ecall + jr ra \ No newline at end of file diff --git a/tools/venus.jar b/tools/venus.jar new file mode 100644 index 0000000..f9f9d7b Binary files /dev/null and b/tools/venus.jar differ