一般的取指令设备,只能够按照编译后的顺序顺次进行指令的读取。那么,要进行分支预测,首先就必须解决如何判断出当前读取的是不是分支指令这一问题;接下来要解决的两个问题则是分支是否跳转和如果预测为跳转,那么要跳转到什么地址继续取指令。
BTB结构的引入很好地解决了这三个问题。BTB中缓存了先前执行过的分支语句的指令地址BIA,分支跳转的地址BTA,以及分支预测的结果标识。取指令机构工作时,同时检索一级指令缓存和BTB,如果在BTB中找到有关条目的指令地址与当前要读取的指令相同,则按BTB中记录的BTA地址读取下一条指令送入管线中,同时继续执行分支指令,分支指令执行完毕后若结果与预测不符合,那么将刷新BTB的有关记录,并进行分支误预测的恢复操作。
分支指令预测技术
1.分支指令预测
在程序中一般都包含有分支转移指令,据统计,平均每七条指令中就有一条是分支转移指令.在指令流水线结构中,对于分支转移指令相当敏感。假设在80486的指令流水线中的第一条指令已进入到译码阶段,而第二条指令已进入到提取阶段(准备进入译码器),如果发现第一条指令是分支指令(如跳转到某个地址),则指令预取队列中下一条及下下条等指令预取无效。这时(确切地说,等到第一条指令执行期间形成了分支的目标地址),需从目标地址中现取指令,并交付执行,同时应立即清除指令预取队列,再将目标地址后面的指令预取过来填到队列中。这表明,一遇到分支指令,整个指令流水线就被打乱一次,稍后才能恢复到正常。显然,这影响了机器的运行速度。为此,在Pentium处理器中使用了分支目标缓冲器(Branch Target Buffer,BTB)来预测分支指令。
BTB实际是一个能存若干(通常为256或512)条目的地址存储部件。当一条分支指令导致程序分支时,BTB就记下这条指令的目标地址,并用这条信息预测这一指令再次引起分支时的路径,预先从该处预取。下面看一下BTB在循环程序中应用。循环程序在程序设计中使用得十分普遍。在指令级目标程序中构成循环程序需要用转移指令(条件转移指令或无条件转移指令)。看下例:
MOV CX.100
LOOP: ……
……
DEC CX
JNZ LOOP
……
在第一次执行到JNZ指令时,预测的转移地址是存在BTB中的前面一条JNZ指令的目标地址,不是LOOP,这一次预测是错误的。但执行后目标地址LOOP便存入到BTB中。等到下一次执行到JNZ指令,就按BTB中的内容来预测,转移到LOOP,这是正确的。如此,一直到cx的值变为0之前,也都是对的。当再循环一次CX的值变为0时,JNZ指令因条件不成立而不实行转移,而预测仍是LOOP,预取仍按该预测进行,这是第二次预取错误。可见,该例中100次循环,有98次预测,确切地说,有98次预测指导下的预取是正确的。同理,对于1000次循环,就会有998次的预取是正确的。即循环次数越多,BTB带来的效益就越高。
图8.1所示是Pentium处理器的分支预测机制示意图。指令预取器从位于CPU内
部的L1指令Cache中预取指令(一般情况,从中可以取到,如果其中没有则访问位于主板上的L2 Cache,若再没有则访问主存储器),指令预取队列中的指令按照管道方式(即先进先出)依次进入指令译码器,当译码时发现是一条分支指令,则检查BTB中有无该种分支指令的记录,若有,则立即按照所记录的目标地址进行预取(目标地址对应的指令及其后面的指令),替代原先已进入指令预取队列中的指令。在这条指令执行完毕前夕,将该指令的实际目标地址再添入BTB中(当然,在预测正确时,目标地址不会变),以使BTB中总保持最近遇到的分支指令及其目标地址。
细心的读者可能会发现,这似乎和上面提到的没有分支预测的80486差不多。应该指出,Pentium的分支预测确实是晚了一些,但毕竟作了预测,并根据预测的结果进行了预取。说它进行了预测和预取,是因为这些是在译码后立即做的,从80386开始指令部件中设置了已译码指令队列(参看第七章的图7.1),指令从译码到执行还有一段时间。此外,对条件分支指令判断条件是否成立以及分支目标地址的形成也需要时间,而这些是在指令执行时进行的。说它预测晚了一些,是因为总是希望预测在译码之前,即在指令预取的过程中进行预测。实际上,这就是在第六代微处理器中得以实现的动态分支预测。
2.推测执行与动态分支预测
推测执行技术又称预测执行技术。它的基本思想是:在取指阶段,在局部范围内预先判断下一条待取指令最有可能的位置,即在取指部件就具有部分执行功能,以便取指的分支预测,保证取指部件所取的指令是按照指令代码的执行顺序取入,而不是完全按照程序指令在存储器中的存放顺序取入。
动态分支预测是推测执行的一种具体做法,它是相对静态分支预测而言的。静态分支预测在指令到了译码器,进行译码时,利用BTB中目标地址信息预测分支指令的目标地址(如Pentium处理器那样);而动态分支预测的预测发生在译码之前,即对指令缓冲器(与8086、80386的指令预取队列基本相同,但有区别。)中尚未进入译码器中的那部分标明每条指令的起始和结尾,并根据BTB中的信息进行预测,这样发现分支指令要早。因此,对动态分支预测,一旦预测有误,已进入到流水线中需要清除的指令比静态分支预测时要少,从而提高了CPU的运行效率。
32 位RISC处理器CPU内部的动作被很自然的划分成取指(IF)、译码(ID)、执行(EX)、访存(MEM)和写回(WB)5个部分。在这些中左到右的指令流中有3个例外,就是写回阶段、分支地址选择和跳转地址选择,这些从右到左的箭头会导致数据冒险和控制冒险。同时为了保持一条指令路径执行的完整性,需要使流水线中的各条指令保持各自的值,所以必须在各级之间加上一个寄存器来保存该级中运算的结果,到下个时钟到来时把数据传给下一级进行运算,例如图6中的IF/ID、ID/EX、EX/MEM、MEM/WB模块,它们都是作为流水线寄存器加入的,PC也可以看成流水线中的一个寄存器,用它们来完成这样一个保存的功能。图6中,WB为2位,分别是memtoreg/regwrite,M为4位,分别是jump/branch/memread/memwrite,EXE为5位,分别是ALUsrc/regdst/ALUop。
http://wrw8167.blog.163.com/blog/static/5752525020093191733789/
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ysdaniel/archive/2010/11/16/6013318.aspx