ch18-codegen-riscv-RISC-V 概述

RISC: Reduced Instruction Set Computer (精简指令集计算机)

V: Five

  • ISA是向上层提供的接口
  • cpu是ISA的硬件实现
  • 提供指令、数据类型、寄存器
  • 2017 ACM Turing Award

“RISC-V 很可能发展成为世界主流 CPU 之一, 在 CPU 领域形成 Intel、 ARM、RISC-V 三分天下的格局。” — 中国工程院院士 倪光南

如何用RISC-V写代码

只涉及32位,只涉及整数

模拟器rars

add.asm

第一列是别名,总共32个寄存器

  • x0:zero:存0,不可修改
  • x1:ra:专门存放返回地址(函数调用返回地址)
  • t0-t6:保存临时变量
  • pc:program counter,下一条指令的地址
  • RISC-V所有运算都在寄存器中

指令

  • li t0, 20 #li: load immediate
  • li t1,22
  • add t2, t0, t1 #t2 = t0 + t1
  • li是伪指令,语法糖
  • addi x5, x0, 20是基本指令

add-sub.asm

  • li t0, 0
  • li t1, 10
  • add t2, t0, t1
  • li t3, 30
  • li t4, 40
  • add t5, t3, t4
  • sub t6, t2, t5

ecall.asm 系统调用

分四步:

  • 系统调用编号存入a7
  • 准备参数
  • 调用ecall
  • 准备返回值
1
2
3
4
5
6
7
8
9
10
11
12
li t0, 0
li t1, 10
add t2, t0, t1
li t3, 30
li t4, 40
add t5, t3, t4
sub t6, t2, t5

li a7, 1
add a0, t6, zero #mov伪指令的实现
#mov a0, t6
ecall

data.asm

把数据和操作分开

  • la
  • lw
  • sw
  • a0是参数寄存器

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
.data
g: .word 0 #.word是汇编指令,一个word是4byte,half是2byte,dword是2words
#g是label,是地址的标号,可以取地址
h: .word 10
i: .word 30
j: .word 40

result: .word 0
msg: .string "the result is :" #.ascii不会自动在末尾加\0

.text
la t0, g #load address,把g所对应的地址放入t0
lw t0,0(to) #load word,从t0+0(偏移量)取值一个word大小的值放入t0,偏移量是为了数组取值
la t1, h
lw t1,0(t1)
add t2, t0, t1
la t3, i
lw t3,0(t3)
la t4, j
lw t4,0(t4)

add t5, t3, t4
sub t6, t2, t5

#往内存放数据
la t0, result
sw t6. 0(t0) #store word

#打印出来
li a7, 4
la a0, msg #a0是参数
ecall

li a7, 4
mv a0, t6
ecall

array.asm

1
2
3
4
5
6
7
8
9
.data
numbers: .word -30, 30, -20, 20, -10, 10, 0

.text
#修改一个值20:3 * 4偏移12byte
la t0, numbers
lw t1, 12(t0)
addi t1, t1, 80
sw t1, 12(t0)

branch-max.asm

  • j:无条件跳转,伪指令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.data
a: .word 100
b: .word 200
c: .word 0

.text
la t0, a
lw t0, 0(t0)
la t0, b
lw t0, 0(t0)

bge t0, t1, greater_equal #如果t0 >= t1,就跳转到greater_equal标签
#t0 < t1
mv t2, t1
j end #j:"jump"

greater_equal:
mv t2, t0 #用t2保存最大值

end:
la t3, c
sw t2, 0(t3) #存入c

for.asm

  • slli
  • bltz
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
.data
numbers: .word -30, 30, -20, 20, -10, 10, 0
size: .word 7

positive_sum: .word 0
negative_sum: .word 0

.text
la t0, numbers #t0: the address of the array数组首地址
lw t1, size

mv t2, zero #counter ,initially 0

li t3, 0 #t3: sum of positive numbers <- 0
li t4, 0 #t4: sum of negative numbers <- 0

loop:
bge t2, t1, end_loop
#numbers[t2]
# mul t5, t2, 4 #t5= t2 * 4
# t2向左移两位
slli t5, t2, 2 #slli:shift left logic immediate
add t5, t0. t5
lw t5, 0(t5) #t5中为当前访问的值

addi t2, t2, 1

bltz t5, negative #branch if less than zero
add t3, t3, t5
j loop

negative:
add t4, t4, t5
j loop
end_loop:
la t5, positive_sum
sw t3, 0(t5)
la t5, negative_sum
sw t4, 0(t5)

proc-max.asm函数调用

  • jal
  • a0, a1同时用作返回值和传参
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
.data
max_result: .word 0

.text
.global main

max:
blt a0, a1, smaller #a0 < a1
j end_max

smaller:
mv a0, a1

end_max:

ret
#jalr ra
#jalr zero 0(ra) #jalr : jump and link reister 根据ra保存的地址,跳转到ra所在地址,同时不关心这条指令的下一条指令的地址,所以扔掉到zero里

####### main #########
.data
a: .word 100
b: .word 200

.text
main:
#先准备好参数,传入a0-a7,再call
lw a0, a
lw a1, b

call max
#jal max
#jal ra, max #jal: jump and link, ra专门存返回地址,转移控制权,保存返回地址
#ra放了max的返回值
sw a0, max_result, t0


proc-fact.asm递归

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
.text
.global main
factorial:
beqz a0, base_case

#stack high->low
#sp stack pointer
addi sp, sp, -8 #入栈保护
sw a0, -4(sp)
sw ra, 0(sp)

# n > 0: n * factorial(n - 1)
addi a0, a0, -1 #a0 = n - 1
call factorial #a0 : factorial(n - 1)
mv t0, a0 #t0: factorial(n - 1)

lw a0, 4(sp) #a0 = n = stack[sp + 4]
lw ra, 0(sp) #ra = stack[sp]
addi sp, sp, 8 #栈清空

mul a0, a0, t0 #a0 = n * factorial(n - 1)
j end

base_case:
li a0, 1
end:
ret

######## main ############
.data
a: .word 10

.text
main:
lw a0, n
call factorial


bubblesort

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
/* Type your code here, or load an example. */
int square(int num) {
return num * num;
}
#include <stdio.h>

int numbers[] = {20, 3, 56, 8, 90};
int size = 5;

void Sort(int v[], int n);
void Swap(int v[], int k);
void Print(int v[], int n);

int main() {
Sort(numbers, size);
}

void Sort(int v[], int n) {
for (int i = 0; i < n; i++) {
for (int j = i - 1; j >= 0 && v[j] > v[j + 1]; j--) {
Swap(v, j);
}
}
}

void Swap(int v[], int k) {
int temp;
temp = v[k];
v[k] = v[k + 1];
v[k + 1] = temp;
}

void Print(int v[], int n) {
for (int i = 0; i < n; i++) {
printf("%d\n", v[i]);
}
}

asm

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
square:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov eax, DWORD PTR [rbp-4]
imul eax, eax
pop rbp
ret
numbers:
.long 20
.long 3
.long 56
.long 8
.long 90
size:
.long 5
main:
push rbp
mov rbp, rsp
mov eax, DWORD PTR size[rip]
mov esi, eax
mov edi, OFFSET FLAT:numbers
call Sort
mov eax, 0
pop rbp
ret
Sort:
push rbp
mov rbp, rsp
sub rsp, 32
mov QWORD PTR [rbp-24], rdi
mov DWORD PTR [rbp-28], esi
mov DWORD PTR [rbp-4], 0
jmp .L6
.L10:
mov eax, DWORD PTR [rbp-4]
sub eax, 1
mov DWORD PTR [rbp-8], eax
jmp .L7
.L9:
mov edx, DWORD PTR [rbp-8]
mov rax, QWORD PTR [rbp-24]
mov esi, edx
mov rdi, rax
call Swap
sub DWORD PTR [rbp-8], 1
.L7:
cmp DWORD PTR [rbp-8], 0
js .L8
mov eax, DWORD PTR [rbp-8]
cdqe
lea rdx, [0+rax*4]
mov rax, QWORD PTR [rbp-24]
add rax, rdx
mov edx, DWORD PTR [rax]
mov eax, DWORD PTR [rbp-8]
cdqe
add rax, 1
lea rcx, [0+rax*4]
mov rax, QWORD PTR [rbp-24]
add rax, rcx
mov eax, DWORD PTR [rax]
cmp edx, eax
jg .L9
.L8:
add DWORD PTR [rbp-4], 1
.L6:
mov eax, DWORD PTR [rbp-4]
cmp eax, DWORD PTR [rbp-28]
jl .L10
nop
nop
leave
ret
Swap:
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-24], rdi
mov DWORD PTR [rbp-28], esi
mov eax, DWORD PTR [rbp-28]
cdqe
lea rdx, [0+rax*4]
mov rax, QWORD PTR [rbp-24]
add rax, rdx
mov eax, DWORD PTR [rax]
mov DWORD PTR [rbp-4], eax
mov eax, DWORD PTR [rbp-28]
cdqe
add rax, 1
lea rdx, [0+rax*4]
mov rax, QWORD PTR [rbp-24]
add rax, rdx
mov edx, DWORD PTR [rbp-28]
movsx rdx, edx
lea rcx, [0+rdx*4]
mov rdx, QWORD PTR [rbp-24]
add rdx, rcx
mov eax, DWORD PTR [rax]
mov DWORD PTR [rdx], eax
mov eax, DWORD PTR [rbp-28]
cdqe
add rax, 1
lea rdx, [0+rax*4]
mov rax, QWORD PTR [rbp-24]
add rdx, rax
mov eax, DWORD PTR [rbp-4]
mov DWORD PTR [rdx], eax
nop
pop rbp
ret
.LC0:
.string "%d\n"
Print:
push rbp
mov rbp, rsp
sub rsp, 32
mov QWORD PTR [rbp-24], rdi
mov DWORD PTR [rbp-28], esi
mov DWORD PTR [rbp-4], 0
jmp .L13
.L14:
mov eax, DWORD PTR [rbp-4]
cdqe
lea rdx, [0+rax*4]
mov rax, QWORD PTR [rbp-24]
add rax, rdx
mov eax, DWORD PTR [rax]
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
add DWORD PTR [rbp-4], 1
.L13:
mov eax, DWORD PTR [rbp-4]
cmp eax, DWORD PTR [rbp-28]
jl .L14
nop
nop
leave
ret