共计 7176 个字符,预计需要花费 18 分钟才能阅读完成。
ECS 50: Programming Assignment #5
Spring 2021
Contents
1 Changelog 1
2 General Submission Details 1
3 Grading Breakdown 1
4 Submitting on Gradescope 1
5 Programming Problems 2
5.1 General Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
5.2 Tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
5.3 Part #1: Get Max . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
5.4 Part #2: Sum Other . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
5.5 Part #3: Transpose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
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
∗This content is protected and may not be shared, uploaded, or distributed.
1
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.
1You must make max a global symbol with the .global directive, so that the symbol can be seen from within call_max.s. (I think that .globl
and .global are exactly the same.)
2
1 $ cat call_max . s
2 . data
3
4 format_str : . string ” Max : %d\ n”
5
6 . text
7 . globl main
8 main :
9 li a0 , 5
10 li a1 , 13
11 jal max
12 mv a1 , a0
13 lui a0 , % hi (format_str)
14 addi a0 , a0 , % lo (format_str)
15 call printf
16 # Perform exit () system call .
17 # Source : https :// www . robalni . org / riscv / linux – syscalls -64. html
18 li a7 , 93
19 li a0 , 0
20 ecall
21 $ cat max .s
22 . global max
23 max :
24 … (removed by Aaron) …
25 jalr x0 , 0(x1)
26 $ / opt / riscv / bin / riscv64 – unknown – elf – gcc max .s call_max .s -o max
27 $ / opt / riscv / bin / spike / opt / riscv / riscv64 – unknown – elf / bin / pk max
28 bbl loader
29 Max : 13
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:
- First argument: the (potentially 64-bit) starting address of an array of 32-bit integers.
- 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. - $ cat call_sum_other .s
- . data
3 - format_str : . string ” Sum : %d\ n”
5 - arr :
- . long 5
- . long 20
- . long 13
- . long 18
- . long 27
- . long 42
13 - . text
- . globl main
- main :
- lui a0 , % hi (arr)
- addi a0 , a0 , % lo (arr)
- li a1 , 6
- jal sum_other
- mv a1 , a0
- lui a0 , % hi (format_str)
- addi a0 , a0 , % lo (format_str)
- call printf
Perform exit () system call .
- li a7 , 93
- li a0 , 0
- ecall
- $ cat sum_other .s
- . global sum_other
- sum_other :
3 - … (removed by Aaron) …
- jalr x0 , 0(x1)
- $ / opt / riscv / bin / riscv64 – unknown – elf – gcc sum_other .s call_sum_other . s -o sum_other
- $ / opt / riscv / bin / spike / opt / riscv / riscv64 – unknown – elf / bin / pk sum_other
- bbl loader
- Sum : 45
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. - $ cat call_transpose .s
- . data
3 - input :
- . word 1
- . word 2
- . word 3
- . word 4
- . word 5
- . word 6
11 - output :
- . rept 6
- . word -1
- . endr
16 - . text
- . globl main
- main :
- lui a0 , % hi (input)
- addi a0 , a0 , % lo (input)
- li a1 , 3
- li a2 , 2
- lui a3 , % hi (output)
- addi a3 , a3 , % lo (output)
- jal transpose
Perform exit () system call .
- li a7 , 93
- li a0 , 0
- ecall
- $ cat transpose .s
- . global transpose
- transpose :
- … (removed by Aaron) …
- jalr x0 , 0(x1)