如同人类交流依赖语言,计算机软硬件之间的交流依赖计算机语言,这种语言被称为指令系统(Instruction Set),众多指令的集合称为指令集架构(ISA,Instruction Set Architecture)。在计算机发展过程中,指令集形成了两种风格,包括复杂指令集计算机(CISC,Complex Instruction Set Computer),精简指令集计算机(RISC,Reduced Instruction Set Computer)。硬十开发的华山派,选择的是CV1812H的这颗SoC,使用双核玄铁C906 RISC-V的CPU,这个CPU就是属于RISC架构。
1、什么是计算机指令集
大家用高级语言比如C、Python等写的程序依赖编译器实现从高级语言 -> 汇编语言 -> 二进制机器码的翻译,其中处理器中机器和底层硬件的交流是通过计算机指令系统实现的,而指令集可视为处理器支撑所有操作的词汇表,定义了处理器可以实行的所有指令的集合。
计算机指令规定的内容包括数据类型及格式,指令格式,寻址方式和可访问地址空间的大小,程序可访问的寄存器个数、位数和编号,控制寄存器的定义,I/O空间的编制方式,中断结构,机器工作状态的定义和切换,输入输出结构和数据传送方式,存储保护方式信息。参考《The RISC-V Instruction Set Manual》的“整形寄存器-马上数”的指令。
2、计算机指令集CISC和RISC的区别
计算机指令集架构大致可以分为两类,复杂指令集计算机(CISC)和精简指令集计算机(RISC)。目前,主流的指令集架构大多数都诞生于20世纪70~80年代,如ARM、Intel X86、MIPS等,其中X86就是典型的CISC,而ARM就是典型的RISC。1974年,纽约约克镇IBM研究中心的John Cocke证明计算机中约20%的指令承担了80%的工作,他和同事提出了RISC的概念,对比于CISC,RISC是一种实行较少类型计算机指令的微处理器,它能够以更快的速度实行操作,CISC和RISC指令集的区别参考下表。
指令集是App生态的源头,假定有一个CPU企业想要设计一款新的CPU并投放市场,那么一定是从设计指令集开始。首先设计了一种新的指令集ISA,制造出兼容这种ISA的CPU,并将生产的CPU安装到计算机中,然后为这种CPU开发相关的操作系统、编译App(也称为工具链)等。而应用App开发者只需使用编译App对源代码进行编译,生成二进制码,就可以在这种CPU上运行App。通过日积月累,在这种CPU上可运行的App越来越多,这种CPU的生态规模也越来越庞大。
3、RISC-V的定义和发展历史
大家说的RISC-V不是一家企业、也不是一款CPU实现、它的定义是
(1)RISC-V的发展历史1981年,在David Patterson教授的领导下,加州大学伯克利分校(UC Berkeley) 的一个研究团队开发了RISC-Ⅰ处理器,这是今天RISC架构的鼻祖。而RISC-V这个名字,代表了这个大学设计的第五代主要的RISC ISA(前四个是RISC-I[18]、RISC-II[11]、SOAR[27]和SPUR[14]),罗马数字“V”也暗示了“变种(Variations)”和“向量(Vectors)”,第五代支撑各种体系结构研究,包括各种数据并行加速器,也是这个ISA设计的目标。2010年夏,Krste Asanovic教授带领他的学生Andrew Waterman和 Yunsup Lee启动了一个3个月的项目,目标是针对X86和ARM指令集架构复杂和需要IP授权的问题,开发一个简化和开放的指令集架构,在这个项目中RISC-V诞生了。
(2)RISC-V基金会负责维护RISC-VRISC-V由RISC-V基金会维护,基金会创建于2015年,是一家非营利组织,董事会最早由Bluespec、谷歌、Microsemi、NVIDIA、NXP、UC Berkeley、Western Digital等组成,目前该基金会的成员已经有1500个以上,覆盖70个国家。
(3)RISC-V高速发展
自RISC-V架构诞生以来,RISC-V内核和SoC芯片大量出现,特别是最近3~5年,它们中的一部分是开源免费的,而商业企业开发的RISC-V处理器内核和平台是需要商业授权的。RISC-V内核和SoC芯片种类繁多,很多都是应用于特定的场景,如西部数据的SweRV架构(RV32IMC)是RISC-V内核处理器的典型代表,它是一个32bit顺序实行指令架构,具有双向超标量设计和9级流水线,采用28nm工艺技术实现,运行频率高达1.8 GHz,可提供4.9CoreMark/MHz的性能略高于ARM的 Cortex A15,在西部数据的SSD和HDD控制器上使用。RISC-V在国内也发展迅速,比如目前华山派上使用的玄铁C906的是64位的RISC-V内核,玄铁系列是alibaba的平头哥研发的。国内其他企业,包括HUAWEI、寒武纪、算能也在研发生产基于RISC-V架构的芯片,应用覆盖人工智能加速到物联网嵌入式设备。另外,大量的中国的工程师和研究人员积极参与了RISC-V开源社区,在RISC-V标准的制定、开源处理器核心的开发以及RISC-V工具链的改进方面发挥了重要作用。
4、RISC-V指令集的优势
(1)完全开源。对于 RISC-V 指令集的使用,RISC-V基金会不收取高额的授权费。开源采用宽松的BSD 协议,企业可以完全自由免费使用,同时也允许企业添加自有指令集,而不必开放共享,实现差异化发展。
(2)架构简单。RISC-V设。处理器领域,流的架构为x8与ARM架构。x86与ARM架构的发展过程也伴随了现代处理器架构技术的不断发展成熟,但作为商用的架构,为了能够保持架构的向后兼容性,不得不保留许多过时的定义,导致其指令数目多,指令冗余严重,文档数量庞大,所以要在这些架构上开发新的操作系统或者直接开发应用门槛很高。而RISC-V 架构则完全抛弃包袱,借助计算机体系结构经过多年的发展已经成为比较成熟的技术的优势,从轻上路。RISC-V基础指令集只有40多条,加上其他的模块化扩展指令总共也就几十条指令。RISC-V的规范文档仅有145页,而特权架构文档的篇幅也仅为 91页。
(3)易于移植操作系统。现代操作系统都做了特权级指令和用户级指令的分离,特权指今只能由操作系统调用,而用户级指令才能在用户模式调用,保障操作系统的稳定。RISC-V提供了特权级指令和用户级指令,同时提供了详细的 RISC-V 特权级指令规范和 RISC-V 用户级指令规范的详细信息,使开发者能非常方便地移植 Linux 和 UNIX 系统到RISC-V平台上。
(4)模块化设计。RISC-V 架构不仅短小精悍,其不同的部分还能以模块化的方式组纱在一起,从而试图通过一套统一的架构满足各种不同的应用场景。用户能够灵活选择不同的模块组合,来实现自己定制化设备的需要,比如针对小面积低功耗嵌入式场景,用户可以选择RV32IC 组合的指令集,仅使用Machine Mode(机器模式);而高性能应用操作系统场景则可以选择RV32IMFDC 指令集,使用 Machine Mode(机器模式)与User Mode()户模式)两种模式。
(5)完整的工具链。对于设计CPU 来说,工具链是App开发人员和 CPU 交互的窗口,若没有工具链,则对App开发人员开发App要求很高,甚至App开发者无法让CPU 工作起来在CPU 设计中,工具链的开发是一个巨大的工作。如果用RISC-V来设计芯片,芯片设计企业则不用再担心工具链问题,只需专注于芯片设计,RISC-V社区已经提供了完整的工具链 RISC-V 基金会持续维护该工具链。当前RISC-V的支撑已经合并到主要的工具中,比如编评工具链 GCC、仿真工具 QEMU 等。
5、RISC-V的特点
1).没有马上数减法
只有马上数加法指令(addi),没有马上数减法指令(subi),那么减法怎么办?无论是数学上还是程序上,x-y都等价于x+(-y),也就是说可以把减法变成加法,把被减数转化成负数然后再加上减数就实现了和减法一样的功能。正是基于这个原理,RISC-V只提供马上数加法,没有提供马上数减法,如果需要马上数减法,那么就要麻烦编译器把这个马上数转化成负数,然后继续使用加法。这也是 RISC-V将马上数作为有符号数处理的原因。
2). x0 寄存器简化指令集
引入x0 寄存器后,很多特殊指令只需用普通的指令加上 x0 做操作数就能解决,指令的数量减少,处理器的解码电路也简化。
3). 32 位常量
之前使用的ARM 处理器是将马上数表示不下的常量存到常量池,然后用PC相关的LDR指令加载到寄存器。RISC-V 的常量完全是用指令拼接,不需要 Load 指令,使用 Load 指令需要额外的访问周期。RISC-V 单条指令可以表示 12 位的有符号常量,超过 12 位需要两条指令来合成。其中一条指令是 lui,lui 指令加载常量的高 20 位,低 12 位可以用addi指令上去,这个过程需要编译器算出马上数到底是什么,因为 addi 指令实行的是有符号加法,其中的 12 位马上数会先被符号扩展成 32 位的有符号数再参与计算。ARM 的常量加载需要8个字节,一条指令加一个常量;RISC-V的常量加载也是需要8个字节,两条指令,两者占用的程序空间一样。
4).只有小于和大于等于
RISC-V 的比较跳转指令只有 blt 和 bge,即只有小于和大于等于。但大于和小于等于也是需要的,RISC-V用了一个很巧妙的办法用两条指令实现了四条指令的工作,将 blt 的两个参与比较的操作数位置换一下就有了 bgt(大于跳转),将bge 的两个参与比较的操作数位置换一下就有了 ble(小于或等于跳转)。
5).让编译器做更多工作
对 RISC 的理解是处理器尽量少做、编译器尽量多做,这是非常有道理的,毕竟编译的次数远少于实行的次数。上面几点就提到不少要让编译器多做的工作,又例如 B-type 是比较跳转指令的格式,J-type 是长跳转或函数调用指令格式,注意它们的马上数排列次序,把填充这里的马上数交给了链接器的工作。这样排放偏移地址马上数是为了简化处理器的设计,但明显给编译器增加了工作。
6).其他省掉的指令
很多常用的指令都被省掉了,比如nop、move、not、neg 等,但所有这些功能都还有只不过都是用其他的指令来等价实现,比如not 指令是用xorird,rs,-1实现。
6、RISC-V的x0寄存器
Linux 有两个特殊的设备:/dev/zero 和/dev/null。从/dev/zero 可以源源不断地读到0,往dev/null 写的任何内容都被丢弃。如果要创建一个需要填0的文件,就从dev/zero 拷贝,如果要丢弃一些输出,就把输出重定向到/dev/null。RISC-V的x0寄存器就相当于是硬件版的/dev/zero 和/dev/null的组合体。从0读出来的总是0,往x0 写进去的总是被丢弃。所以 x0 提供两种功能:一是提供常量0,在App编程中0可以说是最常用的常量:二是提供一个可以丢弃结果的场所。有了 x0 寄存器,很多本来需要单独指令的操作只要在普通的指令前加上x0 就可以实现。
(1)nop 空指令,RISC-V没有提供nop 指令,而是用addi x0,x0,0来实现空指令,这条addi 使用x0作为目标存器,会丢弃结果,所以这条指令不会对程序状态产生任何影响,和空指令是完全等价的,这就不需要单独的空指令了。
(2)neg 取负数指令,RISC-V用 sub rd,x0,rs 来实现,x0-rs 等价于0-rs,等价于-rs,有了x0,就可以用更普通的减法指令来实现取负数指令。
(3)j跳转指令,RISC-V 没有单独的跳转指令,只有jal跳转链接指令,跳转之前总是要把下一条指令的地址拷贝到寄存器,但是如果用 x0 作为jal 的操作寄存器,即把下-条指令的地址拷贝到 x0,那么效果就等价于j跳转指令了,因为写入 x0 的任何值都会被丢弃。
(4)beqz等于零跳转指令等一系列和0比较的跳转指令,程序中和0比较是相当常见的操作,RISC-V 中和0比较的指令是普通的比较跳转指令,是用 x0 寄存器做指令的操作数。还有很多其他这样的指令,用普通的指令加上 x0 做操作数,就实现了那些没有x0 寄存器的处理器需要单独指令或者需要组合两条指令才能实现的操作。
来源:硬件十万个为什么
|