CPU指令的流水线运行
指令集是CPU体系架构的重要组成部分。C语言的语法是对解决现实问题的运算和流程的方法的高度概况和抽象,其主要为算术、逻辑运算和分支控制,而指令集就是对这些抽象的详细支持,汇编仅仅只是是为了让开发者更好地记住指令,但它跟CPU所认的机器码事实上是一一相应的,因此汇编也是低级语言。
CPU的指令运行一般包含取指、译码和运行,这是经典的三级指令运行流水线,教科书上往往以这三种过程来描写叙述,arm7也是。可是现代的CPU设计往往使用更广泛使用的5级流水线,也就是分为取指、译码、运行、訪存和回写。为什么要分为5级?这是由流水线的各个阶段的时间来决定的。我们能够考虑现实生活的工厂的流水线。
如果某流水线仅仅有 三个工序,有三个工人A、B、C,则这条生产线的效率就取决于效率最低的那个工人的效率。现如果B做完其负责的工序须要10秒,而A和C完毕仅仅须要5秒,总共要完毕4个产品。那总时间应该是:5+10*4+5 = 50秒,(第一个5是A先做第一道工序的时间,这时B和C都得等,而最后一个5是C必须要等B所有完毕后才干開始)即会出现C在等待,而B一直在忙死忙活的场景。
当然,不管如何,流水线的运行总比完毕没有流水好,就好比A、B、C负责的工作都由一个人去做,那做完一个得20秒。所有做完得20*4 = 80秒。
最理性的场景就是三个人做事的效率是一样的,那就不会出现等待的情况。那如今确实遇到B工作效率最低的问题,怎么解决呢?就是将B的工作又一次分解,平均分成两个工序,也就是B1和B2,分别都是5秒完毕,那完毕的总时间是40秒。
CPU指令的三级流水运行正是遇到各步骤流水时间不均的问题,也就是取指和译码往往比較快,而运行包含运算和訪问寄存器、内存或者回写等功能,因此运行的时间一般比取指和译码要长,取指和译码能够在单时钟周期内完毕,但运行须要2到3个时钟周期才干完毕。要想得到更高的流水效率,就须要将运行部分分解为运行(运算等)、訪存(内存)和回写(寄存器)。
CPU指令的流水线运行对于软件开发者来说,最重要的就是要知道当前PC(程序计数寄存器)的值与当前运行指令的关系。取指指的是CPU依据当前PC的值内存的相应地址去取指令,因此PC值永远都指的都是当前取指令步骤的地址,而译码则是CPU的一部分电路依据取出来的指令机器码进行译码,选择相应的电路来运行这条运行,如选择加法电路还是减法电路,还是逻辑与电路等等;运行就是这个电路的运行过程了。
arm7的流水线示意图是:
从图能够看到在T1时刻,CPU的运行电路运行的是MOV指令,而取指电路取的是SUB指令,因此当前运行电路的MOV相应的运行地址应该是当前PC值减8. 假设当前运行的指令是一个函数调用(即BL指令),但返回地址就应该是ADD指令所在的地址,即(PC减4)。
有人问到流水线断流的问题,补充说明一下,断流主要有下面情况:
1)数据相关。如第二条指令须要的数据正好是第一条指令运行的结果。这时第二条必须等待。
2)分支跳转。指令分支推断之后,可能会顺序运行,也可能跳转到其它地方,这时也会引起流水线的断流。