Risk-V 初步理解(每日更新)

想要整整硬件安全检测,先得了解了解咱们的硬件开发。

 

首先得看看Risc-V的手册:

RV用到的ISA为模块型,即采用的是基础ISA,代替了以往继承代价极大的增量式ISA,从而减少了成本。

RV的ISA较为简单,虽然对比复杂ISA在同一任务上的执行上可能会采用更多简单指令,但是可以通过加快时钟频率或者降低CPI(平均单条指令周期)减少代价。

跳出来补充一句,RV肯定得适用于32位和64位两个版本。

接下来是RV的标准扩展、乘除操作(RV32M),浮点运算(RV32F,RV32D),原子操作(RV32A),压缩拓展(即将16位指令限制到32位指令,但是代价极小),向量拓展(对比于单指令逐条执行,这里提出了指令向量的概念),RV的系统指令(介绍RV如何实现分页,如何针对机器、用户、开发监督者不同身份赋予不同权限)。

 

(1)RV32I32risc-v整数指令集

 

首先,RISC-V 中没有字节或半字宽度的整数计算操作。操作始终 是以完整的寄存器宽度。

而ARM-32

(RV32I 也不包含乘法和除法,它们包含在可选的 RV32M 扩展中(参见第 4 章)。与 ARM-32 和 x86-32 不同,即使处理器没有添加乘除法扩展,下面的乘除实现都是扩展的!!!)

1. 寄存器

      32x寄存器,RV32x reg32位宽

      x0:硬连线 常数0

      x1-x3131个通用reg

      返回地址:没有强制要求哪一个x作为lr,但是一般用x1

      pc:额外的用户可见寄存器

 

3. 基本指令格式

      四种基础指令格式 R/I/S/U

      imm:立即数

      rs1:源寄存器1

      rs2:源寄存器2

      rd:目标寄存器

      opcode:操作码

     

但是讲道理,其实Risc-V的基础指令有六种,   R I S B U J

R-type  用于 寄存器—寄存器 操作

I-type   用于 短立即数 和 访存load 操作

 

S-type  用于 访存store 操作

 

B-type  用于 条件跳转 操作

U-type  用于 长立即数 操作

J-type  用于 无条件跳转

 

4. 立即数

      各种指令格式下,拼装出立即数

      inst[i]:指令第i

     

5. 整数计算

      使用R或者I类指令

      R类:寄存器-立即数

      I类:寄存器-寄存器

      整数计算不会造成运算异常

     

      寄存器-立即数:

           ADDI:将12位有符号立即数和rs相加,溢出忽略,直接使用结果的最低32bit,并存入rd

                         伪指令MV"MV rd,rs"实际上是"ADDI rd, rs, 0"

           SLTI:如果rs小于立即数(都是有符号整数),rd1,否则置0

           SLTIU:和SLTI一致,不过都是无符号数

                            伪指令SEQZ"SEQZ rd, rs" 实际上是 "SLTIU rd, rs1, 1"

           ANDI/ORI/XORIrs与有符号12位立即数进行and,or,xor操作

                 伪指令NOT"NOT rd, rs"实际上是"XORI rd, rs1, -1"

          

           shiftI类指令格式

                 SLLI:逻辑左移,低位移入0

                 SRLI:逻辑右移,高位移入0

                 SRAI:算数右移,符号移入高位

          

           u类指令格式

                 LUI:创建32位无符号整数,存放立即数到rd的高20位,低20位置0

                 AUIPC:创建pc的相对地址,pc+无符号立即数(偏移量)=>rd        

     

      寄存器-寄存器:

           ADD/SUB:rs1(+/-)rs2 => rd

           SLT/SLTU: 如果rs1<rs2rd1; 否则rd0

           AND/OR/XOR: rs1rs2进行and,or,xor操作

           SLL/SRL/SRA: "寄存器-立即数"指令一致,将r2的低5位作为立即数即可         

     

      NOP指令:

           实际上是ADDI x0,x0,0

     

6. 控制传输指令

      1)非条件跳转

           JALJ类指令,立即数+pc为跳转目标,rd存放pc+4(返回地址)

                 跳转范围为pc(+/-)1MB

           JALRI类指令,rs+立即数为跳转目标,rd存放pc+4(返回地址)

                 实现远跳转

     

      2)条件跳转

           所有分支指令使用B类指令格式,12位立即数+pc作为目标

           跳转范围为pc(+/-)4KB

          

           BEQ/BNErs1(==/!=)rs2, 分别在相等或者不等时,发生跳转

           BLTrs1 < rs2, 跳转

           BGErs1 >= rs2, 跳转

          

7. 加载存储指令

      RV32I是一个加载/存储架构,只有load/store能访问内存,运算指令只操作寄存器

      loadI类指令,storeS类指令

     

      LOADrs作为基地址,加上有符号的偏移,读取到rd寄存器

      STORErs1作为基地址加上有符号的偏移,作为内存地址,写入内容为rs2

     

8. 内存模型

      RISC-V ISA支持单地址空间上多线程运行,每个hardware thread都有都有自己的寄存器状态

     

9. 控制状态寄存器指令

           寄存器-寄存器:读//修改 CSR

                 CSRRWAtomic Read/Write CSR

                      读取CSR的值存入rd寄存器,并将rs存入CSR

                      另外:如果rdx0,将不会执行

                

                 CSRRSAtomic Read and Set Bits in CSR

                      读取CSR的值存入rd寄存器,并根据rs中高位对CSR1

                      另外:如果rsx0,将不会执行

                

                 CSRRCAtomic Read and Clear Bits in CSR

                      读取CSR的值存入rd寄存器,并根据rs中高位对CSR0

                      另外:如果rsx0,将不会执行

 

           立即数-寄存器:读//修改 CSR

                 CSRRWI/CSRRSI/CSRRCI

                 CSRRW类寄存器中的rs换成立即数

                 另外:如果立即数为0,将不会执行 

 

           用户级系统指令:时钟和计数器

                 RV32I提供三个64位只读用户级寄存器:RDCYCLE[H]/RDTIME[H]/RDINSTRET[H]

                 使用CSRRS读取这三个寄存器的高32 bit

 

                 RDCYCLE:时钟周期计数

                 RDTIME:时间 tick

                 RDINSTRET:指令数

10. 环境调用和断点

      ECALL

      EBREAK

 

(2)RV32I,ARM-32,MIPS-32 和 x86-32 指令集的插入排序对比

 

将上述的C语言版本的插入排序编译后,得到下图中:在不同指令集下的指令数与字节数对比。

 

RISC-V 使用内存映射 I / O 而不是像 x86-32 一样,使用 in,ins, insb,insw 和 out,out,outsb 等指令来进行 I/O。为支持字符串处理,RISC-V 实现了 字节存取,而不是像 x86-32 那样实现了 rep,movs,coms,scas,lods 等 16 条特殊的 字符串处理指令。 
可以看到RV成本更低了。

 

(3)RV相关的汇编语言

这里的汇编就略过了,手册上讲的是C高级编程语言 如何 编译为 低级的汇编语言。

(本科期间介绍的汇编嘛,就是需要进行:   词法、语法、语义啥的检测,再做个代码优化(可能用到树)就能生成目标的代码啦,当然异常检测和表格保护还是一直要做的。这里贴一张百度大大的图)

 

(4)函数调用的规范

函数调用过程通常分为 6 个阶段[Patterson and Hennessy 2017]。

 

1. 将参数存储到函数能够访问到的位置;                     (合理存参)

2. 跳转到函数开始位置(使用 RV32I 的 jal 指令);   (无条件跳转,函数运行)

3. 获取函数需要的局部存储资源,按需保存寄存器;   (资源存放于寄存器,减少访存代价)

4. 执行函数中的指令;        (指令执行)

5. 将返回值存储到调用者能够访问到的位置,恢复寄存器,释放局部存储资源; (释放)

6. 返回调用函数的位置(使用 ret 指令)。

 

另外在函数调用过程中,因为RV鼓励尽量将待用数据存寄存器中,所以其对寄存器的应用还是很多的。

保存寄存器:在函数调用前后,寄存器中的值不变

临时寄存器:在函数调用的过程中,不保留部分寄存器存储的值

 

(5)汇编具体实现部分

略了略了   反正就是

汇编器 

也就是生成目标代码的工具。这里Risc-V和X86、ARM存在差异。

链接器(静态链接与动态链接)<静态链接开销大>     

(1)在程序运行前所有的库都进行了链接和加载,这样的静态链接代价可见十分大。并且强制静态链接可能仍然调用旧的存有bug的代码版本。

(2)而动态链接,只有第一次被调用时才会加载和链接,后面都会使用“快速链接”(只有一次动态开销)

并且每次都会调用最新的库函数。多次调用同一个库时,库代码只会加载一次哦!(代价更小了)

 

加载器<针对文件执行,加载到内存中>

如今的“加载器”就是操作 系统。换句话说,加载 a.out 是操作系统众多的任务之一。

(6)总结总结Risc-V在指令集与汇编过程中的优点

 

  • 汇编器向 RISC-V ISA 中增加了 60 条伪指令,使得 RISC-V 代码更易于读写,并且不增 加硬件开销。
  • 将一个寄存器硬编码为 0 使得其中许多伪指令更容易实现。
  • 使用加载高位立即 数(lui)和程序计数器与高位立即数相加(auipc)两条指令,简化了编译器和链接器寻找 外部数据/函数的地址的过程。
  • 使用相对地址转移的代码与位置无关,减少了链接器的工作。
  • 大量的寄存器减少了寄存器保存和恢复的次数,加速函数调用和返回。

总结:

             RISC-V 提供了一系列简单又有影响力的机制,降低成本,提高性能,并且使得编写程序更加容易。 
 

(7)乘除法的拓展(RV 32M)

前面讲到,Risc-I并未直接实现乘除法。RV32M 向 RV32I 中添加了整数乘法和除法指令。

  • 针对(多字?)有符号数与无符号数,分别提供了不同指令。
  • RV 32I 检查除零很容易
  • 两个出发指令可以检查乘法溢出

总结:为了为嵌入式应用提供最小的 RISC-V 处理器,乘法和除法被归入 RISC-V 的第一个可 选标准扩展的一部分 RV32M。许多 RISC-V 处理器将包括 RV32M。

 

(8)单精度和双精度浮点数 ( RV32F 和 RV32D)

 虽然二者时分开的,有着单独的指令集与专用寄存器。但是二者经常成双成对的出现。       2020/9/16   22:33

 

 

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值