1.2 模块化与增量型 ISA
和几乎所有以往的 ISA不同,RISC-V是模块化的。它的核心是一个名为RV32I的基础 ISA,运行一个完整的软件栈。RV32I是固定的,永远不会改变。模块化来源于可选的标准扩展,根据应用程序的需要,硬件可以包含或不包含这些扩展。可以生成当前硬件条件下的最佳代码。惯例是把代表扩展的字母附加到指令集名称之后作为指示。例如,RV32IMFD将乘法( RV32M),单精度浮点(RV32F)和双精度浮点(RV32D)的扩展添加到了基础指令集 RV32I)中。
2.2 RV32I 指令格式
用于寄存器-寄存器操作的R类型指令,用于短立即数和访存load操作的I型指令,用于访存store操作的S型指令,用于条件跳转操作的B类型指令,用于长立即数的U型指令和用于无条件跳转的J型指令。
2.3 RV32I 寄存器
RV32I有31寄存器加上一个值恒为0的x0寄存器。
2.4 RV32I 整数计算
简单的算术指令(add, sub)、逻辑指令(and, or, xor),以及图2.1中的移位指令(sll, srl, sra)和其他ISA差不多。他们从寄存器读取两个32位的值,并将32位结果写入目标寄存器。
程序可以根据比较结果生成布尔值。为应对这种使用场景下,RV32I提供一个当小于时置位的指令(slt)。
图2.1剩下的两条整数计算指令主要用于构造大的常量数值和链接。加载立即数到高位(lui)将20位常量加载到寄存器的高20位。接着便可以使用标准的立即指令来创建32位常量。
有什么不同之处?
- RISC-V中没有字节或半字宽度的整数计算操作。操作始终是以完整的寄存器宽度。
- RV32I也不包含乘法和除法,它们包含在可选的RV32M扩展中。
2.5 RV32I 的Load 和 Store
除了提供32位字(lw,sw)的加载和存储外,图2.1中说明,RV32I 支持加载有符号和无符号字节和半字(lb,lbu,lh,lhu)和存储字节和半字(sb,sh)。有符号字节和半字符号扩展为32位再写入目的寄存器。即使是自然数据类型更窄,低位宽数据也是被扩展后再处理,这使得后续的整数计算指令能正确处理所有的32位。在文本和无符号整数中常用的无符号字节和半字,在写入目标寄存器之前都被无符号扩展到32位。
RV32I 条件分支
相等(beq),不相等 (bne),大于等于(bge),或小于(blt)。最后两种比较有符号比较,RV32I也提供相应的无符号版本比较的:bgeu和bltu。分支指令的寻址方式是12位的立即数乘以2,符号扩展它,然后将得到值加到PC上作为分支的跳转地址。{% label danger @这句话没理解 %}
{% note info %}
补充说明:获取PC
当前的PC可以通过将auipc的U立即数字段设置为0来获得。
{% endnote %}
2.7 RV32I无条件跳转
图2.1中的跳转并链接指令(jal)具有双重功能。若将下一条指令PC + 4的地址保存到目标寄存器中,通常是返回地址寄存器ra(见图2.4),便可以用它来实现过程调用。如果使用零寄存器(x0)替换ra作为目标寄存器,则可以实现无条件跳转,因为x0不能更改。像分支一样,jal将其20位分支地址乘以2,进行符号扩展后再添加到PC上,便得到了跳转地址。
{% note info %}
jal x1, X
means jump to X, and save the return address which is normally PC+4 to the x1.
jal x0 0(x1)
use indirect address (x1
) plus a constant of 12bits (0 in your example). set x0
as return address register because you «don’t care».
{% endnote %}
2.8 RV32I 杂项
图2.1中的控制状态寄存器指令 (csrrc、csrrs、csrrw、csrrci、csrrsi、csrrwi),使我们可以轻松地访问一些程序性能计数器。对于这些64位计数器, 我们一次可以读取32位。这些计数器包括了系统时间, 时钟周期以及执行的指令数目。
在RISC-V指令集中,ecall指令用于向运行时环境发出请求,例如系统调用。调试器使用ebreak指令将控制转移到调试环境。
fence指令对外部可见的访存请求,如设备I / O和内存访问等进行串行化。外部可见指对处理器的其他核心、线程,外部设备或协处理器可见。fence.i指令同步指令和数据流。在执行fence.i指令之前,对于同一个硬件线程,RISC-V不保证用存储指令写到内存指令区的数据可以被取指令取到。
2.10 结束语
- 32位字节可寻址的地址空间
- 所有指令均为32位长
- 31个寄存器,全部32位宽,寄存器0硬连线为零
- 所有操作都在寄存器之间(没有寄存器到内存的操作)
- 加载/存储字加上有符号和无符号加载/存储字节和半字
- 所有算术,逻辑和移位指令都有立即数版本的指令
- 立即数总是符号扩展
- 仅提供一种数据寻址模式(寄存器+立即数)和PC相对分支
- 无乘法或除法指令
- 一个指令,用于将大立即数加载到寄存器的高位,这样加载32位常量到寄存器只需要两条指令