《编译原理》学习笔记之RISC-V

728 阅读4分钟

伪指令与基本指令

伪指令就是并不是硬件实现的直接指令,只是给解释器看的,比如li

就是说向li这种指令,其实并不直接对硬件进行操作

image-20230602151643461

实际上他就是一个addi指令

加法、减法

li t0, 20	# li: load immediate 加载立即数,现在这种写法是10进制
li t1, 22
add t2, t0, t1

li t0, 32
addi t0, t0, 32 	# addi: add immediate
addi t0, t0, -16	# 没有subi指令,所以只能这样,但是sub还是有的

# f = (g + h) - (i + j)
# t6 = (t0 + t1) - (t3 + t4)
li t0, 0
li t1, 10
add t2, t0, t1
li t3, 30
li t4, 40
add t5, t3, t4
sub t6, t2, t5

系统调用

一共4步

# Step 1. Load the service number in register a7. 
# Step 2. Load argument values, if any, in a0, a1, a2, a3, fa0, ... as specified. 
# Step 3. Issue the ECALL instruction. 
# Step 4. Retrieve return values, if any, from result registers as specified.

li t0, 16
li t1, 32
add t2, t0, t1

li a7, 1	# a7存放系统调用号,此处为输出
mv a0, t2	# argument1,伪指令,实际上是add a0, zero, t2
ecall

mv其实是cp并不是会把原来的地方的数据就清空了的

.data .text

image-20230604172502658

.text就是代码指令开始的地方

.的就是写给汇编器看的,比如.data编译器就会放到.data的块的地方

.text就会放到存放代码的地方(如0x0040 0000)

.word = 4byte

.data 
g: .word 16
h: .word 48
i: .word 0
j: .word 0
result: .word 0
msg: .string "Hello world!:"	# .string会在末尾加'\0'而.ascii不会

.text
la t0, g		# load address to t0
lw t0, 0(t0)	# load word t0中的地址+偏移量0
la t1, h		# load address to t0
lw t1, 0(t1)	# load word t0中的地址+偏移量0

add t5, t0, t1

la t0, result
sw t5, 0(t0)	# t5的结果保存到t0的地址中

# la t1, msg
# li a7, 4
# mv a0, t1
# ecall

li a7, 4	# 打印字符串
la a0, msg	# 其实可以直接la到a0里面就行,不需要再经过寄存器中转了,本身就是地址
ecall

li a7, 1	# 打印数字
mv a0, t5
ecall

数组

.data
nums: .word -30, -40, -50, -60, 60, 100

.text
la t0, nums
lw t1, 8(t0)
addi t1, t1, 50
sw t1, 8(t0)	# 把-50变成了0

branch-max.asm

# 实现c = max(a,b)

.data
a: .word 100
b: .word 200
c: .word 0

.text
# la t0, a
# lw t0, 0(t0)
lw t0, a	# 该RARS支持的一个语法糖,并不是RISC-V的语法,考试应该不能用
lw t1, b

bge t0, t1, greater_equal	# t0 >= t1 就跳转到greater_equal
mv t2, t1
j end				# 伪指令, 防止再执行到greater_equal

greater_equal:
mv t2, t0

end:
la t3, c
sw t2, 0(t3)	# 存到c的地方,同样也有简便写法 sw t2, c, t3

array-index-bit.asm求一个数组正数的和与负数的和

.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 current 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	#计数器大于等于size就跳转到end_loop
# number[t2]
# mul t5, t2, 4
slli t5, t2, 2 	# 逻辑左移,即t5*4
add t5, t0, t5
lw t5, 0(t5)
addi t2, t2, 1
bltz t5, negative # bltz: branch if less than zero
add t3, t3, t5
j loop
negative:
add t4, t4, t5
j loop
end_loop:
sw, t3, positive_sum, t5
sw, t3, positive_sum, t5

proc-max.asm函数调用

.data
max_result: .word 0

.text
.global main

max:
	# a0 argument 0
	# a1 argument 1
	# 同时a0-a7的前两个寄存器也可以用来返回值的保存
    blt a0, a1, smaller
    # 没跳转说明a0 >= a1
    # mv a0, a0 正好省略不用写
    j end_max

smaller:
    mv a0, a1
    
end_max:
	ret		# 等同
	# jr ra	# 等同
    # jalr zero 0(ra) 	# jalr: jump and link register
                    	# zero的作用:jalr会将下一条指令的地址存入

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

.text
main:
    lw a0, a    # 并非risc-v的指令,而是汇编器的伪指令,将a的地址存入a0
    lw a1, b

    # jal ra, max 	# jal: jump and link  ra: Return Address register
             		# ra保存了返回地址,jal会将下一条指令的地址存入ra
    # jal max
    call max 	# 三种写法都一样
    sw a0, max_result, t0

调用函数

参数多了可以考虑用栈来传递

jalr zero 0(ra) # jalr: jump and link register
                # zero的作用:jalr会将下一条指令的地址存入

zero的作用:

jalr会做两件事情

  • 一是按照后面给的0(ra)进行跳转

  • 二是会把目前所在位置的下一条指令的地址存入给出的寄存器中,如果把zero换成t0就会保存到t0,写zero的话就表示不想存这个下一条地址(用不到),因为写到zero的东西都会被清零

proc-fact.asm递归

.text
.global main

factorial:
beqz a0, base_case  # 为0跳转,f(0) = 1

# 先改变栈指针,再保存寄存器的值,先保存参数寄存器的值,再保存ra的值
addi sp, sp, -8     # 栈空间高地址往低地址增长,所以先减8
sw a0, 4(sp)        # 先保存a0的值,即n
sw ra, 0(sp)        # 还需要再保存ra的值

# n > 0: n * f(n-1)
addi a0, a0, -1     # 此时a0为n-1
call factorial      # a0为f(n-1)
mv t0, a0			# t0:f(n-1)

lw ra, 0(sp)        # 恢复ra的值
lw a0, 4(sp)        # 恢复a0的值
addi sp, sp, 8      # 恢复栈指针

mul a0, a0, t0      # a0 = n * f(n-1)
j end               # 返回, a0还要用来保存返回值

base_case:
    li a0, 1

end:
    ret

### main ###
.data
n: .word 5

.text
main:
lw a0, n
call factorial

image-20230607153022783

注意ra的值会变