图片来源:南京大学软件学院COA课程PPT
©author:zzb
文章目录
15 指令周期和指令流水线
指令周期
指令周期
只有机器关闭,发生错误,遇到停止计算机的指令时,程序才会停止。只要计算机开着,即使不使用,也是持续在执行指令的
返回字符串或向量数据
是指比如要取一个字符串,那么一次可能无法全部得到,那么就必须要分多次,多次的计算源操作地址,取字符串,计算目的操作数地址,存字符串。但这是一条指令的功能,所以直到全部取完后,才进行下一条指令的地址计算
带中断的指令周期
在这条指令执行完,下一条指令未开始的中间进行中断的判断(这时候PC已经是下一条指令的地址了)
间址周期
把间接地址的读取看作一个额外的指令子周期,相比于直接寻址,多了存储器的访问,所以单独作为一个子周期
CPU的任务
寄存器
数据流
取指周期
如果是同步的总线,那么只要按时间取做上面的流程即可,如果是异步总线,那么在存储器把数据放到数据总线上时,还要通过控制总线告诉CPU已经好了,所以存储器与控制总线之间是双向箭头。
而这里单向箭头,说明是同步总线。事实上,一般来说,CPU和存储器之间都是采用同步的
黄色箭头代表两个含义:
-
控制PC传输地址,从而取指令
-
当指令取完后、指令执行前(一般是要取到IR中后才加1,即在取指周期的最后加1,否则不知道+1是加多少),而不是指令执行完,控制PC+1。但其实也不一定,如下,PC+1可以和其他的一起执行
间址周期
注意:间址周期取回来到MBR的只是有效地址EA,而通过有效地址EA去取操作数的过程是在执行周期里的
中断周期
这里数据线都是指向存储器的,表明写操作,同时PC连到MBR,因此这里想要做的是对PC进行保存(PC这时候存的是下一条指令的地址),从而能够在中断之后能够准确的返回
中断中由控制器去告诉MAR地址,即PC要存储在存储器的哪一个位置,这个地址很可能是栈的指针,中断也是过程调用
(在取指过程中由PC告诉MAR,在间址过程中由MBR告诉MAR)
指令流水线
流水线可以让每个部件各司其职,只做它要做的单一的事,提高效率,节省时间
CPU就像一个生产线,如果各个步骤的任务分配不够好,比如不同步骤所需时间不同,那么就会造成资源的浪费,如矿泉水的生产,不同步骤时间不同,那么时间短的就会闲着。
因此对CPU生产线上的步骤进行阶段划分:
两阶段方法
取指令要访问内存,执行指令也可能要访问内存,可能会造成访存冲突
- 取指令的等待是执行的时间比取指令的时间长,所以要等待
- 执行阶段的等待是可能执行的是跳转指令,所以取指令在执行期间取好的指令就要作废,要根据新的地址去取指令,此时执行阶段要等待
六阶段方法
六个阶段的所需时间几乎相等,因此如下可以把每个阶段所需时间当作一个时间单位
注意在EI阶段就会把目的操作数写入目的位置(主要是CPU内的寄存器),而如果是要写入主存的,才在WO阶段写,就和上面的FO一样,对于寄存器中的值不需要取,取的是主存中的操作数
如同生产矿泉水的流水线
- 为了简化流水线的设计,可以假定每个指令都是6个阶段,如果没有某个阶段,不执行即可(如果为特殊指令设计不同阶段,那么是非常不划算的)
- 阶段之间不一定全都能并行,如对内存的访问,会产生访存冲突
- 几乎相等,仍然是有差别时间,那么会导致一定的等待,所以时间单位应该以最长的时间的为准,保证每个阶段在这个时间单位内都能执行完
限制:在两阶段中跳转指令会使得已经取得的下一条指令失效。而在六阶段中会使得上面红框中执行了一半的指令的全部失效
注意:上面的最后一个指令的WO的同时,下面的FI也在执行,这是因为跳转指令不需要写存储器,而是在EI执行指令的过程中就把PC寄存器的值给改变了,所以在EI后面一个单位时间会执行正确的FI
和跳转一样,中断也会使得指令失效,如上图中的排空流水线,这里多了一个无条件转移,那么在无条件转移把PC值修改后的一个单位时间内的FI才是有效的,中间的流水线全部失效,但已经在执行的指令的后续阶段是不受影响的
绿色框是导致空闲的区域,而红色框内的执行是无效的,同理指令13的EI修改了PC,所以下面一个单位时间的I15才是有效的,中间的全部失效,但I13剩下的阶段正常进行
流水线的性能
这里的t即单位时间,应当为各阶段中花费时间最大的时间,加上两阶段切换的时间
锁存时间是在两个阶段之间切换的时间,就像接力赛,接力棒由前一个人放到桌子上,下一个人再去桌子上拿,这样是最稳妥安全的。
Tk,n是最理想的情况,第一条指令执行需要kt,后面的每多一条指令,总时间只增加1t,所以是 [ k + ( n − 1 ) ] t [k+(n-1)]t [k+(n−1)]t
加速比是指没有使用流水线和使用了流水线的时间之比,是一个大于1的数(所以才叫加速比)
注意:其中分子没有使用流水线是固定的就是 n k t nkt nkt,n条指令,每个需要kt时间,而分母使用了流水线的可能会有跳转的情况,会导致时间的改变
当流水线中的阶段增多时,刚开始是会加快执行速度,但不是越多越好,当阶段太多,锁存延时会增加,增大开销。同时阶段越多,对硬件的使用冲突就会越大,需要更为复杂的控制逻辑
冒险(Hazard)
结构冒险
硬件资源冲突
分时使用如在时钟的上升沿和下降沿分给不同指令使用
数据冒险
第一条指令中r1寄存器被更新,但根据指令的周期,后面的若干条指令中获得的r1寄存器都是未更新的
用软件nop指令让这3个时钟周期啥也不干,直到r1被成功更新后再执行后续指令,从而不需要改动硬件
插入气泡——即硬件通过阻塞阻止可能出问题的指令的执行,因此需要判断哪些指令相关,怎么去阻塞的问题,虽然没有加nop指令,但在判断处理过程中也会有时间开销
把需要的结果从中间就取过来,而不必去等指令的完全执行。
如r1要存放的新数据在经过ALU时即已经产生,只是结果没有更新到所在的r1寄存器中。此时第二条指令可以把这个结果取过来直接用,而不必等待第一条指令完全执行完。因为ALU不会同时被两条指令占用,第一条用完ALU,才会给第二条使用,因此上面的取中间结果是可行的
这就是转发/旁路。当后面要用到的数据是前面算出来的
经过ALU即可得到时,这时候旁路很有效,当不是时,旁路无法解决,如下
r1寄存器此时要从内存中加载数据,而下面sub r1就要用这个数据进行alu计算,但数据还没有从内存中读取过来,所以必须要等待到从内存中取到数据才行,根据转发机制,同样不必等待这个数据加载到r1即可取到。即上面的红线的
解决办法就是交换指令的顺序,如右,lw b 和lw c到两个寄存器中,当执行add时,还没加载好,所以要等待。因此可以通过把下面的一条不相关的指令换上来,这样可以把等待的时间变成执行后面指令的时间。总体执行时间会缩短
控制冒险
当指令的执行顺序被改变,那么就会出现一部分的指令执行白处理了,原因就是取错了。
即把跳转指令之后的指令和跳转到的指令都取过来,因为不知道这个跳转指令是不是真的要跳转(如多个条件跳转指令),所以就不能确定到底是执行后面的指令还是执行跳转指令中的指令
所以把两个都取过来,两条流水线处理,那么就保证了流水线的正常运行,即使有一条是失效的,那么不管它即可,另外一条在按照流水线正常运行
预测会不会发生转移,如果预测会发生转移,那么就直接取跳转指令中指出的指令,而不去取跳转指令后面的指令。
如果预测失败了,那么就造成了流水线中已经执行的部分指令的失效;反之如果预测成功了,那么就避免了指令的失效,从而提高了流水线的效率
静态预测是和当前状态没有关系的,不会去根据刚刚处理的历史来改变,仅仅是按照规则
动态预测
根据状态来动态预测
遇到条件分支,看是不是第一次遇到,如果是就加入表中,如果发生过,看前面的预测是怎么样的,然后根据现在的状态来调整
流水线的效率`
静态预测是和当前状态没有关系的,不会去根据刚刚处理的历史来改变,仅仅是按照规则
动态预测
[外链图片转存中…(img-FTMi3dxV-1656915451955)]
根据状态来动态预测
[外链图片转存中…(img-JXfc38dv-1656915451955)]
遇到条件分支,看是不是第一次遇到,如果是就加入表中,如果发生过,看前面的预测是怎么样的,然后根据现在的状态来调整