ECS 50: Programming Assignment #5

Spring 2021


Contents


1 Changelog

You should always refer to the latest version of this document.

• v.1: Initial version.


2 General Submission Details

        Partnering on this assignment is prohibited. If you have not already, you should read the section on academic misconduct in the syllabus.

        This assignment is due the night of Tuesday, 05/25. Gradescope will say 12:30 AM on Wednesday, 05/26, due to the “grace period” (as described in the syllabus). Be careful about relying on the grace period for extra time; this could be risky.


3 Grading Breakdown

        As stated in the updated syllabus, this assignment is worth 9% of your final grade (which is pretty inflated, but I don’t want there to be too much weight at the very end of the course). Each of the three parts is worth 3%.


4 Submitting on Gradescope

Files to submit:

• max.s

• sum_other.s

• transpose.s

        Do not submit the input code files, e.g. call_max.s. You may be penalized for submitting unnecessary files.

        There is no autograder for this assignment, at least not one that you get to interact with before the deadline. You  must simply submit your code to Gradescope, and – after the deadline – I will use a script to grade the submissions. (Make sure your file names are correct!) I will do this on the CSIF, so the CSIF is still the reference environment.

        Your output must match mine exactly.


5 Programming Problems

        For this assignment, you will implement three functions using the 64-bit RISC-V assembly language, i.e. the one that we have talked about during lecture. There are hardly any RISC-V computers out there now, so I don’t expect any of you to have any. The CSIF computers have x64 (i.e. x86-64) chips. Instead, we will use a simulator and associated compilation tools that are already installed on the CSIF. In case you are curious, the tools are listed below; you do not need to install these tools yourself, since they are already on most of the computers on the CSIF. (If you do install them on your end, just know that the process may take a few hours and is a bit complicated.) You can find a list of the CSIF computers that have the tools installed here.

• The RISC-V GNU toolchain here. I did the Newlib installation (riscv64-unknown-elf-gcc), not the Linux one, because spike requires the former.

• The Spike RISC-V ISA simulator here.

• RISC-V Proxy Kernel and Boot loader here.

In the examples below, I show how to use the RISC-V GNU toolchain on the CSIF to compile code.


5.1 General Requirements

        The requirements mentioned here apply to all three parts.

        In this assignment, all code that you write must be RISC-V assembly code. You must write this assembly code yourself. As an example of what you cannot do, you cannot write C++ code (or code in any other high-level language) and then use some tool to compile that C++ code into assembly code to submit; we will not accept that, and we will easily be able to tell if you submitted compiler-generated assembly code.

        Each of the three required functions that you write for this assignment must preserve the value of any register that it uses except for:

• The registers used for the arguments required by the function. (For example, since the function max() that you will write for part #1 takes two arguments, the registers a0 and a1 need not be preserved.)

• a0, if it is used for a return value.

        In real-world RISC-V assembly code, you would of course obey the appropriate calling convention and not preserve the values of volatile registers. Here, to give you practice preserving registers, we disregard this common calling convention.


5.2 Tips

        Note that you have access to common library functions such as printf(), due to the way in which you will compile your code. This may be helpful as you debug your code.

        If you call printf() in any of your functions, make sure to preserve the values of any volatile registers that you are using first, including – most notably – the ra register.


5.3 Part #1: Get Max

        In this part, you will write a function called max() that takes two arguments in the a0 and a1 registers – both 32-bit integers – and returns (in the a0 register) whichever of the two arguments is higher.

        Below is an example of how your code should behave. You can find call_max.s on Canvas. I intentionally show a few lines of max.s, in order to help you get started1 . Note that if you copy from this PDF directly, spaces may be inserted in unexpected locations; keep that in mind if you copy the commands in order to paste them into a terminal. Also note that the bbl loader part of the output is always there, no matter what you do; that is from the Spike emulator.


5.4 Part #2: Sum Other

        In this part, you will write a function called sum_other() that takes two arguments in the a0 and a1 registers:

1. First argument: the (potentially 64-bit) starting address of an array of 32-bit integers.

2. Second argument: length of this array (a 32-bit value).

        The function should return (in a0) the sum of every other value in the array (i.e. the sum of the first value, third value, fifth value, etc.).

        Below is an example of how your code should behave.


5.5 Part #3: Transpose

        In this part, you will implement the transpose() function that you previously implemented in part #5 of the previous programming assignment. You should consult prog_hw4.pdf if you do not remember all of the details of that function. In the version on the previous assignment, all four arguments were passed on the stack. For this current assignment, this will not be the case; instead, the four arguments will be passed through the registers a0 through a3. This function does not return any value, and it is not allowed to modify the original matrix. Note that both the input matrix and the output matrix are two-dimensional arrays of 32-bit integers, and their dimensions are 32-bit values. However, the starting addresses of these matrices are potentially 64-bit values.

        Hint: Multiplication is supported by our tools. For instance, you can do mul a0, a1, a2 to store the product of a1 and a2 in a0. (There does not seem to be a version that has an immediate operand as the third operand.)

        Below is an example of what calling the function would look like. You should yourself add a nested loop for printing out the values of the output array.