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

RISC-V ISA 学习笔记(2) 乘除法标准扩展“M”和原子扩展“A”

[复制链接]

  离线 

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

    [LV.3]

    发表于 2020-8-28 10:38:45 | 显示全部楼层 |阅读模式

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

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

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

    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 ISA 学习笔记(2) 乘除法标准扩展“M”和原子扩展“A” v2.0
    1. 整数乘除法的标准扩展“M”

      整数乘法和除法的指令扩展“M”包含对两个整数寄存器中的值做乘、除法的指令。而之所以把乘除法单独列出来,是为了简化低端硬件的实现,毕竟某些场景极少用到整数乘除法,不用单独实现。


    (1) 乘法操作

       MUL/MULH[S][H]/MULW

    国内芯片技术交流-RISC-V ISA 学习笔记(2) 乘除法标准扩展“M”和原子扩展“A”risc-v单片机中文社区(1)


      MUL执行一次两个XLEN位的带符号乘法rs1×rs2,并将结果的低XLEN存到rd中,忽略溢出。


    MULH、MULHU、MULHSU执行相同的乘法,分别针对的对象为有符号×有符号、无符号×无符号、 有符号×无符号乘法,并将运算结果2×XLEN位中的高XLEN位返回。


      如果同时需要结果的高、低XLEN位,一般代码顺序为:


        MULH[[S]U] rdh,rs1,rs2 ;
        MUL rdl,rs1,rs2;


      (源寄存器区分符必须按照同样的顺序,并且 rdh 不能是 rs1 或者 rs2 )。允许硬件实现时将其融合为单一操作,而不是分两次操作。MULW属于RV64I暂不表(>_< 暂时用不到,就不写了)。


    (2) 除法操作

       DIV/DIVU/REM/REMU


    国内芯片技术交流-RISC-V ISA 学习笔记(2) 乘除法标准扩展“M”和原子扩展“A”risc-v单片机中文社区(2)


      DIV/DIVU分别做带符号和无符号的整数除法,REM/REMU分别做带符号和无符号的取余。


      如果同时要商和余数,建议代码为


        DIV[U] rdq,rs1,rs2;
        REM[U] rdq,rs1,rs2;


      同样建议硬件实现能够把这两个操作融合为单一操作。


    另外除法溢出语义如下:


    国内芯片技术交流-RISC-V ISA 学习笔记(2) 乘除法标准扩展“M”和原子扩展“A”risc-v单片机中文社区(3)



    2. 标注扩展"A" 原子操作

      原子性包含了对储存器执行原子性的读、写、修改等操作,以支持不同线程之间的同步。有两种原子性的操作包括load-reserved/store-conditional和fetch-and-op存储器指令。


      两种指令都支持各种存储器的一致性排序,包括乱序、获取、释放和顺序一致性语义。


    (1)原子操作的指定顺序

      基本的RISC-V ISA 有一个宽泛约束的储存模型,使用FENCE来加强顺序性约束。地址空间被执行环境分为两类:存储器域和IO域,FENCE指令提供其中一个或者两个地址域实现按序访问。


    每一条原子性指令有两位(aq、 rl位)用于指定其他RISC-V线程看到的额外存储器操作的顺序性。


      如果两个均为0,则没有任何其他顺序性约束强加于原子操作。


      只有aq为1, 获取访问(acquire access)—— 在储存器操作被硬件执行之前,任务序列的所有后续访问指令对于硬件来讲都是看不到的(不会被执行)。


      只有rl为1, 释放访问(release access) ——在储存器操作完成前所有释放操作无法被硬件看到。


      aq和rl均为1,顺序一致性(sequentially consistent) ——即储存器操作完成前,其后的操作不可见;存储操作完成后,其前面的操作不可见。也就是操作对于其他任何线程来讲其操作都是顺序一致的,即严格按照代码逻辑来走,乱序无效。


      这两个bit使得两个地址域(存储器域和I/O域)中一个的访问具有顺序,这依赖于原子性指令正在访问哪个域。对另外一个域的访问并没有隐式的顺序约束,需要使用一条FENCE指令来在两个域实现按序访问(应该是FENCE指令只作用在其中的一个域)。


    (2) load-reserved/store-conditional 指令

    国内芯片技术交流-RISC-V ISA 学习笔记(2) 乘除法标准扩展“M”和原子扩展“A”risc-v单片机中文社区(4)


      单字长储存器的复杂原子操作是通过LR/SC指令来完成的。


      LR将rs1所指的地址处的一个字长的数据读出经符号扩展后放入rd,同时在储存器地址上注册一个监视预约。SC将rs2所指地址中的一个字长的数据保存到rs1所指的存储器地址中,并提供一个此地址的监视预约。如果执行成功将0写入rd,否则写非零值。总的来说,就是LR从储存器读取一个值,并且将让此地址处于被监控状态,检查其他线程是访问过此地址。SC指令如果发现此期间此地址没有被修改则将新值填入此地址。因此,一个原子的LR/SC指令对就是LR读取该值做一些计算后并试图保存新值,如果失败则重新开始这个操作。


      虽然比较-交换指令(CAS)和LR/SC指令也可以用来构建lock-free的数据结构,但是RISCV偏向选择LR/SC来实现。因为,


      <1>. LR/SC监视此地址的所有访问,而不仅仅是检查数值是否发生变化。


      <2>. CAS指令需要一种新的整数指令格式,以支持3个源操作数,还有一个不同存储器消息格式,导致为硬件实现结构复杂化。


      <3>. LR/SC提供了比CAS更加高效的实现。


      为了满足代码的可移植性,LR/SC错误代码在目前版本中仅仅要求错误代码为“非零”,具体错误码没有指定,硬件实现中可自定义。在标准扩展“A”中,为确保指令序列能够成功执行,需要对LR/SC指令序列做出必要的限定。


      LR/SC序列的静态代码加上失败重试这个序列的代码不能超过16条。


      而且LR/SC指令之间的代码只能由子集 “I” 中的指令构成(不会生成异常),并需要排除load、store、向后跳转或者分支指令、FENCE、FENCE.I和SYSTEM指令。


      失败后重试代码可以包含向后的跳转和分支,其他要求不变。SC指令必须和最近执行的LR地址相同。


      真正的硬件实现中可以用任意储存器空间子集,对于单硬件线程而言可以在这个储存器空间上拥有多个LR指令的预约。


      如果在此SC指令和前面最近的LR指令之间没有其他线程访问这个地址,则预约成功,如果前面的LR指令用了其他别名已经预约了这个地址,则会预约失败。


      如果有来自其他硬件线程对此地址所监控的储存器进行访问、或硬件线程上有一个上下文切换,或者此线程上有一条特权异常指令返回,那么SC就必须失败。


      LR/SC指令可以用来构建lock-free数据结构。一个用LR/SC实现一个比较交换的函数


    国内芯片技术交流-RISC-V ISA 学习笔记(2) 乘除法标准扩展“M”和原子扩展“A”risc-v单片机中文社区(5)


      在处理的LR指令之前其他RISC-V线程看不到SC指令,而在LR指令和一个成功的SC指令之间任何线程的都看不到这个存储器的操作。


      这个 LR/SC序列可以通过设置SC指令的aq位而被赋予获取(acquire)语义。这个LR/SC序列可以通过设置LR指令的rl位而被赋予释放(release)语义。


      设置LR指令的aq位和rl位都为1,设置SC指令的aq位为1,使得LR/SC指令序列对于其他操作来说都是顺序一致的。


      如果LR和SC的所有aq、rl位都被清零,那么在来自同一个RISC-V线程的附近存储器操作之前或之后,可以看到LR/SC指令序列。


      并行归约操作就很适合用LR/SC 序列来实现。


    (3)原子性储存器操作

    国内芯片技术交流-RISC-V ISA 学习笔记(2) 乘除法标准扩展“M”和原子扩展“A”risc-v单片机中文社区(6)


      原子性储存器操作(AMO)为多处理器同步执行读、写、修改操作,并编码为R类指令格式。


      这些AMO指令原子性地从rs1地址读取数据值,将这个值写入rd,在这个值和rs2的原始值上做二进制操作、然后把结果保存到rs 所指的储存器中。AMO指令可以对储存器中的64位或者32位字进行操作。


      保存在rs1中的地址必须与操作数的大小对齐,否则会产生一个非对齐地址异常。


      支持的储存器操作包括SWAP、ADD、AND、OR、XOR、MAX[U]/MIN[U]。


      没有额外顺序性约束,这些指令可以用于实现并行规约操作,返回值通过写x0而丢掉。


    AMO指令也可用于提供顺序化一致性load和store。


      一个顺序化的load可以实现为一条AMOADD x0指令,其aq位和rl位都设置为1。


      一个顺序化一致性store可以实现为一条 AMOSWP指令,它将旧值写入x0,其aq位和rl位都设置为1。


      一个使用test-and-set spinlock实现关键段保护的示例代码序列如图 6.2所示。


      注意到在 关键段前面,第一个AMO指令设置了aq位,以便按序获取锁,而在释放锁之前,第二个AMO 指令设置了rl位,以便按序进入关键段。


    国内芯片技术交流-RISC-V ISA 学习笔记(2) 乘除法标准扩展“M”和原子扩展“A”risc-v单片机中文社区(7)


    待续。。。。

    本篇完,感谢关注:RISC-V单片机中文网






    上一篇:恭喜!“中国芯片IP第一股” 登陆科创板
    下一篇:RISC-V单片机快速入门05-玩转ESP8266 WIFI模块②
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

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



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

    GMT+8, 2024-4-16 17:35 , Processed in 0.970744 second(s), 48 queries .

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