RV32I指令集
RV32I是最基本的32位Base指令集,它支持32位寻址空间,支持字节地址访问,仅支持小端格式(little-endian,高地址高位,低地址地位),寄存器也是32位整数寄存器。RV32I指令集的目的是尽量简化硬件的实施设计,所以它只有47条指令。
在RV32I指令集架构中,包括32个通用目的寄存器,其中x0被预留为常数0,其它31个寄存器(x1-x31)是普通的通用整数寄存器。在Risc-V汇编语言中,每个通用寄存器都有一个对应的ABI名字,也就是说在汇编语言中,x1等价于ra,它们都会编译成相同的机器码。
在Risc-V架构中,要得到当前指令pc(指令在存储器中的位置,instruction program counter),可以通过AUIPC指令,把它读入到一个通用寄存器中。
寄存器 | ABI名字(别名) | 注释 | Saver |
x0 | zero | Hard-wired zero,常数0 | |
x1 | ra | Return address | caller,调用函数的指令pc |
x2 | sp | Stack pointer | callee,被调用的函数指令pc |
x3 | gp | Global pointer | |
x4 | tp | Thread pointer | |
x5 | t0 | Temporary/alternate link register | caller |
x6 | t1 | Temporaries | caller |
x7 | t2 | Temporaries | caller |
x8 | s0/fp | Saved register/frame pointer | caller |
x9 | s1 | Saved register | caller |
x10 | a0 | Function arguments/return values | caller |
x11 | a1 | Function arguments/return values | caller |
x12 | a2 | Function arguments | caller |
x13 | a3 | Function arguments | caller |
x14 | a4 | Function arguments | caller |
x15 | a5 | Function arguments | caller |
x16 | a6 | Function arguments | caller |
x17 | a7 | Function arguments | caller |
x18 | s2 | Saved registers | caller |
x19 | s3 | Saved registers | caller |
x20 | s4 | Saved registers | caller |
x21 | s5 | Saved registers | caller |
x22 | s6 | Saved registers | caller |
x23 | s7 | Saved registers | caller |
x24 | s8 | Saved registers | caller |
x25 | s9 | Saved registers | caller |
x26 | s10 | Saved registers | caller |
x27 | s11 | Saved registers | caller |
x28 | t3 | Temporaries | caller |
x29 | t4 | Temporaries | caller |
x30 | t5 | Temporaries | caller |
x31 | t6 | Temporaries | caller |
Base指令格式:
RV32I指令格式包括以下6种,每种指令格式都是固定的32位指令,所以指令在内存中必须4字节对齐,否则将触发异常。其中rd表示目的寄存器,rs1是源操作数寄存器1,rs2是源操作数寄存器2。
imm表示指令中的立即数,比如imm[11:0],表示一个12位的立即数,它的高20位会符号位扩展,imm[31:12]表示一个32位的立即数,它的低12位会补0。
下图是各种指令格式扩展后的32位立即数。
RV32I整数指令集
RV32I整数指令集分为几个种类:
1.Load和store指令
Category | Fmt | RV32I base | machine code(bin) | comment | |
Loads | load byte | I | lb rd, rs1, imm | [31-20,imm][19-15,rs1]000[11-7,rd]0000011 | rd=mem[rs1+imm], 8bit数据符号位扩展后返回rd |
load half word | I | lh rd, rs1, imm | [31-20,imm][19-15,rs1]001[11-7,rd]0000011 | rd=mem[rs1+imm],16bit数据符号扩展后返回rd,应该保证地址对齐,否则产生异常 | |
load word | I | lw rd, rs1, imm | [31-20,imm][19-15,rs1]010[11-7,rd]0000011 | rd=mem[rs1+imm],32bit数据返回rd,应该保证地址对齐,否则产生异常 | |
load byte unsinged | I | lbu rd, rs1, imm | [31-20,imm][19-15,rs1]100[11-7,rd]0000011 | rd=mem[rs1+imm], 8bit数据高位补0后返回rd | |
load half unsinged | I | lhu rd, rs1, imm | [31-20,imm][19-15,rs1]101[11-7,rd]0000011 | rd=mem[rs1+imm], 16bit数据高位补0后返回rd |
stores | store byte | S | sb rs1, rs2, imm | [31-25,imm[11-5]][24-20,rs2,][19-15,rs1]000[11-7,imm[4-0]]0100011 | mem[rs1+imm]=rs2的低8bit数据 |
store half word | S | sh rs1, rs2, imm | [31-25,imm[11-5]][24-20,rs2,][19-15,rs1]001[11-7,imm[4-0]]0100011 | mem[rs1+imm]=rs2的低16bit数据 | |
store word | S | sw rs1, rs2, imm | [31-25,imm[11-5]][24-20,rs2,][19-15,rs1]010[11-7,imm[4-0]]0100011 | mem[rs1+imm]=rs2的32bit数据 |
RV32I是一个load /store架构,所有的memory访问都是通过load/store指令,其它指令都是在寄存器之间进行运算,比如加法指令,减法指令等等。注意,装入目的寄存器如果为x0,将会产生一个异常。Load/Store指令在memory和寄存器之间传输数据,Load指令编码为I型,store指令编码为S型。计算memory地址时候,imm都会符号扩展成32位,然后和rs1相加,得到memory地址。为了提高性能,load/store指令应该尽量对齐地址,比如lw指令,应该4字节对齐访问地址,lh应该双字节对齐访问地址。根据微架构实现的不同,不对齐地址的访问可能会比较慢,而且地址对齐访问,能够确保是原子操作,不对齐的话为了读取和存储数据正确,还有进行额外的同步操作。
2.整数计算指令(算术,逻辑指令,比较指令以及移位指令)
Category | Fmt | RV32I base | machine code(bin) | comment |
arithmetric | add | R | add rd, rs1, rs2 | 0000000[24-20,rs2][19-15,rs1]000[11-7,rd]0110011 | rd=rs1+rs2,如果溢出,舍弃高位,保留低32bit |
add immediate | I | addi rd, rs1, imm | [31-20,imm][19-15,rs1]000[11-7,rd]0010011 | rd=rs1+imm,12bit立即数会符号位扩展,结果写回rd时如果溢出,则舍弃高位,保留低32bit | |
subtract | R | sub rd, rs1, rs2 | 0100000[24-20,rs2][19-15,rs1]000[11-7,rd]0110011 | rd=rs1-rs2,如果溢出,舍弃高位,保留低32bit | |
load upper imm | U | lui rd, imm | [31-12,imm][11-7,rd]0110111 | load imm to high 20 bits of rd, and place 0 in low 12 bits | |
add upper imm to PC | U | auipc rd, imm | [31-12,imm][11-7,rd]0010111 | pc=pc+high 20 bits imm&low 12 bits 0, then result save to rd. |
|
logical | xor | R | xor rd, rs1, rs2 | 0000000[24-20,rs2][19-15,rs1]100[11-7,rd]0110011 | rd=rs1^rs2, bitwise operation |
xor immediate | I | xori rd, rs1, imm | [31-20,imm][19-15,rs1]100[11-7,rd]0010011 | rd=rs1^imm, i符号扩展12bit数imm,结果放在rd。 | |
or | R | or rd, rs1, rs2 | 0000000[24-20,rs2][19-15,rs1]110[11-7,rd]0110011 | rd=rs1|rs2, bitwise operation | |
or immediate | I | ori rd, rs1, imm | [31-20,imm][19-15,rs1]110[11-7,rd]0010011 | rd=rs1|imm, 符号扩展12bit数imm,结果放在rd。 | |
and | R | and rd, rs1, rs2 | 0000000[24-20,rs2][19-15,rs1]111[11-7,rd]0110011 | rd=rs1&rs2, bitwise operation | |
and immediate | I | andi rd, rs1, imm | [31-20,imm][19-15,rs1]111[11-7,rd]0010011 | rd=rs1&imm, i符号扩展12bit数imm,结果放在rd。 |
shifts | shift left | R | SLL rd, rs1, rs2 | 0000000[24-20,rs2][19-15,rs1]001[11-7,rd]0110011 | rd=rs1<<rs2,rs1左移值为rs2的低5bit,低位补0 |
shift left immediate | I | SLLI rd, rs1, shamt | 0000000[24-20,imm][19-15,rs1]001[11-7,rd]0010011 | rd=rs1<<shamt,rs1移动5bit立即数,低位补0 | |
shift right | R | SRL rd, rs1, rs2 | 0000000[24-20,rs2][19-15,rs1]101[11-7,rd]0110011 | rd=rs1>>rs2,高位补0,右移值为rs2中的低5位 | |
shift right immediate | I | SRLI rd, rs1, shamt | 0000000[24-20,imm][19-15,rs1]101[11-7,rd]0010011 | rd=r1>>shamt,高位补0,右移值为5bit立即数 | |
shift right arithmetirc | R | SRA rd, rs1, rs2 | 0100000[24-20,rs2][19-15,rs1]101[11-7,rd]0110011 | rd=rs1>>rs2,高位补符号位,右移值为rs2中的低5位 | |
shift right arith imm | I | SRAI rd, rs1, shamt | 0100000[24-20,imm][19-15,rs1]101[11-7,rd]0010011 | 右移时,右边补符号位 |
compare | set < | R | slt rd, rs1, rs2 | 0000000[24-20,rs2][19-15,rs1]010[11-7,rd]0110011 | if rs1< rs2, write 1 to rd, 有符号数比较 |
set < immediate | I | slti rd, rs1, imm | [31-20,imm][19-15,rs1]010[11-7,rd]0010011 | if rs1<imm, write 1 to rd,imm会符号位扩展,所以进行有符号数比较 | |
set < unsigned | R | sltu rd, rs1, rs2 | 0000000[24-20,rs2][19-15,rs1]011[11-7,rd]0110011 | if rs1< rs2, write 1 to rd, 无符号数比较 | |
set < imm unsigned | I | sltiu rd, rs1, imm | [31-20,imm][19-15,rs1]011[11-7,rd]0010011 | if rs1<imm, write 1 to rd,imm会符号位扩展,所以进行有符号数比较 |
计算指令在寄存器和寄存器之间,或者在寄存器和立即数之间进行算术或逻辑运算。指令格式为I,R或者U型。整数计算指令不会产生异常。我们能够通过ADDI x0, x0, 0来模拟NOP指令,该指令除了改变pc值外,不会改变其它任何用户状态。
3. 控制指令,包括无条件跳转指令和条件跳转指令
Category | Fmt | RV32I base | machine code(bin) | comment |
branch | branch = | SB | beq rs1, rs2,imm |
[31-25, imm[12][10:5]][24-20, rs2][19-15, rs1]000[11-7, imm[4:1][11]]1100011 |
if(rs1==rs2) pc=pc+imm*2,跳转指令 |
branch <> | SB | bne rs1, rs2,imm |
[31-25, imm[12][10:5]][24-20, rs2][19-15, rs1]001[11-7, imm[4:1][11]]1100011 |
if(rs1!=rs2) pc=pc+imm*2,跳转指令 | |
branch < | SB | blt rs1, rs2,imm |
[31-25, imm[12][10:5]][24-20, rs2][19-15, rs1]100[11-7, imm[4:1][11]]1100011 |
if(rs1<rs2) pc=pc+imm*2,跳转指令 , 有符号数 | |
branch >= | SB | bge rs1, rs2,imm |
[31-25, imm[12][10:5]][24-20, rs2][19-15, rs1]101[11-7, imm[4:1][11]]1100011 |
if(rs1>rs2) pc=pc+imm*2,跳转指令,有符号数 | |
branch < unsigned | SB | bltu rs1, rs2,imm |
[31-25, imm[12][10:5]][24-20, rs2][19-15, rs1]110[11-7, imm[4:1][11]]1100011 |
if(rs1<rs2) pc=pc+imm*2,跳转指令,无符号数 | |
branch >=unsigned | SB | bgeu rs1, rs2,imm |
[31-25, imm[12][10:5]][24-20, rs2][19-15, rs1]111[11-7, imm[4:1][11]]1100011 |
if(rs1>rs2) pc=pc+imm*2,跳转指令,无符号数 | |
jump and link | J&L | UJ | JAL rd, imm | [31-12, imm[20][10:1][11][19:12]][11-7,rd]1101111 |
pc=pc+imm*2, 现在的pc+4写入rd寄存器 |
Jump and link register | UJ | JALR, rd, rs1, imm | [31-20,imm[11:0]][19-15,rs1]000[11-7,rd]1100111 | pc=rs1+imm, pc+4写入到rd寄存器 |
JAL指令使用20位的立即数作为偏移,所以它仅可以跳转到前后1M的地址空间。JALR使用12位的立即数,其值和rs1中的值相加,得到偏移量。
4. 同步指令
Category | Fmt | RV32I base | machine code(bin) | comment |
Synch | synch thread | I | FENCE iorw,iorw | 0000[27-24,pred][23-20,succ]00000000000000001111 | pred/succ分别表示fence之前和之后的 iorw |
synch instr and data | I | FENCE.i | 00000000000000000001000000001111 | 用于同步指令和数据流 |
Risc-V在多个hart(硬件线程)之间使用的是松散一致性模型,所以需要存储器fence指令。
fence指令能够保证存储器访问的执行顺序。在fence指令之前的所有存储器访问指令,比该fence之后的所有数据存储器访问指令先执行。
Risc-V架构将数据存储器的地址空间分为设备IO(device IO)和普通存储器空间,因此其读写访问分为四种类型:
I:设备读(device-input)
O:设备写(device-ouput)
R:存储器读(memory-reads)
W:存储器写(memory-writes)
PI/PO/PR/PW,分别f表示ence指令之前的四种读写访问类型,SI/SO/SR/SW分别表示fence指令之后的四种读写访问类型。
fence.i指令用于同步指令和数据流。如果程序中添加一个fence.i,则该指令能够保证fence.i之前所有指令的访存结果能被fence.i之后的所有指令访问到。通常说来,处理器的微架构硬件实现时,一旦遇到一条fence.i指令,便会先等到之前的所有访存指令执行完,然后冲刷流水线,包括Icache,使其后的所有指令,能够重新取指,从而得到最新的值。
注意:fence.i只能保证同一个hart(硬件线程)执行的指令流和数据流顺序,不能保证多个hart之间的指令流和数据流访问。
5.控制状态寄存器指令
Category | Fmt | RV32I base | machine code(bin) | comment |
CSR | CSRRW | I | CSRRW | [31-20,csr][19-15, rs1]001[11-7,rd]1110011 | csrrw rd, csr, rs1, 将csr索引的寄存器值读出,写到rd,将rs1中的值写入csr |
CSRRS | I | CSRRS | [31-20,csr][19-15, rs1]010[11-7,rd]1110011 | csrrs rd, csr, rs1, 将csr索引寄存器值读出写到rd,以rs1为参考,如果rs1中某位为1,则置位对应的csr寄存器位,其他位不受影响。 |
|
CSRRC | I | CSRRC | [31-20,csr][19-15, rs1]011[11-7,rd]1110011 | csrrc rd, csr, rs1, 将csr索引寄存器值读出写到rd,以rs1为参考,如果rs1中某位为1,则清零对应的csr寄存器位,其他位不受影响。 |
|
CSRRWI | I | CSRRWI | [31-20,csr][19-15, zimm]101[11-7,rd]1110011 |
csrrwi rd, csr, imm[4:0], 将csr索引寄存器值读出写到rd,5位立即数的值写入csr,高位补0 |
|
CSRRSI | I | CSRRSI | [31-20,csr][19-15, zimm]110[11-7,rd]1110011 |
csrrsi rd, csr, imm[4:0], 将csr索引寄存器值读出写到rd,5位立即数的值(高位补0)逐位比较,如果为1,则置位csr相应位 |
|
CSRRCI | I | CSRRCI | [31-20,csr][19-15, zimm]111[11-7,rd]1110011 |
csrrci rd, csr, imm[4:0], 将csr索引寄存器值读出写到rd,5位立即数的值(高位补0)逐位比较,如果为1,则清零csr相应位 |
CSR指令包括上面表中的6条指令,通常在用户层,不会访问写csr的指令。
这些CSR指令实现都是原子操作。对于CSRRW和CSRRWI来说,如果rd为x0,则不会有任何写操作。对于CSRS和CSRRC指令,如果rs1为x0,则不会有任何写操作。对于CSRRSI和CSRRCI来说,如果立即数为0,则不会有任何写操作。
用CSR指令可以实现一些伪指令,例如读取始终频率等。详细见伪指令列表。
6.环境调用和断点指令
Category | Fmt | RV32I base | machine code(bin) | comment |
System | system call | I | ECALL | 00000000000000000000000001110011 | 用于生成环境调用异常,产生异常时候,mepc寄存器将保存当前指令pc值。 |
system break | I | EBREAK | 00000000000100000000000001110011 | 生成断点,产生异常时候,mepc寄存器将保存当前指令pc值。 |
这两条指令能够产生环境调用异常和生成断点异常,产生异常时候,当前指令的pc值被写入mepc寄存器。
这两条指令在调试代码时候有用。
RV32I指令集的更多相关文章
- RV32I基础整数指令集
RV32I是32位基础整数指令集,它支持32位寻址空间,支持字节地址访问,仅支持小端格式(little-endian,高地址高位,低地址地位),寄存器也是32位整数寄存器.RV32I指令集的目的是尽量 ...
- Risc-V指令集
https://riscv.org/specifications/ Risc-V文档包括:用户层指令集文档和特权架构文档,下面这两个文件的官网链接. User-Level ISA Specificat ...
- RV64I基础整数指令集
RV64I是RV32I的超集,RV32I是RV64I的子集.RV64I包括RV32I的所有40条指令,另外增加了12条RV32I中没有的指令,还有三条移位指令(slli, srli,srai)也进行小 ...
- tinyriscv---一个从零开始写的极简、易懂的开源RISC-V处理器核
本项目实现的是一个微riscv处理器核(tinyriscv),用verilog语言编写,只求以最简单.最通俗易懂的方式实现riscv指令的功能,因此没有特意去对代码做任何的优化,因此你会看到里面写的代 ...
- RISCV 入门 (学习笔记)
文章目录 1. risv 相关背景 1.1 arm 授权费 1.2 riscv 发展历史 1.3 riscv 风险 2. 指令集 2.1 可配置的通用寄存器组 2.2 规整的指令编码 2.3 简洁的存 ...
- RV32A指令集
RV32A指令包括两类:AMO(atomic memory operation)指令,Load-Reserved/Store-Conditional指令 Category Fmt RV32I base ...
- RV32FDQ/RV64RDQ指令集(1)
Risc-V架构定义了可选的单精度浮点指令(F扩展指令集)和双精度浮点指令(D扩展指令集),以及四精度浮点指令集(Q扩展指令集).Risc-V架构规定:处理器可以选择只实现F扩展指令子集而不支持D扩展 ...
- RVZicsr指令集
Riscv中每个硬件线程(hart)有4096个独立地址空间的状态寄存器.我们可以通过Zicsr指令读写csr寄存器.总共有6条csr读写指令,这些指令之前都在RV32I/RV64I基础指令集里面,在 ...
- SSE指令集学习:Compiler Intrinsic
大多数的函数是在库中,Intrinsic Function却内嵌在编译器中(built in to the compiler). 1. Intrinsic Function Intrinsic Fun ...
随机推荐
- 【教程】Tomcat 的catalina.out 日志按照自定义日期格式进行切割
本文简单介绍在使用cronolog对tomcat的日志进行自定义日期格式的切割,方便日志的整理和遇到问题日志的排查! 安装cronolog 安装cronolog的方法网上有很多,这里也简单的介绍一下. ...
- 用mac的chrome浏览器调试Android手机的网页
一.参考链接 read chrome remote debugging documentation 调出开发者选项 二.设置android 在安卓4.2及更新的版本中,默认情况下,[开发者选项]是隐藏 ...
- NOIP练习赛题目5
小象涂色 难度级别:C: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 小象喜欢为箱子涂色.小象现在有c种颜色,编号为0~c-1:还有n个箱 ...
- BZOJ2671 : Calc
设$d=\gcd(a,b),a=xd,b=yd$,则$a+b|ab$等价于$x+y|xyd$. 因为$x,y$互质,所以$x+y|d$. 假设$x<y$,那么对于固定的$x,y$,有$\lflo ...
- R基础学习(三)-- 简单练习(shiny+mysql+barplot)
测试环境:win10+RStudio 提前准备: install.packages('shiny') install.packages('RMySQL') 数据表准备: 最终实现的界面效果如下:点击[ ...
- The STM32 SPI and FPGA communication
The STM32 SPI and FPGA communication STM32 spi bus communication SPI bus in the study, the protocol ...
- 使用 NuGet 管理我们的程序集 - 预发行版
1.缘起 在我们的项目中.须要引用的组件统一放在一个 Libs 文件夹下.不管对于平台上的公共组件.还是应用模块,都是如此. 假设一个应用模块,比如能源管理(EM).要引用平台提供的公共组件,比如数据 ...
- select,poll,epoll之间的区别
(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替.而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替, ...
- [置顶] 九度笔记之 1494:Dota
题目1494:Dota 1 秒 内存限制:128 兆 特殊判题:否 提交:559 解决:122 题目描述: 大家都知道在dota游戏中,装备是对于英雄来说十分重要的要素. 英雄们不仅可以购买单个的装备 ...
- Revit API画垂直于风管的风管
start /// <summary> /// 选择风管与风管外一点,画与风管垂直的风管. /// </summary> [Transaction(TransactionMod ...