1. 指令集 1.1 指令集 指令集是一个cpu的基石,要实现cpu 计算和控制功能,就必须定义好一系列与硬件电路相匹配的指令系统.
指令就是我们交代cpu 要执行的操作,指令集就可以简单理解为指令的集合。我们把cpu 能够识别的指令汇总在一起就构成了一个指令集。
不同的cpu 有不同的指令集,根据他们的繁简程度可以分为两种:复杂指令集cisc 和精简指令集 risc
1.2 指令集架构 指令架构(instruction set architecture, 缩写为isa),是软件和硬件的接口,不同的应用需求,会有不同的指令架构。要设计一款cpu 指令体系就是设计的出发点。
2. risc-v 指令集架构 risc-v 指令有以下特点:
完全开放 指令简单 模块化设计,易于扩展 名称 类别 说明
rv32i 基础指令 整数指令:包含算法、分支、逻辑、访存指令,有32个32位寄存器。能寻址32位地址空间
rv64i 基础指令 整数指令:包含算法、分支、逻辑、访存指令,有32个64位寄存器。能寻址64位地址空间
rv128i 基础指令 整数指令:包含算法、分支、逻辑、访存指令,有32个128位寄存器。能寻址128位地址空间
rv32e 基础指令 与rv32i一样,只不过只使用前16个(0~15)32位寄存器
m 扩展指令 包含乘法、除法、取模求余指令
f 扩展指令 单精度浮点指令
d 扩展指令 双精度浮点指令
q 扩展指令 四倍精度浮点指令
a 扩展指令 原子操作指令:比如比较并交换,读改写等指令
c 扩展指令 压缩指令:单指令长度为16位,主要用于改善程序大小
p 扩展指令 单指令多数据(packed-simd)指令
b 扩展指令 位操作指令
h 扩展指令 支持(hypervisor)管理指令
j 扩展指令 支持动态翻译语言指令
l 扩展指令 十进制浮点指令
n 扩展指令 用户中断指令
g 通用指令 包含i、m、a、f、d 指令
要满足现在操作系统和应用程序的基本运行,rv32g指令集或者rv64g指令集就够了。rv32g和rv64g指令集只有寄存器位宽和寻址大小不同。这些指令按照功能可以分为如下几类:
整数运算指令:算术、逻辑、比较等基础运算功能。 分支转移指令:实现条件转移、无条件转移操作 加载存储指令:实现字节、半字(half word)、字(word)、双字(rv64i)的加载,存储操作,采用的都是寄存器相对寻址方式 控制与状态寄存器访问指令:实现对系统控制与系统状态寄存器的原子读-写、原子读-修改、原子读-清零等操作 系统调用指令:实现系统调用功能。 原子指令:用于各种同步锁 单双浮点指令:实现浮点运算操作 从上表我们可以看到,risc-v 指令集具有模块化特点。这就允许我们根据自己的需求,选择一个基础指令集,加上若干个扩展指令集灵活搭配,就可以得到我们想要的指令集架构,进而根据这样的指令架构,设计出贴合我们需求的cpu.
作为初学者,我们了解risc-v 的核心即可。它的最核心部分是一个基础指令集,叫做rv32i.
rv32i 包含的指令是固定不变的,这为编译器设计人员,操作系统开发人员和汇编语言程序员提供了稳定的基础框架。
rv32i 指令集:
rv32i 指令集如图所示,把带下划线的字母从左至右连接组合就是组成了rv32i指令。{}表示集合中垂直方向的每个项目指令不同变体。变体用下划线字母或者下划线表示表示,如果大括号里面只有下划线,则表示对此变体不需要用字母表示
我们结合具体例子来看:下图表示了bge、blt、bgeu、bltu四个指令。
3. 指令格式 下图是risc-v 指令格式,从下图可以看到rsic-v共六种指令格式。
opcode :指令操作码 imm:代码立即数 func3和funct7:代表指令对应的功能 rs1:源寄存器1 rs2:源寄存器2 rd:目标寄存器(rsic-v 一个指令可以提供三个寄存器操作) 六种指令格式作用如下:
序号 指令类型 作用
1 r 型指令 用于寄存器和寄存器操作
2 i 型指令 用于短立即数和内存载入指令load操作
3 s 型指令 用于内存存储store操作
4 b 型指令 用于有条件跳转操作
5 u 型指令 用于长立即数操作
6 j 型指令 用于无条件跳转操作
4.寄存器 在risc-v 的规范里面定义了32 个通用寄存器。其中31个是常规寄存器,1个恒为0值的x0寄存器。
0值寄存器是为了满足汇编语言程序员和编译器编写者的使用需要,他们可以使用x0寄存器作为操作数,来完成功能相同的操作。
addi x0,x0,0 ; 0 = 0 + 0,相当于 nop 空指令 rsic-v 寄存器说明
寄存器 abi 名称 说明
x0 zero 0值寄存器,硬编码为0,写入数据忽略,读取数据为0
x1 ra 用于返回地址(return address)
x2 sp 用于栈指针(stack pointer)
x3 gp 用于通用指针 (global pointer)
x4 tp 用于线程指针 (thread pointer)
x5 t0 用于存放临时数据或者备用链接寄存器
x6~x7 t1~t2 用于存放临时数据寄存器
x8 s0/fp 需要保存的寄存器或者帧指针寄存器
x9 s1 需要保存的寄存器
x10~x11 a0~a1 函数传递参数寄存器或者函数返回值寄存器
x12~x17 a2~a7 函数传递参数寄存器
x18~x27 s2-s11 需要保存的寄存器
x28~x31 t3~t6 用于存放临时数据寄存器
5. rv32i 指令解读 5.1 算术与逻辑指令 在rv32i 中包括算术指令(add/sub)、数值比较指令(slt)、逻辑指令(and/or/xor)以及移位指令(sll/srl/sra)这几种指令。
这些指令和其他指令集差不多,它们从寄存器读取两个32位的值,并将32位运算结果再写回到目标寄存器。
i型指令:立即数算术运算
r型指令:寄存器与寄存器操作指令
需要指出的是,在寄存器与寄存器操作的算术指令中。必须要有减法指令。这和立即数操作指令不同。
5.2 load 和 store 指令 在risc-v 指令集中,对内存的读写只能通过load 和 store 指令实现。而其他的指令只能以寄存器为操作对象。
如上图所示,load 和 store 的寻址模式只能是符号扩展12位的立即数,加上基地址寄存器得到访存的存储器地址。因为没有了复杂的内存寻址方式,这让cpu 流水线可以对数据冲突提前做出判断,并通过流水线各级转送加以处理,而不需要加入空操作(nop),极大的提高了代码的执行效率。
5.3 分支跳转指令 5.3.1 有条件的分支跳转 rv32i 中的条件跳转就是通过比较两个寄存器的值,进行分支跳转:
beq:相等 bne:不相等 bge/bgeu:大于等于 blt/bltu:小于 5.3.2 无条件的分支跳转 无条件跳转指令可以细分为直接跳转和间接跳转。直接跳转指令jal 如下图所示:
jal 指令执行过程是这样的。它会把20位立即数做符号位扩展。并左移一位,产生一个32位符号数。然后,将该32位符号数和pc相加来产生目标地址(这样,jal 可以作为短跳转指令,跳至pc+1mb的地址范围内) 同时jal 会把紧随其后的那条指令地址,存入目标寄存器中。这样,如果目标寄存器是零,则jal就等同goto指令;如果目标寄存器不为零,jal可以实现函数调用功能。 间接跳转直接jalr如下:
jalr指令会把12位立即数和源寄存器相加,并把相加结果末位清零,作为新的跳转地址。同时和jal指令一样,也会把紧随其后的那条指令地址,存入目标寄存器中。 5.4 其他指令 除了内存地址空间和通用寄存器地址空间外,risc-v 还定义了一个独立的控制和状态寄存器地址空间(control status register)每个处理器实现的csr会因设计目标不同而有差异,但是这些csr的访问方式却是一样的,访问这些csr指令定义在了用户指令集中(zicsr指令集扩展)
有了上图这些csr 指令,能够让我们轻松的访问一些程序性能计数器。这些计数器包括系统时间、时间周期以及执行的指令数目。
特斯拉新型电池技术,让电池寿命延长至160万公里
【芯闻时译】荷兰政府发布半导体出口新措施
LC滤波器怎么设计,Q值怎么理解最简单
备受程序员们追捧的蚕蛹你了解多少?
特斯拉家用充电桩参数及规格
一文详解RISC-V指令集
中国联通:为满足携号转网项目技术要求,相关设备只能从华为处采购
南昌VR研究院成立,注册资本达6亿
无人机采用单相机双拼航线飞行实现倾斜摄影的设计
基于STM32单片机秒中断源和闹钟中断源的解决方案
电瓶修复技术—蓄电池的特性和试验6
耳机玄学究竟说的是什么
智能苹果数据线,颜值高性能稳定的充电神器
激光电视1月逆势增超100% 市场正在大量迎合激光电视
低功率40m连续波发射机
电子芯闻早报:苹果触控笔,谷歌人形机器人
iPhone15最新消息:印度工厂开始组装iPhone15 iPhone15系列USBC数据线曝光
【资料下载】IMG CXM GPU:面向复杂消费级设备的无缝视觉体验
魅蓝E3与红米Note5之间如何抉择?
无线充电技术经典问答