Deadline: Friday, February 19, 11:00 PM PST.
Like last week, we will be using the Venus RISC-V simulator (which can be found online here). Also, please refer to the Venus Guide on our course website when you need a refresher on any of the Venus features.
Mount the lab 4 files as you did with lab 3:
./tools/venus . -dm
.
This will expose your lab directory to Venus on a network port (6161 by default).
To connect, enter `mount http://localhost:6161 vmfs <bunch of characters>` on Venus.
,
as well as a a big “Javalin” logo.
the browser dialogue.--port <port number>
to the command (for example, ./tools/venus . -dm --port 6162
will expose the file system on port 6162)python3
command, like so: python3 ./tools/venus . -dm
. This applies to every
other instance in this assignment where you need to run ./tools/venus
.mount local vmfs
(if you chose a different port, replace “local” with the full
URL, such as http://localhost:6162
). This connects Venus to your file system.
Key has been shown in the Venus mount server! Please copy and paste it into here.
.
You should be able to see a key in the most recent line of your local terminal output;
just copy and paste it into the dialogue.vmfs
folder.lab04
, and make sure it works by hitting the Edit
button next
to discrete_fn.s
. This should open in the Editor
tab.
Editor
tab, hitting command-s
on a Mac and ctrl-s on Windows/Linux will update your local copy of the file.
To check if the save was successful, open the file on your local machine to see
if it matches what you have in the web editor (unfortunately no feedback message
has been implemented yet).Consider the discrete-valued function f
defined on integers in the set
{-3, -2, -1, 0, 1, 2, 3}
. Here’s the function definition:
f(-3) = 6
f(-2) = 61
f(-1) = 17
f(0) = -38
f(1) = 19
f(2) = 42
f(3) = 5
discrete_fn.s
in RISC-V, with the condition that
your code may NOT use any branch and/or jump instructions!discrete_fn.s
. Make sure you have it saved locally!Hint: How do you load a word from a dynamic address?
In this exercise, we’ll be looking at the code in cc_test.s
. We’ll be using
a feature that’s only available on the command line version of Venus, so if
you’re still using the Venus web editor, make sure you hit cmd-s or ctrl-s
to make sure your changes are reflected in your local files. Likewise, if you
modify your local files and want to use the Venus web simulator, make sure to
reopen your file through the simulator to make sure the changes are reflected.
Throughout this course, we will be running automated checks to make sure your assembly complies with RISC-V calling conventions, as described in lecture and discussion. Here’s a quick recap: all functions that overwrite registers that are preserved by convention must have a prologue, which saves those register values to the stack at the start of the function, and an epilogue, which restores those values for the function’s caller. You can find a more detailed explanation along with some concrete examples in these notes.
Bugs due to calling convention violations can often be difficult to find manually, so Venus provides a way to automatically report some of these errors at runtime.
Take a look at the contents of the cc_test.s
file, particularly at the main
,
simple_fn
, naive_pow
, inc_arr
, and helper_fn
functions. Enable the CC checker in settings, then run the program in the simulator.
Alternatively, you can run Venus locally with the following command:
$ ./tools/venus -cc lab04/cc_test.s
The -cc
flag enables the calling convention checker, and detects some basic
violations. You should see an output similar to the following:
[CC Violation]: (PC=0x00000080) Usage of unset register t0! cc_test.s:58 mv a0, t0
[CC Violation]: (PC=0x0000008C) Setting of a saved register (s0) which has not been saved! cc_test.s:80 li s0, 1
[CC Violation]: (PC=0x00000094) Setting of a saved register (s0) which has not been saved! cc_test.s:83 mul s0, s0, a0
[CC Violation]: (PC=0x00000094) Setting of a saved register (s0) which has not been saved! cc_test.s:83 mul s0, s0, a0
[CC Violation]: (PC=0x00000094) Setting of a saved register (s0) which has not been saved! cc_test.s:83 mul s0, s0, a0
[CC Violation]: (PC=0x00000094) Setting of a saved register (s0) which has not been saved! cc_test.s:83 mul s0, s0, a0
[CC Violation]: (PC=0x00000094) Setting of a saved register (s0) which has not been saved! cc_test.s:83 mul s0, s0, a0
[CC Violation]: (PC=0x00000094) Setting of a saved register (s0) which has not been saved! cc_test.s:83 mul s0, s0, a0
[CC Violation]: (PC=0x00000094) Setting of a saved register (s0) which has not been saved! cc_test.s:83 mul s0, s0, a0
[CC Violation]: (PC=0x000000A4) Save register s0 not correctly restored before return! Expected 0x00000A3F, Actual 0x00000080. cc_test.s:90 ret
[CC Violation]: (PC=0x000000B0) Setting of a saved register (s0) which has not been saved! cc_test.s:106 mv s0, a0 # Copy start of array to saved register
[CC Violation]: (PC=0x000000B4) Setting of a saved register (s1) which has not been saved! cc_test.s:107 mv s1, a1 # Copy length of array to saved register
[CC Violation]: (PC=0x000000E4) Setting of a saved register (s0) which has not been saved! cc_test.s:142 addi s0, t1, 1
Venus ran into a simulator error!
Attempting to access uninitialized memory between the stack and heap. Attempting to access '4' bytes at address '0x14B7A3FD'.
Find the source of each of the errors reported by the CC checker and fix it. You can find a list of CC error messages, as well as their meanings, in the Venus reference.
Once you’ve fixed all the violations reported by the CC checker, the code might still fail: this is likely because there’s still some remaining calling convention errors that Venus doesn’t report. Since function calls in assembly language are ultimately just jumps, Venus can’t report these violations without more information, at risk of producing false positives.
The fixes for all of these errors (both the ones reported by the CC checker and the
ones it can’t find) should be added near the lines marked by the FIXME
comments
in the starter code.
Note: Venus’s calling convention checker will not report all calling convention
bugs; it is intended to be used primarily as a sanity check. Most importantly, it will
only look for bugs in functions that are exported with the .globl
directive - the
meaning of .globl
is explained in more detail in the
Venus reference.
Resolve all the calling convention errors in cc_test.s
, and be able to answer the
following questions:
simple_fn
, naive_pow
, and inc_arr
that
were reported by the Venus CC checker?ra
register. Does calling convention apply to the jumps to the naive_pow_loop
or naive_pow_end
labels?ra
in the prologue for inc_arr
, but not in any other function?helper_fn
reported by the CC checker?
(Hint: it’s mentioned above in the exercise instructions.)Once you have answered these, run Venus with the calling convention checker on
factorial.s
from the last exercise as well. Make sure to fix any bugs you find.
After fixing the errors in cc_test.s
, run Venus locally with the above command to
make sure the behavior of the functions hasn’t changed and that you’ve remedied all
calling convention violations.
Once you have fixed everything, running the above Venus command should output the following:
Sanity checks passed! Make sure there are no CC violations.
Found 0 warnings!
megalistmanips.s
In Lab 3, you completed a RISC-V procedure that applied a function to every element of a linked list. In this lab, you will be working with a similar (but slightly more complex) version of that procedure.
Now, instead of having a linked list of int
’s, our data structure is a linked
list of int
arrays. Remember that when dealing with arrays in struct
’s, we
need to explicitly store the size of the array. In C code, here’s what the data
structure looks like:
struct node {
int *arr;
int size;
struct node *next;
};
Also, here’s what the new map
function does: it traverses the linked list and
for each element in each array of each node
, it applies the passed-in function
to it, and stores it back into the array.
void map(struct node *head, int (*f)(int)) {
if (!head) { return; }
for (int i = 0; i < head->size; i++) {
head->arr[i] = f(head->arr[i]);
}
map(head->next, f);
}
For the purpose of this lab, don’t worry too much about the weird syntax for C function pointers (you are welcome to learn more about them here). Basically, you can pass arguments into function pointers just like you do with normal functions.
Record your answers to the following questions in a text file. Some of the questions will require you to run the RISC-V code using Venus’ simulator tab.
megalistmanips.s
. Read
all of the commented lines under the map
function in megalistmanips.s
and make sure that the lines do what the
comments say. Some hints:
jal
?add t0, s0, x0
and lw t0, 0(s0)
?struct node
.map
, mapLoop
, and done
functions but
it’s worth understanding the full program.f
in map
), we want you to use temporary registers
instead and follow their caller/callee conventions. The provided map
implementation only uses the s0
and s1
registers, so we’ll require that you
don’t use s2
-s11
.megalistmanips.s
file. Use the -cc
flag to run a
basic calling convention check on your code locally:
./tools/venus -cc megalistmanips.s
The CC checker should report 0 warnings.
Again, the Venus Guide is a great resource if you feel unsure about any of the Venus features.
Note: The CC checker won’t check if you are using registers besides s0
and s1
, but you need to implement this requirement in order to pass the autograder.
megalistmanips
on the web interface should give the following output:Lists before:
5 2 7 8 1
1 6 3 8 4
5 2 7 4 3
1 2 3 4 7
5 6 7 8 9
Lists after:
30 6 56 72 2
2 42 12 72 20
30 6 56 20 12
2 6 12 20 56
30 42 56 72 90
Coding in RISC-V can be tricky; most of the guardrails that are present in higher level languages are missing here. As such, it is very easy to write code that passes most test cases, but still has bugs in them. This exercise will give practice on finding and solving the most common of these bugs.
The function accumulator
is defined as follows:
Inputs: a0 contains a pointer to an array of nonzero integers, terminated with 0
Output: a0 should return the sum of the elements of the array
Example: Let a0 = [1,2,3,4,5,6,7,0]
Then the expected output (in a0) is 1+2+3+4+5+6+7=28
Open the file lotsofaccumulators.s
In this file, there are five versions of accumulator
, numbered one
to five
. Then go to accumulatortests.s
. You should see a testing template, with a test already written, that tests the function on the array [1,2,3,4,5,6,7,0]
. If you replace the jal accumulatorone
line with the other accumulators, you should notice that all five version pass.
However, only one of the five versions we gave you is actually correct. Your task is to find the bugs in the accumulators, and write tests that pass on the correct version, but fail on the buggy versions.
Notably, the CC checker only catches two of these bugs. This serves as a good lesson: The CC checker does not catch everything, and as such is only a final sanity check. You are still responsible for writing strong test suites.
Record your answers to these questions in a text file. This exercise will not be autograded, but will provide a lot of practice in finding RISC-V bugs.
At this point, make sure that you are comfortable with the following.
If you are havind difficulty with the automated mounting system, you can move files to venus using this process:
upload
, then select the zip file.unzip
Please submit to the Lab 4 Autograder assignment on Gradescope.