0%

计算机组成原理自学笔记

更新中... ...

资料来源:ChatGPT、课件

一. 汇编

  • 在线RISC-V汇编编写网站:venus

  • 更多指令细节请参考:CS 61C Reference Card

  • RISC-V的大部分指令长度固定,为32位。每条指令都是由32个0/1序列组成。

  • 寄存器:RISC-V中,寄存器是处理器内部用于存储数据的小存储单元。它们可以非常快速地被访问和写入,比起访问主内存来说速度要快得多。

  • RISC-V定义了一组32个通用寄存器,编号从0到31。在代码中就是x0, x1, x2, ..., x31。

  1. R(register)型指令:操作寄存器操作的指令

    • 格式:
    • opcode操作码,rd目标寄存器号,rs1/rs2第一/二个源寄存器号,funct3附加操作码,funct7附加操作码。
    • add x3, x1, x2(+)
    • sub x3, x1, x2(-)
    • and x3, x1, x2(&)
    • or x3, x1, x2(|)
    • xor x3, x1, x2(^)
  2. I(immediate)型指令:寄存器与常数操作的指令

    • 格式:
    • immediate立即数。
    • addi x1, x2, 10
    • slti x1, x2, 15:如果x2小于15,将x1设置位1。否则设置为0
    • andi x1, x2, 0xFF:寄存器与常数进行&操作
    • ori x1, x2, 0xFF
    • xori x1, x2, 0xFF
    • slli x1, x2, 2(将x2右移2位结果存到x1中)
    • ld x1, 0(x5):从内存地址 x5+0 处加载 64 位的值到 x10
  3. S(store)型指令:寄存器与内存操作的指令

    • 格式:
    • rs1访存基址寄存器编号,r2源操作数寄存器编号,imm立即数(表示从基址开始的偏移量。
    • sw x1, 10(x2):将x1内容存储到x2为基址,偏移量为10的内存地址中
  4. B(branch)型指令:程序的有条件跳转指令

    • 格式:
    • imm立即数:表示要跳转的语句的地址。
    • beq x1, x2, label:如果x1==x2,程序跳转到label处
    • blt(Branch less than) x1, x2, label:如果x1 < x2,程序跳转到label处
    • bgt(Branch greater than) x1, x2, label:如果x1 > x2,程序跳转到label处
    • bgtz(Branch greater than zero) x1 label:如果x1大于0,程序跳转到label处
    • bgez(Branch greater or equal to zero) x1 label:如果x1大于等于0,程序跳转到label处
  5. J(jump)型指令:程序的无条件跳转指令

    • 格式:
    • 也可以叫UJ(Unconditional Jump)指令。
    • jr rd:跳转到rd寄存器存的地址那里
    • jal x1, offset:跳转到当前指令地址加上offset的位置,并将下一条指令的地址存入x1中
  6. U(upper immediate)型指令:将20位立即数加载到寄存器的高位

    • 格式:
    • lui x1 imm:将20位立即数imm加载到x1的高20位,低12位清零
  • 练习题:写一个斐波那契数列程序
1
2
3
4
5
6
7
8
int fib(int n) {
if (n==0)
return 0;
else if(n==1)
return 1;
else
return fib(n-1)+fib(n-2);
}
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
fib:
addi sp, sp, -16 # 开辟16字节的栈空间
sw ra, 0(sp) # 保存函数地址
sw a0, 4(sp) # 保存参数n, a0 = n

addi t0, x0, 2 # t0 = 2
blt a0, t0, less_or_equal_than_one # 如果n <= 1,直接返回n

addi a0, a0, -1 # a0 = n - 1
jal ra, fib # 执行fib(n - 1)
add t1, a0, x0 #fib(n - 1)的结果存到t1
sw t1, 8(sp) # 将结果存到栈中

lw a0, 4(sp) # 恢复参数n, a0 = n
addi a0, a0, -2 # a0 = n - 2
jal ra, fib # 执行fib(n - 2)
add t2, a0, x0 #fib(n - 2)的结果存到t2
sw t2, 12(sp) # 将结果存到栈中

lw t1, 8(sp) # 重新把结果读到t1
lw t2, 12(sp) # 重新把结果读到t2

add a0, t1, t2 # a1 = fib(n - 1) + fib(n - 2)
lw ra, 0(sp) # 恢复当前fib的返回地址
addi sp, sp, 16 # 恢复栈空间
jr ra # 返回到调用fib函数的地方

less_or_equal_than_one:
addi sp, sp, 16 # 栈空间恢复
add a0, a0, x0 # a1 = n
jr ra # 返回