Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

CS 61C Fall 2023

Part A

In this part, you will implement a few math operations that will be used for classification later.

Before starting, please pull from the starter and update Venus.

$ git pull starter main

$ bash test.sh download_tools

Task 1: Absolute Value (Walkthrough)

To familiarize you with the workflow of this project, we will walk you through this task.

Running Tests

In this project, tests are written in Python and compiled into RISC-V assembly.

The Python source for the provided tests is located in unittests.py. Look over the contents of unittests.py. Although the tests are written for you in Tasks 1-4, it helps to be familiar     with the unit testing framework to understand what the tests are doing.

To run the tests, on your local machine, start by running bash test.shin the 61c-proj2

directory on your local machine. This gives you an overview of the commands you can run for testing. In particular, bash test.sh part_a compiles and runs all the tests for Part A. You  can also provide the name of a specific function to compile and run all the tests for that

particular function.

For this task, since we are implementing the abs function, on your local machine, run bash test.sh test_abs. This creates a test-src folder containing the Python tests compiled into   RISC-V.

Since we haven't implemented the abs function yet, some of the tests are failing. Let's try implementing abs.

You can edit files in a text editor or directly in Venus. To edit files in Venus, switch to the Files tab. Here you can open and edit assembly files. Remember to save your files

frequently with control+S (Windows) or command+S (Mac). Venus does not auto-save as you work.

Open src/abs.s (either in a text editor or Venus) and copy-paste the implementation below.

abs:

blt a0, zero, done

# Negate a0

sub a0, x0, a0

done:

ret

Again on your local machine, run bash test.sh test_abs. The tests don't pass, so something is probably wrong with our implementation.

Using VDB to debug tests via Venus

First, open up Venus in your web browser and mount your files. (Refer back to the setup section of the spec if you're having trouble.)

Let's start by setting a breakpoint. Type ebreak at the start of the abs function. This places a breakpoint just before the blt a0, zero, done instruction.

To start the debugger, in the Venus terminal, run cd /vmfs/test-src and run ls. This

should list all the test files you can run. Run vdb test_abs_one.s to start the debugger for an absolute value test.

In the Venus simulator tab, Click Run to start running the program. The debugger will    pause at the breakpoint we set. While paused, you can inspect the registers and memory. In particular, notice that register a0 contains the argument 1 here, because this test calls    your function with argument a0 = 1.

Task 2: ReLU

In this project, we will be working with integer arrays. Remember that the integers in an integer array are stored in a consecutive block of memory.

To pass an integer array as an argument, we will pass a pointer to the start of the integer array, and the number of elements in the array.



In this diagram, register a0 stores the first argument (the address of the start of the array). Register a1 stores the second argument (the number of integers in the array).

Conceptual Overview: ReLU

The ReLU function takes in an integer array and sets every negative value in the array to 0. Positive values in the array are unchanged. In other words, for each element x in the array, ReLU computes max(x, 0).

ReLU should modify the array in place. For example, if the above integer array is passed into ReLU, the result would be stored in the same place in memory:




Note that the negative values in the array were set to 0 in memory.

Your Task

Fill in therelu function in src/relu.s.


relu: Task 2.

Arguments

a0

int *

A pointer to the start of the integer array.

a1

int

The number of integers in the array. You can assume that

this argument matches the actual length of the integer

array.

Return

values

None

If the input is malformed in the following ways, put the appropriate return code into a0  and run j exit to quit the program. (For example, if the length of the array is less than 1, run li a0 36 and j exit.)


Return

code

Exception

36

The length of the array is less than 1.


Testing and debugging

To test your function, in your local terminal, run bash test.sh test_relu.

To debug your function, in your Venus terminal, run cd /vmfs/test-src, then run a VDB command to start the debugger:


vdb test_relu_standard.s

vdb test_relu_length_1.s

vdb test_relu_invalid_n.s

Here are some debugging tips that should apply to the entire project:

· If you see the error "You are attempting to edit the text of the program though the

program is set to immutable at address 0x00000000!", this means that you are trying  to write to memory address 0x00000000 (or whatever memory address you see in the error). This is probably happening because you're giving this address to a store

instruction, which then tries to write to this address.

· If you see the error "label exit used but not defined" when starting the debugger,

make sure that you're starting the debugger with the vdb commands above. Clicking "assemble and simulate from editor" will not work.

· Unfortunately the local tests don't check for out-of-bounds memory accesses. If you  ever encounter a failing test on the autograder, try making sure that your code never writes to memory outside of an array.

If your ReLU works locally but not on Gradescope, here are some edge cases we've seen that the local cases don't check. You can modify unittests.py to write your own tests for these cases!

· The local tests don't perform ReLU on larger numbers.

· Watch the debugging videos.


Task 3: Argmax

Conceptual Overview: Argmax

The argmax function takes in an integer array and returns the indexof the largest element in the array. If multiple elements are tied as the largest element, return the smallest index.

For example, if the integer array [-6, -1, 6, 1] is passed into the argmax function, the

output should be 2, because the largest integer (6) is located at index 2 in the array. If the integer array were instead [6, 1, 6, 1], then the output should be 0, because the largest  integer (6) is first found at index 0.


Your Task

Fill in the argmax function in src/argmax.s.


argmax: Task 3.

Arguments

a0

int *

A pointer to the start of the integer array.

a1

int

The number of integers in the array. You can assume that

this argument matches the actual length of the integer

array.

Return

values

a0

int

The index of the largest element. If the largest element appears multiple times, return the smallest index.

If the input is malformed in the following ways, put the appropriate return code into a0 and run j exit to quit the program.


Return

code

Exception

36

The length of the array is less than 1.


Testing and debugging

To test your function, in your local terminal, run bash test.sh test_argmax.

To debug your function, in your Venus terminal, run cd /vmfs/test-src, then run a VDB command to start the debugger:


vdb test_argmax_invalid_n.s

vdb test_argmax_length_1.s

vdb test_argmax_standard.s

If your argmax works locally but not on Gradescope, here are some edge cases we've seen that the local cases don't check. You can modify unittests.py to write your own tests for

these cases!

The local tests don't check that your code works if the largest element in the array is the last element of the array.

The local tests don't check that your code works if the largest element appears more than once.

Watch the debugging videos.


Task 4: Dot Product

Conceptual Overview: Dot Product

The dot product function takes in two integer arrays, multiplies the corresponding entries of the arrays together, and returns the sum of all the products.

For example, if these two integer arrays were passed into the dot product function, the function would return (1*6) + (2*1) + (3*6) + (4*1) + (5*6) + (6*1) + (7*6) + (8*1) +  (9*6) = 170.



Conceptual Overview: Array Strides

Instead of iterating through every element of the array, what if we want to iterate through

every other element, or every third element? To do this, we will define the stride of an

array.

To iterate through an array with stride n, start at the beginning of the array and only consider every nth element, skipping the elements in between.

Note that the stride is given in number of elements, not number of bytes. This means that iterating with stride 1 is equivalent to iterating through every element of the array.



For example,in the above diagram, both arrays are using stride 2, so we skip every other    element in the array. 5 elements should be considered, so we stop after multiplying 5 pairs

of elements together. The function would return (1*6) + (3*6) + (5*6) + (7*6) + (9*6) =

150.



In the above diagram, the first array is using stride 2, so we skip every other element in

this array. The second array is using stride 3, so we use every third element in this array. 3 elements should be considered, so we stop after multiplying 3 pairs of elements together. The function would return (1*6) + (3*1) + (5*6) = 39.


Your Task

Fill in the dot function in src/dot.s.

The dot function may assume that the a2 argument for the number of elements to use in the calculation will not cause an out-of-bounds array access. However, you will need to   enforce this when calling dot from other functions later in this project.


dot: Task 4.

Arguments

a0

int *

A pointer to the start of the first array.

a1

int *

A pointer to the start of the second array.

a2

int

The number of elements to use in the calculation.

a3

int

The stride of the first array.


a4

int

The stride of the second array.

Return

values