蜂鸟E203学习笔记-取指模块概述(2)

蜂鸟E203学习笔记

  • 前言
  • 1 部分译码
  • 2 分支预测与PC生成
  • 3 请求与响应
  • 4 流水线冲刷
  • 5 阻塞请求


前言

本文取指模块概述后半部分,前半部分跳转至:取指模块概述(1)

蜂鸟E203学习笔记-取指模块概述(2)_第1张图片


1 部分译码

Minidecode中例化decode模块,使用decode部分译码功能,只需要译出IFU所需的部分指令信息。包括此指令是属于普通指令还是分支跳转指令、分支跳转指令的类型和细节。从minidecode的端口可以看出其主要完成这些功能:

  1. 判断寄存器(rs1,rs2,rd)是否被使用,并输出其索引。
  2. 判断指令长度(32 or 16)及指令类型(bjp, jal, jalr, bxx)。
  3. 若指令为乘除法相关指令,判断其是否属于back2back fusing类型,这指的是对于乘法来说,两个32位数相乘最高能得64位数,而寄存器只为32位,因此每次只能将结果的高32位或低32位存入寄存器,如果希望得到两个32位整数相乘的完整64位结果,RISC-V架构推荐使用两条连续的乘法指令“MULH[[S]U] rdh, rsl, rs2; MUL rdl, rsl,rs2”, 而对于除法如果希望同时得到两个32位整数相除的商和余数,RISC-V架构推荐使用两条连续的除法和取余指令“DIV[U] rdq, rsl, rs2; REM[U] rdr, rsl, rs2”其要点如下:
  • 两条指令的源操作数索引号和顺序必须完全相同。
  • 第一条指令的结果寄存器rdh或rdq的索引号必须不能与其rsl和rs2的索引号相等。
  • 处理器实现的微架构可以将两条指令融合(Fused)成为一条指令执行,而不是分离的两条指令,从而提高性能。
  1. 解析jalr的rs1寄存器索引和分支跳转指令bjp使用到的立即数输出至分支预测模块。

2 分支预测与PC生成

对于分支预测,此处为了实现低功耗采用较简单的静态分支预测,对于Bxx指令来说,立即数表示的offset偏移若是负即向后跳转,则判定为跳,若是正的向前跳转则判定为不跳。而jal和jalr则始终跳转,其中对于jalr来说,因为其是间接跳转,跳转目标计算所需的基地址来自于其rs1索引的操作数,需要从通用寄存器组(Regfile)中读取,并且还可能和正在EXU执行的指令形成RAW数据相关性,如图1所示,为分支预测与解决jalr的rs1数据相关性的流程图。对于图中红色序号:

  1. 判定rs1的索引号是x1,则其可能与EXU中的指令存在潜在的RAW数据相关性,首先若OTIF不为空,意昧着可能有长指令正在执行,其结果可能会写回x1(OITF本质上是一个先入先出的FIFO, 在流水线的派遣点,每次派遣一个长指令,则会在OITF中分配一个表项,在这个表项中会存储该长指令的源操作数寄存器索引和结果寄存器索引,在流水线的写回点,每次按顺序写回一个长指令之后,就会将此指令在OITF中的表项去除),其次若处于IR寄存器中的指令的写回目标寄存器的索引号为x1,意昧着有RAW数据相关性。
  2. 特别加速指的是将x1从处于EXU的Regfile中直接拉线取出(不需要占用Regfile的读端口)。
  3. 若jalr的基址寄存器不是x0、x1就是xn,此时考虑数据相关性除了要判断OTIF是否为空,还要看IR中指令是否为空,因为若IR中指令不为空,其执行写回操作时虽然不一定写回到jalr所用的xn,但是保守判断,也可能产生数据相关性,因此需要考虑。
  4. 当jalr所用基址寄存器为xn时,不在对其进行特别加速,要从regfile端口读出,因此要考虑端口占用问题。

蜂鸟E203学习笔记-取指模块概述(2)_第2张图片

由于PC计算需要使用到加法器(pc = 基地址 + 偏移量),为了节省面积,所有的PC计算均共享同一个加法器。如以下代码。构建带优先级的多路选择器,来获取基址。PC生成逻辑用于产生下一个待取指令的PC, PC生成根据不同的情形需要不同处理,书中7.3.4节做了详细论述,包括reset后第一次取指、16位与32位自增取指、分支跳转和流水线冲刷四种情况的PC生成。

 wire [`E203_PC_SIZE-1:0] pc_add_op1 = 
                            `ifndef E203_TIMING_BOOST//}
                               pipe_flush_req  ? pipe_flush_add_op1 :
                               dly_pipe_flush_req  ? pc_r :
                            `endif//}
                               ifetch_replay_req  ? pc_r :
                               bjp_req ? prdt_pc_add_op1    :
                               ifu_reset_req   ? pc_rtvec :
                                                 pc_r;

  wire [`E203_PC_SIZE-1:0] pc_add_op2 =  
                            `ifndef E203_TIMING_BOOST//}
                               pipe_flush_req  ? pipe_flush_add_op2 :
                               dly_pipe_flush_req  ? `E203_PC_SIZE'b0 :
                            `endif//}
                               ifetch_replay_req  ? `E203_PC_SIZE'b0 :
                               bjp_req ? prdt_pc_add_op2    :
                               ifu_reset_req   ? `E203_PC_SIZE'b0 :
                                                 pc_incr_ofst ;

3 请求与响应

Ifetch在以下情况下发出新的Ifetch请求:不需要等待、中断、重置、重播的情况。当存在新的ifetch请求,或冲刷请求挂起时,将触发取指请求有效信号。另外新的请求就绪产生的条件是:1.当前没有未完成的请求;2.有未完成的请求但已收到响应有效信号。而一旦产生新的请求或流水线冲刷,则更新当前PC值。指令输出到IR则由Ifetch请求响应通道根据当前状态作出控制。

4 流水线冲刷

在取指阶段的分支预测功能,对于带条件分支指令,由于其条件的解析需要进行操作数运算(譬如大小比较操作),流水线在取指阶段无法得知该指令的条件跳转结果是跳还是不跳,只能进行预测。 因此在执行阶段,通常需要使用 ALU 对该指令进行条件判断运算(譬如大小比较操作)。
ALU进行条件判断运算的结果将用于解析该分支指令是否真的需要跳转,并且和之前预测 的跳转结果进行比对。如果真实的结果和预测的结果不一致,则意味着之前的预测错误, 需要进行流水线冲刷(Pipeline Flush ),将预测取指( Speculative Fetch)所取的指令都舍弃 掉,重新按照真实的跳转方向进行取指。
流水线冲刷本应在Ifetch接口就绪或存在响应有效(valid)信号时被确认,但为了减少EXU和IFU之间的组合环路,采用一种始终接受流水线冲刷的策略,当冲刷未被确认时,使用延迟冲刷指示标记此次冲刷,而即使有冲刷被挂起,仍然可以接受新的冲刷请求。当收到流水线冲刷请求,但IFU未就绪接受新的取指请求时,设置冲刷延迟。

5 阻塞请求

如果收到阻塞请求,IFU会暂停获取新的指令,直到正在进行的事务完成之后,会收到ifu_halt_ack响应,只有在ifu_halt_req请求取消后,才会恢复取指。

你可能感兴趣的:(#,RISC-V,处理器设计,学习,risc-v)