本文目标
RV32I 是 32-bit 的基本整数指令集,该指令集会使用到 32 个暂存器 (x0-x31),且一共有 47 道指令,RV32I 的指令一共可分成六大类:
为了方便, RISC-V 将一个 WORD 的大小设成 4 Bytes (32 bits) ,同时, RISC-V 的指令长度也是 32 bits,这些空间会被分割成好几个 fields,不同类型的指令都会有不同的分配方式。
这种类型的指令代表暂存器与常数之间的运算:
| 31 20 | 19 15 | 14 12 | 11 07 | 06 00 |
+----------------------+---------+------------+--------+------------+
| immediate[11:0] | rs1 | funct3 | rd | opcode |
+----------------------+---------+------------+--------+------------+
addi rd, rs1, simm12
常数部分为 (simm12) 为 12 位元的有号数,运算时会将 12 位元扩展成 32 位元,与 rs1 暂存器做加法运算并将结果写进 rd 暂存器中。
关於 simm12 扩展的逻辑,我们可以参考 rv32emu-next 的实作:
// FI_IMM_11_0 = 0b11111111111100000000000000000000 static inline int32_t dec_itype_imm(uint32_t inst){ return ((int32_t)(inst & FI_IMM_11_0)) >> 20; }
slti rd, rs1, simm12
运算时会将 12 位元扩展成 32 位元,再与 rs1 暂存器当做 signed number 做比较(如果指令为 SLTIU
则视为无号数),若 rs 暂存器 1 小於常数,则将数值 1 写入 rd 暂存器,否则为 0 。
补充
本篇文章的 simm[number] 代表有号的 number 个位元,若是 uimm[number] 则代表无号的 number 个位元。
若出现在下方指令,就不再特别说明。
andi/ori/xori rd, rs1, simm12
将 simm12 扩展後与 rs1暂存器做 AND / OR / XOR 运算,再将结果写入 rd 暂存器中。
slli/srli/srai rd, rs1, uimm5
常数部分为 unsigned 5 bits,将 rs1 暂存器做 shift 运算,偏移量为 uimm5 的值 (0 - 31),偏移後的结果会写入 rd 暂存器。
lw/lh/lhu/lb/lbu rd, rs1, simm12
将 rs1 暂存器的内容加上 simm12 视为地址,并将该地址存放的值放到 rd 中。
包含 upper immediates 的指令
lui rd, uimm20
将 uimm20 存放到 rd 暂存器的高位 20 bits 中,剩余的 12 bits 皆为 0 。
auipc rd, uimm20
unsigned 20-bit放到最高 20位元,剩余 12位元补0,将此数值与 pc相加写入 rd暂存器。
指令为暂存器与暂存器之间的运算
add/sub rd, rs1, rs2
将 rs1 与 rs2 做加法/减法运算後,再将结果写入 rd暂存器。
slt/sltu rd, rs1, rs2
将 rs1 与 rs2 暂存器当做有号或是无号数做比较,若 rs1 小於 rs2 ,将数值 1 写入 rd ,反之写入 0 。
and/or/xor rd, rs1, rs2
将 rs1 与 rs2 做 AND/OR/XOR 运算,并将结果写入 rd 中。
sll/srl/sra rd, rs1,, rs2
将 rs1 做 shift 运算,再将结果写入 rd 暂存器,rs2 的最低 5 位为代表位移量。
NOP 指令即为不改变任何暂存器状态,除了 pc 以外。
NOP 指令会被编码成 addi x0, x0, 0
替代。
UJ-Format 包含了无条件跳跃 (Unconditional Jumps) 类型的指令。
jal rd, simm21
常数部分为 21 位元的有号数(此常数必须为 2 的倍数,代表 LSB 必为 0 ),因为此道指令编码的常数位元数只有 20位元,所以只会将 simm21 的最高 20 位元放入指令编码中,跳跃范围为 -+1MiB ,同时也会将下一道指令的位址 pc+4 写入 rd 暂存器中,在标准的 calling convention 中,rd 暂存器会使用 x1 。如果只是单纯的 jump,并非是呼叫函示需要储存其返回位址 pc+4,可用 jal x0, simm21 取代。
jalr rd, rs1, simm12
跳跃的位址为 rs暂存器加上 simm12 ,并把下一道指令的位址 pc+4 写入 rd 暂存器中。
SB-Format 包含了条件跳跃 (Conditional Branches) 类型的指令。
beq/bne/blt/bltu/bge/bgeu rs1, rs2, simm13
常数部分必须为 2的倍数,即最低位元为 0 ,因为此道指令编码的常数位元数只有 12 位元,所以只会将 simm13 的最高 12 位元放入指令编码中,跳跃范围为 -+4Kib 。
将内容存放到记忆体中的指令。
sw/sh/sb rs2, rs1, simm12
将 rs1 暂存器的内容加上 simm12 视为地址,并将 rs2 的资料写到该地址中。
定义了一组 FENCE 指令,达到多个 thread 间的记忆体同步。
CSRRW / CSRRS / CSRRC / CSRRWI / CSRRSI / CSRRCI
定义了一组 CSR指令,可用来读取写入 CSR。
rdcycle 用来读取最低 31-bit cycle CSR , rdcycleh 用来读取最高 31-bit cycle 数。
用来读取 time CSR 。
用来读取 instret CSR 。
属於 I-Type。
使用来呼叫 system call。
Debugger 用来切换进 Debugging 环境。
>>: 不只懂 Vue 语法:如何使用 v-model 实现父子元件传递资料?
什麽是 DNS DNS 全称 Domain Name System 中文为「网域名称系统」, 可视为...
介绍: k-平均演算法(英文:k-means clustering,以下简称为 k-means )是...
如果一件事情够重要,那麽即便所有条件都与你作对,你仍应该要做。 If something is im...
今天试着全用Figma做一个UI设计,无论是插图或是icon都是在Figma内画出来,Figma的画...
一样要说明这是由彭彭影片撷取出来的例题 <!DOCTYPE html> <html...