cs61c-lab03

Lab 3: RISCV Assembly

cs61c - Great Ideas in Computer Architecture (Machine Structures) lab 笔记第三篇

课程主页:https://inst.eecs.berkeley.edu/~cs61c/fa20/#by-week

个人仓库:https://github.com/2333monster/my-cs61c-lab

lab3 熟悉编写 RISC-V 并使用 Venus 模拟器 Venus reference,先硬着头皮做的proj2A,被折磨了两天,现在在写这些基础的确实觉得很简单,不过先写了lab3应该对proj2有些帮助,可以说是前置。

Exercise 0: Connecting your files to Venus

注意lab03好像默认是没有tools/venus.jar 这个文件的,可以从sp22的proj2复制一个

将文件链接到_Venus_, 在lab文件下

1
2
3

terminal -> java -jar tools/venus.jar . -dm
venus -> mount local vmfs

Exercise 1: Familiarizing yourself with Venus

  1. What do the .data, .word, .text directives mean (i.e. what do you use them for)? Hint: think about the 4 sections of memory.
1
2
3
4
5
.data : 这是一个数据段的声明,用于存储程序中的数据
.word 2, 4, 6, 8: 这个指令在数据段中分别存储了四个字(32位)的数据,具体是 2, 4, 6, 8
0x1000000 - 0x1000000c
n: .word 9:这个指令在数据段中创建了一个标签 n,并在 n 处存储了一个字的数据,即 9
0x10000010
  1. Run the program to completion. What number did the program output? What does this number represent?
1
34 9th fibonacci 数
  1. At what address is n stored in memory? Hint: Look at the contents of the registers.
1
0x10000010 
  1. Without actually editing the code (i.e. without going into the “Editor” tab), have the program calculate the 13th fib number (0-indexed) by manually modifying the value of a register. You may find it helpful to first step through the code. If you prefer to look at decimal values, change the “Display Settings” option at the bottom.
1
n: .word 9 -> n: .word 13

Exercise 2: Translating from C to RISC-V

ex2.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}

ex2.s

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
.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, -20
sw s0, 0(sp)
sw s1, 4(sp)
sw s2, 8(sp)
sw s3, 12(sp)
sw ra, 16(sp)
# END PROLOGUE
addi t0, x0, 0
addi s0, x0, 0
la s1, source
la s2, dest
loop:
slli s3, t0, 2 # 4*k index step
add t1, s1, s3 # &source[k]
lw t2, 0(t1) # source[k]
beq t2, x0, exit # source[k] != 0
add a0, x0, t2 # a0 = source[k] prepare for fun() argument
addi sp, sp, -8 # store registers
sw t0, 0(sp)
sw t2, 4(sp)
jal fun # call fun()
lw t0, 0(sp)
lw t2, 4(sp)
addi sp, sp, 8 # recover registers
add t2, x0, a0 # t2 = fun(source[k]), a0 已经是返回值了
add t3, s2, s3 # t3 = &dest[k]
sw t2, 0(t3) # dest[k] = fun(source[k])
add s0, s0, t2 # sum += dest[k]
addi t0, t0, 1 # k++
jal x0, loop
exit:
add a0, x0, s0
# BEGIN EPILOGUE
lw s0, 0(sp)
lw s1, 4(sp)
lw s2, 8(sp)
lw s3, 12(sp)
lw ra, 16(sp)
addi sp, sp, 20
# END EPILOGUE
jr ra

  1. The register representing the variable k.
1
t0
  1. The register representing the variable sum
1
s0
  1. The registers acting as pointers to the source and dest arrays.
1
2
la s1, source -> load address of source
la s2, dest
  1. The assembly code for the loop found in the C code
1
2
3
4
5
6
7
loop:
...
beq t2, x0, exit # source[k] != 0
...
addi t0, t0, 1 # k++
...
jal x0, loop
  1. How the pointers are manipulated in the assembly code.
1
2
3
slli s3, t0, 2		# 4*k index step
add t1, s1, s3 # &source[k]
lw t2, 0(t1) # source[k]

Exercise 3: Factorial

递归:

factorial.c

1
2
3
4
5
6
7
unsigned long long factorial(unsigned int n) {
if (n == 0 || n == 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}

factorial.s

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
.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:
bnez a0, L # 如果 a0 非零,跳转到 .L1 标签
li a0, 1 # 如果 a0 为零,将 a0 设为 1
ret

L:
# prologue
addi sp, sp, -8 # 分配堆栈空间
sw ra, 0(sp) # 保存 ra 寄存器
sw a0, 4(sp) # 保存 a0 寄存器

li a1, 1 # 加载立即数 1 到 a1
sub a0, a0, a1 # 计算 n - 1,并将结果保存在 a0

jal factorial # 递归调用 factorial 函数,将结果保存在 a0

add t0, x0, a0
# epilogue
lw a0, 4(sp) # 恢复 a0 寄存器的值
lw ra, 0(sp) # 恢复 ra 寄存器的值
addi sp, sp, 8 # 释放堆栈空间

mul a0, t0, a0 # 计算 n * (n - 1) 的结果,并保存在 a0
ret

迭代:

factoria.c

1
2
3
4
5
6
7
8
9
10
unsigned long long factorial(unsigned int a0) {
unsigned long long t1 = 1;

while (a0 != 0) {
t1 = t1 * a0;
a0 = a0 - 1;
}

return t1;
}

factoria.s

1
2
3
4
5
6
7
8
9
10
factorial:
addi t1, x0, 1
loop:
beq a0, x0, _get_out
mul t1, t1, a0
addi a0, a0, -1
jal x0, loop
_get_out:
mv a0, t1
ret

显然迭代貌似更好写

Exercise 4: Calling Convention Checker

修复约定检查器检测出的违规行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[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'.

添加了些存储sp

1
Sanity checks passed! Make sure there are no CC violations.

Exercise 5: RISC-V function calling with map

finish


cs61c-lab03
https://2333monster.github.io/2023/08/16/cs61c-lab03/
作者
John Titor
发布于
2023年8月16日
许可协议