序列重新排序以解决RISC-V组装中的数据危险

问题描述

对于下面的RISC-V代码序列,我试图确定数据转发无法解决的数据危险。通过重新排序代码序列可以克服危险吗?如果是,任何人都可以显示新序列吗?

这是我的代码

loop: slli  s2,s1,2
      add   s3,s2,s0
      lw    t0,0(s3)
      add   t1,t2,t0
      sw    t1,20(s3)
      addi  s1,1
      beq   s1,s5,loop

解决方法

通过转发可以解决哪些数据危险完全取决于您所使用的RISC-V体系结构的特定实现。我将假设使用Patterson&Hennessey教科书中介绍的具有转发功能的传统5阶段RISC-V管道,并为您的问题加分。

此流水线具有阶段指令提取(IF),指令解码(ID),执行(EX),内存(MEM)和写回(WB)。执行阶段计算寄存器-寄存器和寄存器立即操作的值,并计算存储器(lw / sw)和控制传输(分支/跳转)操作的地址,并且存储器级读取lw的数据并写入sw的数据。数据可以从执行,存储或写回阶段的末尾转发到上一个阶段的开头,以用于后续指令。

在您包含的代码段中,有5种数据危害:

(1)slli s2,s1,2add s3,s2,s0,用于寄存器s2

在这里,寄存器s2slli写入并由add读取。新值是在第一条指令的EX阶段结束时计算的,而在下一条指令的EX阶段开始时需要的,因此可以通过转发来解决。

(2)add s3,s0lw t0,0(s3)用于寄存器s3

在这里,寄存器s3add写入并由lw读取。新值是在第一条指令的EX阶段结束时计算的,而在下一条指令的EX阶段开始时需要的,因此可以通过转发来解决。

(3)寄存器lw t0,0(s3)的{​​{1}}和add t1,t2,t0

在这里,寄存器t0t0写入并由lw读取。新值是在第一条指令的MEM阶段结束时计算的,而在下一条指令的EX阶段开始时需要此新值,因此无法通过转发解决

(4)寄存器add的{​​{1}}和add t1,t0

在这里,寄存器sw t1,20(s3)t1写入并由t1读取。新值是在第一条指令的EX阶段结束时计算的,而在下一条指令的MEM阶段开始时需要的,因此可以通过转发来解决。

(5)寄存器add的{​​{1}}和sw

在这里,寄存器addi s1,1beq s1,s5,loop写入并由s1读取。在第一条指令的EX阶段结束时计算新值。通常,对于没有对控制危险进行任何优化的RISC-V管道,对于分支指令,在EX期间将寄存器与程序计数器+偏移量的计算并行进行比较,以获得分支目标。这里的控制危险是一个单独的问题,但是可以通过转发解决数据危险。

因此,在5种危险中,只有一种是无法通过数据转发解决的。可以通过指令重新排序解决吗?是。看一下s1。在addi之前,第一个beq之后的任何指令都不会读写addi s1,1。如果我们移动该指令,那么生成的代码将如下所示:

addi

这样,s1检索要写入slli的数据的指令将在{{}需要新的loop: slli s2,2 add s3,s0 lw t0,0(s3) addi s1,1 add t1,t0 sw t1,20(s3) beq s1,loop 值时完成MEM阶段。 1}}指令。

通过这种重新排序,可以通过转发解决所有数据危害,并且不需要停顿。