7.5 流水线暂停机制的设计与实现
7.5.1流水线暂停机制的设计
因为OpenMIPS设计乘累加、乘累减、除法指令在流水线执行阶段占用多个时钟周期,因此需要暂停流水线,以等待这些多周期指令执行完毕,一种直观的实现方法是:要暂停流水线,只需要保持取指令地址PC的值不变,同时保持流水线各个阶段的寄存器(也就是IF/ID、ID/EX、EX/MEM、MEM/WB模块的输出)不变。
OpenMIPS采用的是一种改进的方法,假如位于流水线第n阶段的指令需要多个时钟周期,进而请求流水线暂停,那么需要保持取指地址PC的值不变,同时保持流水线第n阶段、第n阶段之前的各个阶段的寄存器不变,而第n阶段后面的指令继续运行。例如:流水线执行阶段的指令请求流水线暂停,那么保持PC不变,同时保持取指、译码、执行阶段的寄存器不变,但是可以允许访存,回写阶段的指令继续运行。
为实现流水线暂停机制,对系统结构做如图所示的修改
CTRL模块来自ID、EX模块的请求暂停信号stallreq,对于OpenMIPS教学版而言,只有译码、执行阶段可能会有暂停请求,取指、访存阶段都没有暂停请求,因为指令读取、数据存储器的读/写操作都可以在一个时钟周期完成。
CTRL模块对暂停请求信号进行判断,然后输出流水线暂停信号stall。从图中可知,stall输出到PC、IF/ID、ID/EX、EX/MEM、MEM/WB等模块,从而控制PC的值,以及流水线各个阶段的寄存器。
7.5.2流水线暂停机制的实现
- CTRL模块的实现
CTRL模块的接口如图所示,各接口作用如表所示:
输出信号stall是一个宽度为6的信号,其含义如下: - stall[0]表示取指地址PC是否保持不变,为1保持不变
- stall[1]表示流水线取指阶段是否暂停,为1表示暂停。
- stall[2]表示流水线译码阶段是否暂停,为1表示暂停。
- stall[3]表示流水线执行阶段是否暂停,为1表示暂停
- stall[4]表示流水线访存阶段是否暂停,为1表示暂停。
- stall[5]表示流水线回写阶段是否暂停,为1表示暂停。
代码从以下三方面理解。
(1)当处于流水线执行阶段的指令请求暂停时(即stallreq_from_ex等于Stop),按照OpenMIPS流水线暂停机制的设计,要求取指、译码、执行阶段暂停,而访存、回写阶段继续,所以设置stall为6’b001111。
(2)当处于流水线译码阶段的指令请求暂停时(即stallreq_from_id等于Stop),按照OpenMIPS流水线暂停机制的设计,要求取指、译码阶段暂停,而执行、访存、回写阶段继续,所以设置stall为6’b000111。
(3)其余情况下,设置stall为6’b000000,表示不暂停流水线。
- 修改取指阶段
(1)修改PC模块
PC阶段新增加了一个输入信号stall,其值就是CTRL模块的接口stall.
(2)修改IF/ID模块
IF/ID模块也新增了一个输入信号stall。 - 修改译码阶段
(1)修改ID模块
ID模块新增了一个输出信号stallreq,在实现加载、存储指令的时候就会给该信号赋值,目前暂时设置这个输出就是NoStop。
(2)修改ID/EX模块
ID/EX模块新增了一个输入信号stall。 - 修改执行阶段
(1)EX模块新增了一个输出信号stallreq_from_ex,在本章后面实现乘累加、乘累减、除法指令的时候会给该信号赋值。
(2)修改EX/MEM模块
EX/MEM模块新增了一个输入信号stall。 - 修改顶层模块OpenMIPS
因为上面添加了CTRL模块,而且对流水线各个阶段的模块也增加了相应的接口,所以需要修改OpenMIPS模块,以将新增接口与CTRL模块连接起来。
7.6乘累加、乘累减指令说明
乘累加、乘累减指令共有4条,包括:madd、maddu、msub、msubu,各指令格式如图所示。从图中可知,这四条指令的指令码都是SPECIAL2,第6-15bit都为0,可以依据第0-5bit功能码确定是哪一种指令。
- 当功能码是6’b000000,表示是madd指令,有符号乘累加运算。
指令用法为:madd rs,rt。
指令作用为:{HI,LO} <- {HI,LO} + rs * rt,将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作为有符号数进行乘法运算,运算结果与{HI、LO}相加,相加的结果保存到{HI、LO}中。此处{HI、LO}表示HI、LO寄存器连接形成的64位数,HI是高32位,LO是低32位。
7.7 乘累加、乘累减实现思路
在本章开始已经说明了乘累加、乘累减指令的实现思路,计划在流水线执行阶段采用两个时钟周期完成运算,第一个周期进行乘法运算,第二个周期将乘法结果与HI、LO寄存器进行加减法。
为了实现乘累加、乘累减指令的实现思路,必须要保存两个信息:(1)当前是第几个时钟周期;(2)乘法结果。OpenMIPS通过在EX/MEM模块中添加两个寄存器cnt、hilo,分别保存上述信息。修改系统结构如图所示。
执行阶段EX模块的输出hilo_temp_o是乘法结果,传递到EX/MEM模块,并在下一个时钟周期送回EX模块,参与第二个时钟周期的加/减法运算。
执行阶段EX模块的输出的cnt_o代表当前是第几个时钟周期,传递到EX/MEM模块,并在下一个时钟周期送回EX模块,后者据此判断当前处于乘累加、乘累减指令的第几个执行周期。
7.8 修改OpenMIPS以实现乘累加、乘累减指令
7.8.1修改译码阶段的ID模块
译码阶段的ID模块要添加对乘累加、乘累减指令的分析,根据图给出的指令格式可知,这4条指令都是SPECIAL2类指令,可以依据功能码确定是哪一种指令,确定指令的过程如图所示。
代码解释为:
7.8.2 修改执行阶段的EX模块
EX模块要增加4个接口
代码理解
7.8.3修改EX/MEM模块
参考图可知,EX/MEM模块要增加4个接口,具体如表所示:
7.8.4 修改OpenMIPS模块
因为上面为EX、EX/MEM模块增加了接口,所以需要修改OpenMIPS模块,以将这些接口连接起来,连接如上图所示。
7.9 测试乘累加、乘累减指令实现效果
7.10 除法指令说明
除法指令有2条,包括div、divu,各指令的格式如图所示,从图中可知这2条指令的指令码都是SPECIAL,第6-15bit都为0,可以依据第0-5bit的功能码确定是哪一种指令。
7.11除法指令实现思路
7.11.1 试商法
7.11.2实现思路
新建一个模块DIV,在其中实现采用试商法的32位除法运算。当流水线执行阶段的EX模块发现当前指令是除法指令时,首先暂停流水线,然后将被除数,除数等信息送到DIV模块,开始除法运算。DIV模块在除法运算结束后,通知EX模块,并将除法结果送到EX模块,后者依据除法结果设置HI、LO寄存器的写信息,同时取消暂停流水线。
7.11.3 系统结构的修改
为了实现7.11.2节的思路,修改系统结构如图所示。
EX模块通过接口div_opdata1_o、div_opdata2_o分别给出被除数、除数,同时通过接口signed_div_o指明是否是有符号除法。
DIV模块在除法运行完毕后,然后通过接口div_start_o指示开始除法运算。
DIV模块在除法运行完毕后,通过接口ready_o告知EX模块,并且通过接口result_o输出除法结果,result_o的宽度是64位,其中高32位是余数,低32位是商。
7.12 修改OpenMIPS以实现除法指令
7.12.1 增加DIV模块
DIV模块接口含义如表所示
DIV模块的主要部分是一个状态机,共有4个状态,如下,状态转换如图所示:
- DivFree:除法模块是空闲。
- DivByZero:除法是0.
- DivOn:除法运算进行中。
- DivOn:除法运算结束。
复位的时候,DIV模块处于DivFree状态,当输入信号start_i为DivStart,且输入信号annul_i为0时,表示除法操作开始。
- 如果除数opdata2_i为0,那么进入DivFree状态,直接给出除法结果,这里设置为0,余数也为0,然后进入DivEnd状态,并通知EX模块得到除法运算结果,后者会设置DIV模块的输入信号start_i为DivStop,除法运算结束。
- 如果除数opdata2_i不为0,那么进入DivOn状态,使用试商法,经过32个时钟周期,得出除法结果,然后进入DivEnd状态,并通知EX模块得到除法运算结果,后者会设置DIV模块的输入信号start_i为DivStop,除法运算结束。
7.12.2 修改译码阶段的ID模块
译码阶段的ID模块要增加对除法指令的分析,根据给出的指令格式可知,除法指令都是SPECIAL类指令,可以依据功能码确定是哪一种指令,确定指令的过程如图所示。
这2条除法指令的译码过程都是相似的,简要说明如下。
7.12.3 修改执行阶段的EX模块
EX模块需要增加部分接口。