RISC-V简介
RISC-V的设计理念就是“简单”(有C语言内味了)
RISC-V通过架构的定义使硬件的实现足够简单,实现“简单就是美”的设计哲学
riscv的架构文档分成“非特权架构文档”(曾经被称为“指令集文档”)和“特权架构文档”,在需求高性能时,核心可以运行在特权+非特权的模式下;在需求高实时性时,核心可以只运行在非特权模式下。
RISCV具有模块化的指令集,可以通过组合不同的指令集来满足不同场景下的使用,核心指令数仅有40多条,加上其他的模块化扩展指令总共有几十条
模块化指令子集
RISCV每个指令集模块用一个英文字母来表示,其中最基本且唯一要求强制实现的指令集是由I字母表示的基本整数指令子集,使用该指令集就可以实现完整的软件编译器,进而使用高级语言进行编程
比较有代表性的模块包括IMAFD,这些模块组合起来被称为通用组合,用G(general)表示,全称是RV32G(32位)或RV64G(64位)。为提高代码密度,RISCV也提供可选的压缩指令集,用C(compress)表示。压缩指令的指令编码长度为16比特,普通的非压缩指令长度为32比特。还有面积更小的“嵌入式架构”,用E(embedded)表示,该架构仅需要支持16个通用整数寄存器,而非嵌入式架构的指令集需要支持32个通用整数寄存器
通用寄存器组
RISCV架构支持32位或64位架构,32位架构用RV32表示,寄存器位宽32bit;64位架构用RV64表示,寄存器位宽64bit。整数通用寄存器组包含32(I架构)或16(E架构)个通用整数寄存器;其中整数寄存器0被预留为常数0,其他31个(I)或15个(E)为普通的通用整数寄存器
如果使用浮点模块(F或D指令子集),则需要另外一个独立的浮点寄存器组,包含32个通用浮点寄存器。如果仅使用F模块(float)的浮点指令子集,则每个通用浮点寄存器的宽度为32bit;如果仅使用了D模块(double)的浮点指令子集,则每个通用浮点寄存器的宽度为64bit
规整的指令编码
RISCV的指令集编码非常规整,指令所需的通用寄存器的索引(Index)被放在固定的位置,指令译码器可以非常便捷地译码出寄存器索引来读取通用寄存器组(Register File,Regfile)
存储器访问指令
RISCV架构使用专用的存储器读指令和存储器写指令进行访问存储器操作,其他普通指令无法访问存储器!
这是RISC-V架构的一个基本策略,体现了简单即是美的设计哲学
存储器访问的基本单位是字节(Byte)
RISCV的存储器读和存储器写指令支持单字32位、半字16位、字节8位,如果是64位架构还可以支持一个双字64位的存储器读写
其他特点如下:
推荐使用地址对齐,但也支持地址非对齐,处理器可以选择硬件支持也可以选择软件支持
RISCV仅支持现在的主流存储器格式,即小端格式little endian(低地址中存放的是字数据的低字节,高地址存放的是字数据的高字节,大端格式big endian与其相反)
不支持地址自增或自减模式
采用松散存储器模型(Relaxed Memory Model),对于访问不同地址的存储器读写指令的执行顺序不做要求,除非明确使用存储器屏障(Fence)指令将存储器屏蔽
这种存储器访问指令要求简化了硬件电路设计,对于追求高性能的超标量处理器,也可以通过复杂设计的动态硬件调度能力来提高性能
分支跳转指令
RISC-V拥有2条无条件跳转指令,分别称为JAL和JALR指令
JAL即jump and link跳转链接指令,可用于子程序调用(函数调用),同时将子程序返回地址存在链接寄存器(Link Register,由某一个通用整数寄存器担任)中
JALR即JAL加上return,用于从子程序返回(函数返回)
还有6条带条件跳转指令(Conditional Branch),这种带条件的跳转指令和普通运算指令一样使用两个整数操作数,然后对其进行比较,如果比较的条件满足则进行跳转(很多其他的RISC架构处理器使用两条独立的指令,第一条指令进行比较,结果放在状态寄存器中,第二条指令读取状态寄存器进行跳转)
对于没有配备硬件分支预测器的低端CPU,为保证其性能,RISCV架构明确要求采用默认的静态分支预测机制:如果是向后跳转的条件跳转指令则预测为跳;向前跳转的指令则预测为不跳,并且要求编译器也按照这种默认的静态分支预测机制来编译生成汇编代码。同时RISCV架构规定了所有带条件跳转指令跳转目标相对与当前指令地址的偏移量都是有符号数,其符号位被编码在固定的位置,因此这种静态预测机制在硬件上容易实现。对于配备硬件分支预测器的高端CPU,也可以采用更高级的动态分支预测机制
子程序调用
一般RISC架构中程序采用以下方式进行子函数调用:
保存现场:用存储器写指令将当前函数上下文(通用寄存器、SP、IR等)保存到系统存储器的堆栈区(上下文压栈)
恢复现场:用存储器读指令将之前保存的上下文从系统存储器的堆栈区读入对应寄存器(上下文出栈)
RISCV架构直接放弃使用“一次读/写多个寄存器”指令,让用户可选公用程序库来处理保存现场-恢复现场的指令,省掉在每个子函数调用的过程中都放置数目不等的保存-恢复相关指令
无条件码执行
RISCV中没有带条件码的指令(当xxx条件为真时执行xxx)
对所有条件判断都使用普通的带条件分支跳转指令,大幅简化CPU的硬件设计
无分支延迟槽
分支延迟槽:在每一条分支指令后面紧跟的一条或若干条指令不受分支跳转的影响——不管分支是否跳转,后面的几条指令都一定会被执行
分支延迟槽是为了早期CPU缺少高级硬件动态分支预测器情况下增加CPU效率而使用的,会让CPU硬件设计极其难受
RISCV直接砍掉分支延迟槽来简化电路
RISCV的思路就是“我只要硬件够少、操作够方便,跟高性能有关的东西全部交给分支预测电路和软件”
无零开销硬件循环
零开销硬件循环:通过硬件直接参与,设置某些循环次数寄存器,然后让程序自动地进行循环,每一次循环则循环次数寄存器自动-1,直到循环次数寄存器值为0(相当于软件的for(int i=cnt;i==0;i--))
这可以让上述软件循环得到优化,减少加法和条件跳转指令使用
RISCV砍掉了零开销硬件循环来简化电路
|