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指令集的更多相关文章

  1. RV32I基础整数指令集

    RV32I是32位基础整数指令集,它支持32位寻址空间,支持字节地址访问,仅支持小端格式(little-endian,高地址高位,低地址地位),寄存器也是32位整数寄存器.RV32I指令集的目的是尽量 ...

  2. Risc-V指令集

    https://riscv.org/specifications/ Risc-V文档包括:用户层指令集文档和特权架构文档,下面这两个文件的官网链接. User-Level ISA Specificat ...

  3. RV64I基础整数指令集

    RV64I是RV32I的超集,RV32I是RV64I的子集.RV64I包括RV32I的所有40条指令,另外增加了12条RV32I中没有的指令,还有三条移位指令(slli, srli,srai)也进行小 ...

  4. tinyriscv---一个从零开始写的极简、易懂的开源RISC-V处理器核

    本项目实现的是一个微riscv处理器核(tinyriscv),用verilog语言编写,只求以最简单.最通俗易懂的方式实现riscv指令的功能,因此没有特意去对代码做任何的优化,因此你会看到里面写的代 ...

  5. RISCV 入门 (学习笔记)

    文章目录 1. risv 相关背景 1.1 arm 授权费 1.2 riscv 发展历史 1.3 riscv 风险 2. 指令集 2.1 可配置的通用寄存器组 2.2 规整的指令编码 2.3 简洁的存 ...

  6. RV32A指令集

    RV32A指令包括两类:AMO(atomic memory operation)指令,Load-Reserved/Store-Conditional指令 Category Fmt RV32I base ...

  7. RV32FDQ/RV64RDQ指令集(1)

    Risc-V架构定义了可选的单精度浮点指令(F扩展指令集)和双精度浮点指令(D扩展指令集),以及四精度浮点指令集(Q扩展指令集).Risc-V架构规定:处理器可以选择只实现F扩展指令子集而不支持D扩展 ...

  8. RVZicsr指令集

    Riscv中每个硬件线程(hart)有4096个独立地址空间的状态寄存器.我们可以通过Zicsr指令读写csr寄存器.总共有6条csr读写指令,这些指令之前都在RV32I/RV64I基础指令集里面,在 ...

  9. SSE指令集学习:Compiler Intrinsic

    大多数的函数是在库中,Intrinsic Function却内嵌在编译器中(built in to the compiler). 1. Intrinsic Function Intrinsic Fun ...

随机推荐

  1. 【教程】Tomcat 的catalina.out 日志按照自定义日期格式进行切割

    本文简单介绍在使用cronolog对tomcat的日志进行自定义日期格式的切割,方便日志的整理和遇到问题日志的排查! 安装cronolog 安装cronolog的方法网上有很多,这里也简单的介绍一下. ...

  2. 用mac的chrome浏览器调试Android手机的网页

    一.参考链接 read chrome remote debugging documentation 调出开发者选项 二.设置android 在安卓4.2及更新的版本中,默认情况下,[开发者选项]是隐藏 ...

  3. NOIP练习赛题目5

    小象涂色 难度级别:C: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 小象喜欢为箱子涂色.小象现在有c种颜色,编号为0~c-1:还有n个箱 ...

  4. 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 ...

  5. R基础学习(三)-- 简单练习(shiny+mysql+barplot)

    测试环境:win10+RStudio 提前准备: install.packages('shiny') install.packages('RMySQL') 数据表准备: 最终实现的界面效果如下:点击[ ...

  6. The STM32 SPI and FPGA communication

    The STM32 SPI and FPGA communication STM32 spi bus communication SPI bus in the study, the protocol ...

  7. 使用 NuGet 管理我们的程序集 - 预发行版

    1.缘起 在我们的项目中.须要引用的组件统一放在一个 Libs 文件夹下.不管对于平台上的公共组件.还是应用模块,都是如此. 假设一个应用模块,比如能源管理(EM).要引用平台提供的公共组件,比如数据 ...

  8. select,poll,epoll之间的区别

    (1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替.而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替, ...

  9. [置顶] 九度笔记之 1494:Dota

    题目1494:Dota 1 秒 内存限制:128 兆 特殊判题:否 提交:559 解决:122 题目描述: 大家都知道在dota游戏中,装备是对于英雄来说十分重要的要素. 英雄们不仅可以购买单个的装备 ...

  10. Revit API画垂直于风管的风管

    start /// <summary> /// 选择风管与风管外一点,画与风管垂直的风管. /// </summary> [Transaction(TransactionMod ...