|
楼主 |
发表于 2017-2-11 22:55:14
|
显示全部楼层
关于分支预测:
于是有人问了,如果一条无条件跳转指令,经过IF-ID-EX后最终改动了IF阶段的PC。执行下来应该是4个周期。那么,ARM/AVR这类处理器是如何在2级/3级流水线的情况下执行无条件跳转指令只要一个周期的呢?
这种情况,在IF阶段,要做一次译码。比如判断到待发送给ID阶段的指令是无条件跳转指令,那就在IF阶段把PC给改掉,指向新的地址,然后ID和EX阶段什么都不做就可以。相当于把跳转提前了。所以无条件跳转指令就可以一个周期实现。
那么,如果是带着指针寄存器偏移的无条件跳转指令。这样的方式就是不能使用的,因为此时ID,EX,WB三个阶段中还有3条指令在同时执行。如果这三条指令中任何一条改动了寄存器的值,就会导致跳转到错误的地址上。这样倒也有应对的解决方案,就是把ID、EX、WB阶段在操作的寄存器地址全部引出来。如果寄存器地址和跳转用的指针寄存器毫无关系。则可以放心跳转。有关系,就得先阻塞住,等到和这个寄存器相关的指令跑完以后,才可以进行跳转。但是这样会在IF阶段引入太多的组合逻辑,降低速度。对我而言,我暂时不会使用这个技术。
如果是有条件的跳转指令,那么也得先确保条件在另外3个正在执行的阶段中不会被改动。如果确认没有被改动的话,就可以放心大胆的取值跳转。但是很不幸运的是,条件跳转指令和判断指令几乎都是伴生的。
因此,我们需要引入一种称为分支预测的技术,来尽量降低流水线阻塞的条件。在单片机用的内核里,不会给你太多的空间放跳转预测表(gshare之类的算法需要)。
不过,没有跳转表和概率计算,也是可以做分支预测的。只是说,穷有穷办法。比如说,一般而言,编译器喜欢将代码的向后跳转优化的容易执行,向前跳转优化的较少执行。比如:
for(i=0;i<100;i++){.....}
所以,不妨假设大多数程序都是这样的。遇到向后跳转的条件跳转指令,即使我不知道条件的结果(估计还卡在EX哪里没算出来呢)。我就先当它应该是跳了。于是把PC改为跳转后的值。老的PC保留备用。
等到条件值过了EX被计算出来了之后,我就来比较和我当时假设的跳转情况做比较。如果预测失败了,那么将IF/ID的寄存器全部清空,把上次的PC放出来,+1。然后继续执行。如果预测成功了,那就接着跑。
向前跳转的条件跳转指令也一样处理,只是反过来而已。
显而易见,这样的分支预测算法在遇到随机代码的时候,预测的正确率对半开。但是!一般的编译器喜欢把向后的跳转指令默认更容易执行。向前的更不容易被执行。所以这样的预测效率还是比较可观的,配合良好的编译器可以上90%。
预测正确的话,条件跳转指令应当是一个周期。预测失败的话,假设改动条件的指令在EX阶段,条件跳转指令在IF阶段。于是执行一个周期,写回寄存器需要一个周期,同时可以再次修改PC,等RAM数据妖一个周期。因此这样的条件跳转指令要执行3个周期。
如果改动条件的指令在ID阶段。那么要等ID走完一个周期,EX走完再一个周期,写回寄存器和修改PC又要一个周期,等RAM也要一个周期。因此这样执行的条件跳转指令就要4个周期。
预测失败后,EX阶段以前的流水线指令必须被抛弃,然后从头重新取。要不然就会得到错误的结果。
所以说,在某些处理器核心手册上看到的某些指令执行周期是1/2/3就是这样来的。带分支预测的流水线的行为是完全可以预测的,而不是像本坛某些人说的那样根本不可控。做计算机底层开发的,还是需要更多了解计算机结构比较好。
关于超标量和乱序执行,我自己也不是非常明白。所以我就不来班门弄斧了。如果有大牛愿意通俗易懂的描述这两个技术,我非常支持! |
|