MIPS pipelining
什么是pipelining
pipelining的概念很像统筹规划,例如一个零件有需要五个机器依次工作。我们并不需要等一个零件完全做完后再开始下一个零件加工,而是可以第一个零件进入第二步时第二个零件就开始加工,这样可以节省很多时间。

mips将一个instruction的运行拆分成了五个步骤:

每两个步骤中间我们会加入一个pipeline registers(多个register的集合,包含data和control signals)

其作用是:
阶段隔离与时序稳定
流水线寄存器隔离了各个流水线阶段,使得每个阶段的数据和控制信号在时钟边沿被“锁定”,从而在整个时钟周期内保持稳定。这种稳定性确保了数据不会因信号传递延时或噪声而受到干扰。
辅助冒险检测和解决
通过将数据和控制信息保存到各个阶段的流水线寄存器中,冒险检测逻辑可以准确地分析和比较相邻阶段之间的信号,从而识别数据冒险、结构冒险或控制冒险。没有这些隔离寄存器,相关信号可能混合或不稳定,使得冒险检测变得更加复杂或不准确。
降低设计复杂性
使用流水线寄存器将每个阶段的操作独立开来,可以简化时序分析和设计验证工作,同时为系统提供更强的抗干扰能力和鲁棒性。
这样设计后,每一个步骤只需要读取前一个pipeline registers的数值,然后在处理后传给后一个pipeline registers。
有些信息如write register会在前面被覆盖掉,所以这个需要一同传给MEM/WB pipeline registers。
对于control signal,我们可以derive以下diagram:


加入使用时序后,可以得出以下diagram:

pipelining的问题(Pipeline hazards)
1. structural hazards
Simultaneous use of a hardware resource

同一个时钟周期使用mem。
Solution1: Inst3 delay(stall) 3 cycles
Solution2: 我们需要将mem的访问分成两个部分:Data memory和Instruction Memory。
同样地,我们可以将reg的重叠分成半个clock cycle的write和read:

2. Data Hazards
这个和下一个control hazards本质上都是data dependency的问题,如果RAW (Read After Write)访问同一个register,则会出现data hazards,如果一个指令 depends on 另一个指令,则会出现Control hazards (beq, bne) 。
如果第二个Instruction需要立刻使用上一个instruction的结果,我们就需要将上一个的execution(ALU) result 传递给下一个instruction的ALU,并覆盖(by pass)掉从reg读取的data。这个过程称为forwarding。

但是load instruction是必须结束DM才能够得到register的数值,这种情况下我们就需要stall。

对于同一个register,WB和ID可以同时进行,lw的情况下,下一个instruction的EX会获取MEM的结果(不需要等WB),并覆盖ID的register value。
3. Control Hazards
beq和bne语句需要跳转,但是如果我们继续使用pipelining可能会execute顺序错误。这时我们用三个方法保证pipelining的正确性:
-
Early Branch Resolution:
我们为beq和bne语句特殊快速处理。这样我们可以在reg stage结束就能得到结果。

如果beq紧跟在beq所需register赋值后面,或者lw后面,需要stall更多时间。(无法继续优化)
-
branch prediction
假设不会跳转,接着执行后续命令。如果猜错了,跳转了,那么将后面instruction之后的步骤全部清空不做了。

这个优化其实不多,因为在循环中,branch一般是taken的。
-
delayed branch
可以独立进行的在beq和bne前面的操作可以放到紧接着beq和bne做,这样无论是否take都不需要flush,通常能节省50%的时间。(compiler must be smart enough to pre-execute the ordering problem)

本文图片大量借鉴NUS CS2100 slides
Comments
No comments yet.