本节笔记中使用到的RISC-V指令表格样式来自@TonyCrane:fontawesome-brands-github:
Introduction
-
Language of the machine
- Instructions(指令)
- Instruction set(指令集)
-
Computer Designer goals
- Find a language that makes it easy to build hardware and compiler.(简单易用)
- Maximize performance(同样的资源性能更好)
- Minimize cost & energy (同样的性能成本更低)
- Clarity of its application (易用)
- Simplicity: reduce design time (便于设计)
Our chosen instruction set: RISC V
各种指令集的区别

Von Neumann’ Computer
如今的计算机是基于两个核心原理构建的:存储程序概念。 这两个原理分别是:
- 指令被表示为数字;
- 程序可以像数字一样存储在内存中,以便读取或写入。
四个设计理念:
- Simplicity favors regularity 指令集的设计应该尽可能简单,规则。
- Smaller is faster 尽可能减少指令集的大小,以便提高速度。
- Good design demands good compromises 设计指令集时,需要权衡各种因素。
- Make the common case fast 优化常见情况的执行速度。
当设计ISA时,需要硬件简单--让芯片只实现基本的原语并能快速运行,指令要规整
Instruction characteristics
指令集的基本结构
operator+operands

不同的操作系统,字的长度不同,比如32位系统,字长为32位(4 Byte),64位系统,字长为64位(8 Byte)。
边界对齐送地址,最后两位是00
RISC-V 指令集
| 寄存器 | ABI 名称 | 用途描述 | saver |
|---|---|---|---|
| x0 | zero | 硬件 0 | |
| x1 | ra | 返回地址(return address) | caller |
| x2 | sp | 栈指针(stack pointer) | callee |
| x3 | gp | 全局指针(global pointer) | |
| x4 | tp | 线程指针(thread pointer) | |
| x5 | t0 | 临时变量/备用链接寄存器(alternate link reg) | caller |
| x6-7 | t1-2 | 临时变量 | caller |
| x8 | s0/fp | 需要保存的寄存器/帧指针(frame pointer) | callee |
| x9 | s1 | 需要保存的寄存器 | callee |
| x10-11 | a0-1 | 函数参数/返回值 | caller |
| x12-17 | a2-7 | 函数参数 | caller |
| x18-27 | s2-11 | 需要保存的寄存器 | callee |
| x28-31 | t3-6 | 临时变量 | caller |
在riscv代码中,当进行函数调用时,需要考虑caller save和callee save;
所谓caller save,就是指在函数调用时,调用者需要保存自己的寄存器,一般是参数还有返回值;
所谓callee save,就是指在函数调用时,被调用者需要保存某些重要寄存器里面的值,比如x8-11这些寄存器;
caller需要保证调用子函数时,x1,x5,x6-7,a0-7寄存器可以被子函数使用;
callee需要保证调用结束后,x8-11寄存器里面的值不会改变;
保存的方法是使用堆栈
addi sp, sp, -8
sw x1, 4(sp)
sw x2, 0(sp) #push
...
...
lw x2, 0(sp)
lw x1, 4(sp) #pop
sp始终指向栈顶
R-type指令是指令集中的一种类型,它们的操作码字段是固定的,而剩余的字段则根据指令的具体功能而变化。R-type指令通常用于执行算术运算和逻辑运算等操作;R-type指令的格式如下所示:
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| funct7 | rs2 | rs1 | funct3 | rd | opcode | ||||||||||||||||||||||||||
rd = rs1 op rs2,有时候rs1,rs2,又称为rs,rt
R-type指令
| Instruction | Name | Meaning |
|---|---|---|
| ADD | Addition | Adds two values and stores the result in the destination register. |
| SUB | Subtraction | Subtracts the second value from the first and stores the result in the destination register. |
| SLT | Set Less Than | Sets the destination register to 1 if the first value is less than the second (signed), otherwise sets to 0. |
| SLTU | Set Less Than Unsigned | Sets the destination register to 1 if the first value is less than the second (unsigned), otherwise sets to 0. |
| AND | Logical AND | Performs a bitwise AND operation between two values and stores the result in the destination register. |
| OR | Logical OR | Performs a bitwise OR operation between two values and stores the result in the destination register. |
| XOR | Logical XOR | Performs a bitwise XOR (exclusive OR) operation between two values and stores the result. |
| SLL | Shift Left Logical | Shifts the bits of the first value to the left by the number of positions specified by the second value, filling with zeros. |
| SRL | Shift Right Logical | Shifts the bits of the first value to the right by the number of positions specified, filling with zeros. |
| SRA | Shift Right Arithmetic | Shifts the bits of the first value to the right by the number of positions specified, maintaining the sign bit. |
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0000000 | rs2 | rs1 | 000 | rd | 0110011 | ||||||||||||||||||||||||||
- 使用格式
ADD rd,rs1,rs2rd = rs1 + rs2 - 溢出将会被忽略
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0100000 | rs2 | rs1 | 000 | rd | 0110011 | ||||||||||||||||||||||||||
- 使用格式
SUB rd,rs1,rs2rd = rs1 - rs2 - 溢出将会被忽略
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0000000 | rs2 | rs1 | 010 | rd | 0110011 | ||||||||||||||||||||||||||
- 使用格式
SLT rd,rs1,rs2rd = ($signed(rs1) < $signed(rs2)) ? 1 : 0 - 有符号数的比较
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0000000 | rs2 | rs1 | 011 | rd | 0110011 | ||||||||||||||||||||||||||
- 使用格式
SLTU rd,rs1,rs2rd = (rs1 < rs2) ? 1 : 0 - 进行无符号数的比较
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0000000 | rs2 | rs1 | 111 | rd | 0110011 | ||||||||||||||||||||||||||
- 使用格式
AND rd,rs1,rs2rd = rs1 & rs2 - 按位的与操作
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0000000 | rs2 | rs1 | 110 | rd | 0110011 | ||||||||||||||||||||||||||
- 使用格式
OR rd,rs1,rs2rd = rs1 | rs2 - 执行按位或操作
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0000000 | rs2 | rs1 | 100 | rd | 0110011 | ||||||||||||||||||||||||||
- 使用格式
XOR rd,rs1,rs2rd = rs1 ^ rs2 - 执行按位异或操作
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0000000 | rs2 | rs1 | 001 | rd | 0110011 | ||||||||||||||||||||||||||
- 使用格式
SLL rd,rs1,rs2rd = rs1 << rs2[4:0] - 逻辑左移
- 取
rs2的低五位进行运算
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0000000 | rs2 | rs1 | 101 | rd | 0110011 | ||||||||||||||||||||||||||
- 指令格式:
srl rd,rs1,rs2,rd=rs1>>rs2[4:0] - 取
rs2的低5位
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0100000 | rs2 | rs1 | 101 | rd | 0110011 | ||||||||||||||||||||||||||
- 指令格式
sra rd,rs1,rs2;rd = $signed(rs1) >>> rs2[4:0] - 算数右移,高位补符号位(为什么没有算数左移,因为没意义)
使用寄存器和立即数进行数字逻辑运算,以及 load 类指令等的指令格式如下:
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | funct3 | rd | opcode | |||||||||||||||||||||||||||
立即数为
imm={{20{inst[31]}}, inst[31:20]}
即将立即数的最高位符号位进行扩展到32位
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | 000 | rd | 0010011 | |||||||||||||||||||||||||||
- 指令格式:
addi rd, rs1, immrd = rs1 + imm imm范围为12位有符号数字-2048~2047
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | 010 | rd | 0010011 | |||||||||||||||||||||||||||
- 使用格式
slti rd,rs1,immrd = ($signed(rs1) < $signed(imm)) ? 1 : 0 - 有符号数的比较
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | 011 | rd | 0010011 | |||||||||||||||||||||||||||
- 使用格式
sltiu rd,rs1,immrd = (rs1 < imm) ? 1 : 0 - 进行无符号数的比较,
rs1和imm都是无符号数
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | 111 | rd | 0010011 | |||||||||||||||||||||||||||
- 使用格式
andi rd,rs1,immrd = rs1 & imm imm范围在-2048~2047,位数不够时会扩展符号位
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | 110 | rd | 0010011 | |||||||||||||||||||||||||||
- 使用格式
ori rd,rs1,immrd = rs1 | imm imm范围在-2048~2047,位数不够时会扩展符号位
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | 100 | rd | 0010011 | |||||||||||||||||||||||||||
- 使用格式
xori rd,rs1,immrd = rs1 ^ imm imm范围在-2048~2047,位数不够时会扩展符号位- 需要注意的是
xori rd,rs1,-1等价于与全1异或:rd=~rs1
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0000000 | shamt | rs1 | 001 | rd | 0010011 | ||||||||||||||||||||||||||
- 使用格式
slli rd,rs1,shamtrd = rs1 << shamt - 逻辑左移
shmat在原来rs2的位置上,为五位立即数;此时空出来相当于原来的func7
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0000000 | shamt | rs1 | 101 | rd | 0010011 | ||||||||||||||||||||||||||
- 使用格式
srli rd,rs1,shamtrd = rs1 >> shamt - 逻辑右移
shmat在原来rs2的位置上,为五位立即数;此时空出来相当于原来的func7
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| 0100000 | shamt | rs1 | 101 | rd | 0010011 | ||||||||||||||||||||||||||
- 使用格式
srai rd,rs1,shamtrd = $signed(rs1) >>> shamt - 算数右移,高位补符号位
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | 000 | rd | 1100111 | |||||||||||||||||||||||||||
- 使用格式
jalr rd,rs1,immrd = pc+4; pc = (rs1 + imm) & ~1,即最低位为0 - 可以实现任意位置的跳转
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | 000 | rd | 0000011 | |||||||||||||||||||||||||||
- 使用格式
lb rd,imm(rs1)rd = {{24M[rs1+imm][7]},M[rs1 + imm][7:0]} - 从内存的
rs1+imm地址处读取一个字节的数据,符号扩展到32位,存到rd中
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | 001 | rd | 0000011 | |||||||||||||||||||||||||||
-
使用格式
lh rd,imm(rs1)rd = {{16M[rs1+imm][15]},M[rs1 + imm][15:0]} -
从内存的
rs1+imm地址处读取一个半字的数据,存到rd的低16位,符号扩展到32位
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | 010 | rd | 0000011 | |||||||||||||||||||||||||||
- 使用格式
lw rd,imm(rs1)rd = M[rs1 + imm] - 从内存的
rs1+imm地址处读取一个字的数据,存到rd中
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | 100 | rd | 0000011 | |||||||||||||||||||||||||||
- 使用格式
lbu rd,imm(rs1)`rd = M[rs1 + imm][7:0] - 从内存的
rs1+imm地址处读取一个字节的数据,零扩展到32位,存到rd中(高位全0)
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| imm[11:0] | rs1 | 101 | rd | 0000011 | |||||||||||||||||||||||||||
- 使用格式
lhu rd,imm(rs1)rd = M[rs1 + imm][15:0] - 从内存的
rs1+imm地址处读取一个半字的数据,零扩展到32位,存到rd中(高位全0)
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| 000000000000 | 00000 | 000 | 00000 | 1110011 | |||||||||||||||||||||||||||
| 31 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||
| 000000000001 | 00000 | 000 | 00000 | 1110011 | |||||||||||||||||||||||||||
store 类指令,将寄存器中的数据存储到内存中,存储的大小由func3决定,没有rd寄存器
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode | ||||||||||||||||||||||||||
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| imm[11:5] | rs2 | rs1 | 000 | imm[4:0] | 0100011 | ||||||||||||||||||||||||||
- 使用格式
sb rs2,imm(rs1)M[rs1 + imm] = rs2[7:0] - 将
rs2的低8位存到内存的rs1+imm地址处
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| imm[11:5] | rs2 | rs1 | 001 | imm[4:0] | 0100011 | ||||||||||||||||||||||||||
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| imm[11:5] | rs2 | rs1 | 010 | imm[4:0] | 0100011 | ||||||||||||||||||||||||||
- 使用格式
sw rs2,imm(rs1)M[rs1 + imm] = rs2 - 将
rs2存到内存的rs1+imm地址处
在RISC-V指令集中,B型(B-type)指令用于条件分支,根据比较结果决定是否跳转到指定的偏移地址。B型指令通常包含两个寄存器进行比较以及一个立即数偏移量(表示跳转的距离)。
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| imm[12,10:5] | rs2 | rs1 | funct3 | imm[4:1,11] | opcode | ||||||||||||||||||||||||||
立即数为
imm={{19{inst[31]}}, inst[31], inst[7], inst[30:25], inst[11:8], 1'b0}
最低位为0,不存;扩展到imm[12]位;将13位拼接完后,剩下高19位用inst[31]符号位填充,此时imm[11]可以不是符号位;imm[12]是符号位
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| imm[12,10:5] | rs2 | rs1 | 000 | imm[4:1,11] | 1100011 | ||||||||||||||||||||||||||
- 使用格式:
beq rs1,rs2,immif(rs1 == rs2) pc = pc + imm - 可以跳转到的位置,即
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| imm[12,10:5] | rs2 | rs1 | 001 | imm[4:1,11] | 1100011 | ||||||||||||||||||||||||||
- 使用格式:
bne rs1,rs2,immif(rs1 != rs2) pc = pc + imm - 可以跳转到的位置,即
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| imm[12,10:5] | rs2 | rs1 | 100 | imm[4:1,11] | 1100011 | ||||||||||||||||||||||||||
- 使用格式:
blt rs1,rs2,immif($signed(rs1) < $signed(rs2)) pc = pc + imm - 有符号数
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| imm[12,10:5] | rs2 | rs1 | 101 | imm[4:1,11] | 1100011 | ||||||||||||||||||||||||||
- 使用格式:
bge rs1,rs2,immif($signed(rs1) >= $signed(rs2)) pc = pc + imm - 有符号数
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| imm[12,10:5] | rs2 | rs1 | 110 | imm[4:1,11] | 1100011 | ||||||||||||||||||||||||||
- 使用格式:
bltu rs1,rs2,immif(rs1 < rs2) pc = pc + imm - 无符号数比较
| 31 | 25 | 24 | 20 | 19 | 15 | 14 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||
| imm[12,10:5] | rs2 | rs1 | 111 | imm[4:1,11] | 1100011 | ||||||||||||||||||||||||||
- 使用格式:
bgeu rs1,rs2,immif(rs1 >= rs2) pc = pc + imm - 无符号数比较
| 31 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||||||
| imm[31:12] | rd | opcode | |||||||||||||||||||||||||||||
没有源操作数,只有目的操作数,立即数为
imm={inst[31:12], 12'b0}
| 31 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||||||
| imm[31:12] | rd | 0110111 | |||||||||||||||||||||||||||||
- 使用格式
lui rd,immrd = imm << 12 - 将
imm位存入rd高20位 imm不能超过20位
| 31 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||||||
| imm[31:12] | rd | 0010111 | |||||||||||||||||||||||||||||
- 使用格式
auipc rd,immrd = pc + imm << 12 - aupic意思是add upper immediate to pc,将imm 加载到高 20 位,然后加上 pc 值
imm不能超过20位
| 31 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||||||
| imm[20,10:1,11,19:12] | rd | opcode | |||||||||||||||||||||||||||||
立即数为
imm={{11{inst[31]}}, inst[31], inst[19:12], inst[20], inst[30:21], 1'b0}
imm最低位0不存,此时imm[20]是符号位,imm相当于21位有符号数
,跳转范围是
| 31 | 12 | 11 | 7 | 6 | 0 | ||||||||||||||||||||||||||
| imm[20,10:1,11,19:12] | rd | 1101111 | |||||||||||||||||||||||||||||
- 使用格式
jal rd,immrd = pc + 4; pc = pc + imm - 将
pc+4存入rd,然后跳转到pc+imm处 - Jal指令的跳转范围是,即
