计组学习07——RISC-V Instruction Formats
计组学习 —— RISC-V Instruction Formats
存储式程序的概念
指令也同样作为数据,存储在内存里,只是对二进制的解释方式不同。
RISC-V的指令都是,一条指令占4字节,32位
- 把32位的指令划分为区间
- 之后定义六种指令格式
- R-Format
- I-Format
- S-Format
- U-Format
- SB-Format
- UJ-Format
我们希望把32位分成一切区间,并且我们希望这些区间处于固定位置,
比如我们想要目标寄存器总是在某些bit里,这会让硬件工作容易很多,因为如果是这样,硬件就可以以相同的方式来解释不同的指令
注意,jal是UJ格式,UJ格式也只有jal,jalr是I格式的
R格式
- opcode(7): 特定的操作码,用于区分这是哪类指令
- 比如,R类型是: 0b011011
- SB类型是: 0b1100011
- funct7 + funct3 两个字段组合到一起用来表明我们要执行的操作,比操作码更为详细
所以我们最后可能组合成210种R操作码!
- rs1,rs2:寄存器1,寄存器2
- rd:储存结果的寄存器
为什么我们rs,rd都要用5位表示呢?
——因为我们有32个寄存器!5个二进制数刚好表示0-31!
如果我们想做其他R操作,我们只需要改变funct7和funct3的位置的数就可以了
I格式
-
可以发现,只有imm的部分组成是与R格式不同的,我们把rs2和funct7的部分换成了12位的imm
-
可以发现imm只有12位,但是我们往往进行符号拓展
为什么移位的指令只需要5位的shamt呢?
因为我们的位只有32位,5位可以表示0-31,什么东西移动超过32位就没有意义了,本来就只有32位。
Jalr
jalr rd,rs1,offset
- 会把PC+4写入到rd中(return address)
- 把pc设置为 rs1+offset
- 和逻辑运算或者加载数据使用同样格式的immediate
- 没有二字节的乘法
如果想要jalr跳转到一个绝对的32位数,我们可以这样做:
lui x1,<high 20 bits>
jalr ra,x1,<low 12 bits>
Load Instructions are alse I-TYPE
这是两种的对比:
所有的Load Instruction列表:
- 这里没有LWU,原因在之前已经说过了
S格式
S型存储除了rs1,rs2以外,也需要immediate的偏移量!
但是我们在刚刚的学习中认识到,不可能同时存在rs2和immediate呀!要不然根本放不到一个位置
该怎么解决呢.....?
我们发现,我们不需要把结果输出到寄存器里,所以我们不需要rd!
SB-Format
-
和之前的相同,但是这里涉及到偏移值的计算,一行指令占4个字节
-
如果改变了代码!那么有可能我们需要重新计算分支跳转的偏移量
-
如果下一条指令距离太远了怎么办?
- 可以连续跳转两次,跳转到一个跳转语句
U格式
-
我们该怎么处理一个32位的immediate呢?
- 我们的 I 指令只能处理12位的立即数
-
所以!我们需要另一种格式来处理剩下的20位
-
只有LUI 和 AUIPC可以使用这样的imm!
lui是把一个20位的数左移12位,那么如何得到一个大数字呢?例如0xDEADBEEF
lui x10, 0xDEADC
addi x10, x10, 0xEEF
只要这样组合起来,先移动!后面12位交给addi就可以了!
AUIPC (add upper immediate value to PC)
基本这是我们唯一能获取到关于PC的指令了!