查看: 1510|回复: 0
收起左侧

RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0

[复制链接]

  离线 

  • TA的每日心情
    奋斗
    2021-3-3 12:32
  • 签到天数: 10 天

    [LV.3]

    发表于 2020-8-23 09:54:12 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 皋陶 于 2020-8-28 10:53 编辑

    RISC-V ISA 学习笔记(1)    指令集介绍及基本指令集RV32I v2.0
    RISC-V ISA 学习笔记(2)    乘除法标准扩展“M”和原子扩展“A” v2.01. 整数乘除法的标准扩展“M”
    RISC-V ISA 学习笔记(3)    单精度浮点标准扩展 “F” v2.0
    RISC-V ISA 学习笔记(4)    函数调用约定+RV32G列表及对应的汇编



    (一)RISC-V指令集介绍

       RISC-V指令集是UC Berkley 大学设计的第五代开源 RISC ISA, V 也可以认为是允许变种(Variations)和向量(Vector)向量实现,数据的并行加速功能也是明确支持目标,是专用硬件发展的一个重要方向。RISC ISA相对于成熟的指令集来说有开源、简捷、可扩展、和后发优势(没有历史包袱,可以绕过很多弯路,也不需要考虑兼容历史指令集)等。


      指令集分为基本部分和扩展部分,基本部分的指令集所有硬件实现都必须有这一部分实现,而扩展部分则是可选的。扩展部分又分为标准扩展和非标准扩展。例如,乘除法、单双精度的浮点、原子操作就在标准扩展子集中。


    “I” 基本整数集,其中包含整数的基本计算、Load/Store和控制流,所有的硬件实现都必须包含这一部分。


    “M” 标准整数乘除法扩展集,增加了整数寄存器中的乘除法指令。


    “A” 标准操作原子扩展集,增加对储存器的原子读、写、修改和处理器间的同步。


    “F” 标准单精度浮点扩展集,增加了浮点寄存器、计算指令、L/S指令。


    “D” 标准双精度扩展集,扩展双精度浮点寄存器,双精度计算指令、L/S指令。


     I+M+F+A+D 被缩写为 “G” ,共同组成通用的标量指令。


    在后续ISA的版本迭代过程中,RV32G和RV64G总是保持不变。


      基本RISC-V ISA具有32位固定长度,并且需要32位地址对齐。但是也支持变长扩展,要求指令长度为16位整数倍,16位地址对齐。

      32位指令最低2位为“11”,而16位变长指令可以是“00、01、10”,48位指令低5位位全1,64位指令低6位全1。任何长度的指令,如果所有位全0或全1,都认为是非法指令,前者跳入填满0的储存区域,后者通常意味着总线或储存器损坏。


      另外,RISC-V默认用小端储存系统,但非标准变种中可以支持大端或者双端储存系统。


    另外专业术语:

    异常:RISC-V线程中出现了指令相关的非正常情况。
    自陷:RISC-V线程中出现了指令相关的异常情况,控制同步传输到自陷处理函数(一般在高特权环境中执行)。
    中断:RISC-V线程外异步出现了一个事件,如果需要处理则需要选择某条指令来接收,并顺序产生自陷。


    (二)RV32I 基本整数指令集

      基本整数子集用户可见状态为31个寄存器x1~x31,用来保存整数值,其中x0是常数0。还有一个用户可见的寄存器pc用来保存当前指令的地址。

    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(1)



    1. 基本指令格式

      4种核心指令格式(R/I/S/U),都是固定32位长度的指令。基于立即数的处理,还有SB/UI这两种指令格式的变种。


    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(2)


      在所有格式中,RISC-V ISA将源寄存器(rs1和rs2)和目标寄存器(rd)固定在同样的位 置,以简化指令译码。在指令中,立即数被打包,朝着最左边可用位的方向,并且已分配好以减少硬件复杂度。特别地,所有立即数的符号位总是在指令的第31位,以加速符号扩展电路。


    2. 整数计算指令

      整数计算指令要么使用I类格式编码R-I操作,要么使用R类格式编码R-R操作。其目标都是rd,不会产生异常。这里没有支持溢出检测指令,uint加法和int数组边界检测用一条分支即可完成,有符号数的加法溢出检测则需要几条指令(与被加数是立即数还是变量有关)。



    R-I类指令


     ADDI/SLTI(U)/ANDI/ORI/XORI

    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(3)


      ADDI—> rs1+=imm(12bit),溢出被忽略。ADDI rd,rs1,0 ==> 伪码 mv rd, rs1


      SLTI(set less than imm), if(rs1<imm) rd=1; else rd=0; 其中rs1和imm都被当作有符号数。


      SLTIU 功能同SLTI, 不过rs1和imm被当作无符号数。SLTIU rd,rs1,1 {if(rs1= =0)rd=1;else rd=0;} = = 汇编 SEQZ rd, rs

      ANDI、ORI、XORI均为逻辑操作,在寄存器rs1和符号扩展位上的12bit按位AND、OR、XOR。


      比如 XORI rd,rs1,-1 被用来按位取反 NOT rd,rs 。


     SLLI/SRLI/SRAI


    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(4)


      rs1被移位imm[4:0]次,SLLI/SRLI分别是逻辑左右移(空出来的位填0),SRAI是算术右移(符号位的单独处理,正数填充0,负数填充1)。
     LUI/AUIPC


    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(5)


      LUI用于构建32位常数,LUI将imm放到rd的高20位,低12位填0.


      AUIPC(add upper immediate to pc) 用imm构建一个偏移量的高20位,低12位填0,并将此偏移加到pc上,将结果写入rd。

      AUIPC+JALR可以将控制转移到任意32位相对地址,而加上一条12位立即数偏移的load/store指令就可以访问任意32位pc相对数据地址。


    R-R类指令

     ADD/SLT/SLTU/AND/OR/XOR/SLL/SRL/SUB/SRA


    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(6)


      ADD/SUB分别用于执行加减法、忽略溢出。


      SLT/SLTU分别用于执行有无符号数的比较 if rs1<rs2)rd=1;else rd=0; 同样,STLU rd,x0,rs2 用来判定rs2 是否为0.


      SLL/SRL/SRA 分别逻辑左右移,算术右移。被移位的是 rs1,移动rs2的低5位。


    NOP指令


      此指令不改变任何用户的可见状态,用于pc的向前推进。 被编码为 ADDI x0,x0,0

    3. 控制转移指令

      RV32I提供了两类控制转移指令,无条件跳转和条件分支。并且没有在体系结构中可见的分支延迟槽。


    无条件跳转


    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(7)


      JAL在立即数处编码了一个有符号偏移量,这个偏移量加到pc上后形成跳转目标地址,并将跳转指令后面指令的地址(pc+4)加载到rd,跳转范围为±1MB。标准软件调用约定使用寄存器x1来作为返回地址寄存器。


    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(8)


      JALR(jump and link register) 通过有符号立即数加上rs1,然后将结果的最低位设置为0,作为目标地址,将跳转指令后面的地址存到rd中。


      如果目标地址没有对齐到32位,JAL和JALR指令均会产生一个非对齐指令取址异常。


      所有无条件跳转指令都是用pc相对寻址,有助于支持位置无关代码。JALR可以用来跳转到任何32位绝对地址空间。


      首先LUI将目标地址的高20位加载到rs1中,然后JALR可以加上低12位。事实上,绝大多数JALR指令的使用要么是一个立即数0,要么就是配合LUI或者AUIPC来跳转到32位地址空间。


    条件分支


      所有的分支指令使用SB类指令格式。12位立即数编码了以2字节倍数的有符号偏移量,并被加到当前pc上,生成目标地址。于是条件分支的范围是±4KB。


    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(9)


      BEQ/BNQ if (rs1==/!=rs2) Jmp


      BLT/BLTU if(rs1<rs2) Jmp


      BGT/BLEU if (ifrs1>rs2) Jmp


      其他的如 BGT/BGTU/BLE/BLEU可以通过前面的比较指令组合来实现。


      优化过程中,频率较大的分支放在直线位置上,较小的分支被放到跳转分支上,尽量减少跳转。无条件跳转应该总是用JAL指令而不是用永为真的条件跳转。 JAL既可以有更大的跳转范围,也不会占用分支预测器的条件预测表。


    4. Load/Store指令

      RV32I中只有load和store指令可以访问储存器,其他指令只能操作寄存器。


    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(10)


      Load 为I类格式,而Store为S类指令格式。load类储存器地址是通过rs1+imm(偏移来实现),都是将储存器值复制到寄存器中。


      store将rs2中的值复制储存器中。


      LW 将32位值复制到rd中,LH从储存器中读取16位,然后将其符号扩展到32位,保存到dr中。LHU指令读取存储器16位,然后0扩展到32位,再保存到rd中。LB/LBU则是读取8位。SW/SH/SB分别将寄存器rs2中的低32/16/8/位到储存器中。


      load和store操作的数据地址应该与操作的数据类型长度保持地址对齐,否则会被分解成两次访问,还需要额外的同步来保证原子性。


      例如:将x2中的32位指令,保存到x3指向的存储器


         sh x2, 0(x3) // 将指令的低半部分保存到第一个包裹中


         srli x2, x2, 16 // 将高位移动到低位,覆盖x2


         sh x2, 2(x3) // 将高位保存到第二个包裹中


    5.存储器模型

      RISC-V ISA允许在单一用户地址空间中支持多个线程同时执行。每个线程拥有自己的寄存器和程序计数器,并执行一段互不相关的指令流。 线程的创建和管理根据环境来定义,线程间的通讯可以根据环境或者共享储存器系统来通讯。RISC-V每个线程看到自己的存储操作就好像是按照程序中顺序执行的一样。线程间的存储模型在不同线程间的储存器上操作时需要FENCE指令来确保某些特定的顺序。


      FENCE就是一个栅栏操作,其前后指令之间不能被乱序,可用于线程间的同步。


      FENCE.I用于同步指令和序列流,用于线程内的同步。


    6. 控制状态寄存器指令(CSR)

       用户级的CSR指令只能访问少数几个只读寄存器。



    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(11)


      CSRRW(Atomic Read/write CSR)原子性低交换CSR和整数寄存器中的值。读取CSR 中的旧值将其0扩展到XLEN位,写入整数寄存器rd中。rs1中的值被写到CSR中。


      CSRRS(Atomic Read and Set Bits in CSR) 读取CSR的值,0扩展到XLEN位,写入整数寄存器rd中。rs1中的值被当作掩码指明CSR中哪些位置被置1。rs1中为1的位会导致CSR中对应的位被置1,其他位不受影响(CSR|=rs1)。


      CSRRC(Atomic Read and Clear Bits in CSR)功能同上,但是rs1中的值用来指明哪些位置零,即rs1中为1的位CSR对应的位将会被置0,其他位不受影响.


      CSRRWI/CSRRSI/CSRRCI分别对应上面的几条指令,但是被扩展的是5位立即数而不是rs1寄存器的值.


      读取CSR的汇编伪指令 CSRR 被编码为 CSRRS rd,csr,x0


      写入CSR的汇编位指令 CSRW 被编码为CRSRW x0,csr,rs1


      伪指令 CSRWI csr,zimm 被编码为 CSRRWI x0,csr,zimm


      当不需要CSR旧值时, 同来设置和清除CSR中的位 CSRS/CSRC csr,rs1 CSRSI/CSRCI csr,zimm


    定时器和计数器
    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(12)


      RV32I提供了多个用户级只读的64位计数器,它们被映射到一个12位的CSR地址空间中, 它们可以使用CSRRS指令以32位片段的形式进行访问。


      RDCYCLE 伪指令用来读取cycle CSR的低XLEN位,这个值是硬件线程开始执行以来的时钟周期数.RDCYCLEH用于读取高32位.


      RDTIME读取time CSR的低XLEN位,这个数值是从过去任意时刻开始以来的在墙实时时间计数值.RDTIMEH是读取高32位.


      RDINSTRET 读取instret CSR的低XLEN位,用于计数本硬件线程的线程退休指令数值.


    这些计数器必须提供,而且可以被用户以较小代价访问.当然允许提供额外的寄存器以帮助性能诊断.


    环境调用和断点
    国内芯片技术交流-RISC-V ISA 学习笔记(1) 指令集介绍及基本指令集RV32I v2.0risc-v单片机中文社区(13)


      ECALL用于向环境(通常是操作系统)发出一个请求,系统环境ABI具体确定参数如何让传递,但是这些参数在整数寄存器中的位置应该确定.
      EBREAK 被调试器使用,用来将控制权传送回调试器.

    待续…






    上一篇:RISC-V 资源了解下
    下一篇:Risc-V简要概括
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条



    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2024-3-29 23:35 , Processed in 0.878981 second(s), 48 queries .

    快速回复 返回顶部 返回列表