RISC-V

发布时间 2023-04-01 16:05:20作者: 摧残一生

RISC-V是一个通用的指令集架构(ISA),类似于一个标准,当硬件和软件分别遵循RISC-V标准时,就能无缝衔接,至于硬件后面是否有芯片解码,那就是商业化硬件自身的问题了(例如Type-C是一个开放性的标准接口,但是有些厂商会在使用时封装一层,达到商业化的目的)。

  • 与ARM的不同

    ARM是增量式的ISA,因为向前兼容问题,ARM的指令集已经很大。而RISC-V是模块化的,核心是RV32I的指令集,其他扩展模块可通过附加的方式进行扩展。例如:基本的是RV32I,当添加乘法(RV32M)后则表示为RV32IM。添加单精度(RV32F)和双精度(RV32D)时,表示为RV32FD,依次类推。

  • ISA设计衡量的标准

    • 成本
    • 简洁性
    • 性能
    • 架构和具体实现的分离
    • 提升空间
    • 程序大小
    • 易于编程
  • 指令集一览

RV32I 基础指令集

  • 六种基本指令

    • 用于寄存器-寄存器操作的 R 类型指令
    • 用 于短立即数和访存 load 操作的 I 型指令
    • 用于访存 store 操作的 S 型指令
    • 用于条件跳转操 作的 B 类型指令,
    • 用于长立即数的 U 型指令
    • 用于无条件跳转的 J 型指令
  • RISC-V的指令格式,以基本指令为例

    • 汇编与RISC-V的对应关系

      指令 说明
      汇编语言 RISC-V指令 add x9, x20, x21 x9=x20+x21
      机器语言 十进制表示 0 21 20 0 9 51 0 0 和 51 表示执行加法操作,21表示寄存器编号(21表示x21),20表示另一个源操作数,9表示接收总和的寄存器编
      机器语言 二进制-R型 0000000 7位 10101 5位 10100 5位 000 3位 01001 5位 0110011 7位 指令格式,共32位
      R型-寄存器 二进制说明 funct7 操作码字段 rs2 原操作寄存器 rs1 源操作数寄存器 funct3 操作码字段 rd 目标操作数寄存器 opcode 操作码
      I型-常数 二进制-I型 immediate 12位 rs1 5位 funct3 3位 rd 5位 opcode 7位 举例addi
      S型-基址和存储数据 二进制-S型 immediate 7位 rs2 5位 rs1 5位 funct3 3位 immediate 位 opcode 7位 ld x9, 64(x22)
  • C语言与汇编说明

  • RISC-V寄存器 共32个寄存器

    名称 寄存器号 用途 接口名称 是否保留
    x0 0 常数0 zero
    x1 1 返回赋值 ra 不保留
    x2 2 栈指针 sp 保留
    x3 3 全局指针 gp
    x4 4 线程指针 tp
    x5 5 临时,备用链接寄存器 t0 不保留
    x6~x7 6~7 临时寄存器 t1 t2 不保留
    x8 8 保存,帧指针 s0/fp 保留
    x9 9 保存 s1 保留
    x10~x11 10~11 函数参数、返回值 a0,a1 不保留
    x12~x17 12~17 函数参数 a2-7 不保留
    x18~x27 18~27 保存寄存器 s2-11 保留
    x27~x31 27~31 临时寄存器 t3-6 不保留
    • 各寄存器情况

      保存 不保存
      保存寄存器:x8, x9, x18~x27 临时寄存器:x5~x7, x28~x31
      栈指针寄存器:x2(sp) 参数/结果寄存器:x10~x17
      帧指针:x8(fp)
      返回地址:x1(ra)
      栈指针以上的栈 栈指针一下的栈

RISC-V汇编语言

  • 函数调用规范

    • 将参数存储到函数能够访问到的位置;
    • 跳转到函数开始位置(使用 RV32I 的 jal 指令)
    • 获取函数需要的局部存储资源,按需保存寄存器;
    • 执行函数中的指令;
    • 将返回值存储到调用者能够访问到的位置,恢复寄存器,释放局部存储资源;
    • 返回调用函数的位置(使用 ret 指令)。
  • RISC-V函数入口及出口

    # 入口
    entry_label:
    	addi sp, sp, -framesize # 调整栈指针(sp 寄存器)分配栈帧
    	sw ra, framesize-4(sp)  #保存返回地址(ra 寄存器)
    # 出口
    	lw ra, framesize-4(sp)	# 恢复返回地址
    	addi sp, sp, framesize	# 释放栈帧空间
    	ret						# 返回调用点
    
  • 汇编器

    • 指示符

RV32M:乘法和除法指令

RV32F 和 RV32D:单/双精度指令

RV32I中寄存器x0是常量,而f0则与其他寄存器一样,是可变寄存器。

RV32A:原子指令

  • 内存原子操作

    对内存中的操作数执行一个原子操作,并将目标寄存器设置为操作前的内存 值。原子表示内存读写之间的过程不会被打断,内存值也不会被其它处理器修改。- 类似于多线程中的原子值

  • 加载保留/条件存储

    加载保留读取一个内存 字,存入目标寄存器中,并留下这个字的保留记录。

RV32C:压缩指令

每条短指令必须和一条标准的 32 位 RISC-V 指令一一 对应

  • 压缩指令原则

    1.对十个常用寄存器(a0-a5,s0-s1,sp 以及 ra)访问的频率远超过其他寄存器;

    2.许多指令的写入目标是它的源操作数之一;

    3.立即数往往很小,而且有些指令比 较喜欢某些特定的立即数

  • 举例

    # 举例1
    addi a4, x0, 1		# i=1
    # 使用16位指令为:
    c.li a4, 1			# i=1
    # 举例2
    # a2是指向a[j]的指针
    add a2, x0, a3
    # 使用16位指令为:
    c.mv a2, a3
    

RV32V:向量

  • 将向量的长度和每个时钟周期可以进行的最大操作数分 离,是向量体系结构的关键所在:向量微架构可以灵活地设计数据并行硬件而不会影响到 程序员,程序员可以不用重写代码就享受到长向量带来的好处。

  • 寄存器以v开头,每个向量寄存器的元素个数不同,主要取决于处理器的设计者。