计算机体系结构之流水线

发布时间 2023-09-17 23:31:18作者: 无名之士

一、引入流水线

  某厂要生产一件产品,从组装、打螺丝、密封、打包都由一个人完成,一小时过去了这个人还在打螺丝,老板看不下去了,心想不能全靠一个人,这样公司就干不下去了,所以老板就招了4个人,让这个人带。并且给这个人涨了工资。一个月之后这个人把那4个人全部教会了。老板就叫那个人去人事处领工资走人了(你懂的)。之后老板就让4个人分别干组装、打螺丝、密封、打包,由此4人一组的流水线就此成型。老板只要给第一个人拼命的下命令给元件,4个人就一直干。4个人的工资还不如以前那一个人的。老板为了激励4个人,拿出一丢丢蛋糕,于是4个人拼了命的干,就为一点蛋糕。从没想过一起慢慢干,拖着让老板加薪。从此又多了一个开保时捷出入高级会所的某厂老板。

  这就是流水线,把一个工作细化、拆分,不同人干不同事,同一时刻好多人一起工作。

  计算机体系里面的流水线也是如此,本来cpu执行一条指令,从取指、译码、执行、访存、写回,一步一步的,但是效率太慢,于是将步骤细化,第一条执行译码时,下一条指令就可以执行取指了,提高了吞吐量,但增加了延迟。

二、流水线架构图

 

一条指令的执行被分为多个阶段执行,这样第一条指令的取指完成之后,第二条指令就可以进行取指了(即自然的保证了指令的有序性),不必等到上一条指令全部执行完成,增加了吞吐量(单位时间内服务的指令数量),相应的增加了单条指令的延迟(服务一条指令的时间,有的指令不需要经理全部五条阶段)。
 
暂停:
   在指令之间插入nop指令,等效于插入一条无效指令使得下一条指令延迟一个周期
气泡:
   在执行阶段之后插入nop指令,无效指令的执行效果。
   (气泡和暂停的区别是:暂停是从取指到写回一整个周期的指令,而气泡可以在各个阶段无效执行结果,不必从取指开始)
转发:
    基本可以理解为:一个时钟周期就执行一个阶段,当时钟开始上升沿时,先进行阶段流水线状态的保存,之后执行指令。如此,就可以实现转发功能,因为译码阶段可能会使用到之后三个阶段中的值,所以为了不暂停流水线三个周期(译码阶段使用了写回阶段的值,示例1)、或两个周期(译码解阶段使用了上条指令访存阶段的值,示例2)、或一个周期(译码解阶段使用了上条指令执行阶段的值,示例3)
 
  • 初始:不使用转发,必须暂停三个周期 nop等效于暂停
  •        irmovq $3 %rax;  nop;   nop;  nop;  addq %rdx, %rax;
  • 示例1:irmovq $3 %rax;  nop;   nop;  addq %rdx, %rax; 只需暂停两个周期
  • 示例2:irmovq $3 %rax;  nop;  addq %rdx, %rax; 只需暂停一个周期
  • 示例3:irmovq $3 %rax;  addq %rdx, %rax; 不需暂停
问:既然转发了m_valM、M_valE,为什么还需要转发W_valM、W_valE?
    访存阶段的m_valM、M_valE表示的是上条指令的值,而写回阶段的表示的是上上条指令的值。
 
  • W_valE、W_valM:转发写回阶段流水线的值
  • M_valE、m_valM:转发访存阶段的值
  • e_valE:转发执行阶段的值

 三、流水线预测

  数据冒险:转发和暂停
  控制冒险:分支预测+插入气泡

  流水线控制逻辑:4种情况转发和分支预测不能处理

  • 加载/使用冒险:一条从内存读出一个值的指令(执行周期)和一条使用该值的指令(译码周期)之间,流水线必须暂停一个周期
  • 处理ret:流水线必须暂停直到指令写回
  • 预测错误的分支:执行阶段是一个跳转指令(jep),需要取消,并从跳转指令后面的那条指令开始取指
  • 异常:必须在指令到达写回阶段时,停止执行

  转发:首先检测执行中的转发源,然后是访存阶段,最后是写回阶段