Nehalem百科
四、前端部分:(指令拾取和解码)
1、指令拾取(包括分支预测)
在Nehalem的指令拾取单元(instruction fetch unit)中包含有相关指令指针(relative instruction point,RIP),每个线程状态(thread context)各有一个。在指令拾取单元中还包含有分支预测器,用来预测下一条将被拾取的指令的RIP。对于分支预测器的很多细节,INTEL并没有公布,但它们是适合于工作在SMT模式的。并且Nehalem也将继续使用上一代的那些特殊的分支预测器,比如循环检测器(loop detector),间接预测器(indirect predictor)等。
当分支预测器选定一条分支时,分支目标缓冲(branch target buffer,BTB)就负责预测目标地址。Nehalem使用了2级BTB结构。作为参考,K10使用了一个有2K 项(entry)的BTB用于直接分支,和一个有512项的间接分支目标阵列(indirect branch target array)。Nehalem的两级BTB设计,非常适用于有大量指令代码的任务,例如数据库、ERP和其它的商业应用,通过提高分支预测准确度而提升性能和能效。INTEL没有发布详细的内部结构。下面作出一些有依据的猜测。
有两种可能。一是两个BTB使用同样的预测算法,而一个存取更小一点的历史文件,包含最近时间内所使用的分支RIP和目标RIP。在这种情况下,它们的关系就象L1缓存和L2缓存一样(因为分支目标也具有相当好的地址相关性)。举个例子,比如L1 BTB有256-512项,而更大的L2 BTB则有2K-8K项。如果分支RIP在L1 BTB中没有找到,然后就到L2 BTB中去找,以作出目标预测。
另一种可能(RWT认为这种可能性比较小)则是两级BTB使用不同的预测算法和不同的历史文件。比如L1 BTB使用简单而快速的算法和相对较小的历史文件,而L2 BTB则使用更慢但更准确的算法,而且被配置成是具有优先权的预测器。如果L2 BTB不同意L1 BTB的预测,则它可以撤消(override)L1 BTB的预测,去除掉流水线中错误拾取的指令,而从新预测的RIP处重新拾取指令。这种结构可能性不大,因为它的能效比较低下。对于这种预测器架构,通常的情况是L1和L2 BTB都独立的得出正确的分支目标——这就意味着在大多数的时间里,L2 BTB都是在浪费能源。而L1 BTB错误,L2 BTB是正确的情况,只占非常小的比例。
不过在更早一点的ANANDTECH的文章中有提到认为是第二种方式:通常会遇到这样的情况,L1 BTB作出预测是基于分支的类型,但实际上它并没有历史数据,这样准确度就很低。而L2 BTB有更多的历史数据,就可以提高准确度,而且L2 BTB可以在执行过程中就纠正(L1 BTB所给出的)错误预测,而避免性能损失(这就正是override的情况)。
现在不清楚哪一种观点更正确一些。
Nehalem另一个提升分支目标预测的机制是对返回堆栈缓冲(return stack buffer,RSB)进行了重命名。当发生程序调用时,RSB就记录下地址,这样当结束调用返回时,就从该地址继续执行下去。但是当有很多程序递归调用时,RSB将会溢出,并且如果分支预测错误,那么也将会产生错误的返回地址。Nehalem通过重命名RSB,就避免了溢出。并且错误的分支预测也不会毁坏RSB,只要调用与返回地址是正确配对的,那么就可以从Nehalem的RSB中得到正确的数据。对于每一个线程都有一个专用的RSB,避免任何交叉弄脏数据。
拾取单元取得了每一个线程预测的下一个地址(通常情况下也就是正确的下一个地址),就到ITLB(指令旁路转换缓冲)和L1 I(一级指令缓存)去标注。ILTB由每个线程静态分配(平分),有128项缓存4KB的小页表,是4路联合方式的缓存;另外,每个线程还有7项用于缓存大页表文件(2MB/4MB),是全联合方式。L1 I是32KB,4路联合方式,由线程竞争共享。进入指令缓存后,每周期16Byte(128bit)的指令发送到预解码和拾取缓冲(pre-decode and fetch buffer)。然后,每周期6条指令从预解码和拾取缓冲发送到有18个项目数的指令队列(instruction queue)。在Core 2中,指令队列被用做循环缓存(Loop Stream Detector,LSD,循环流检测器),这样碰上小循环(指令数≤18)的时候,指令拾取单元就可以被关闭。而Nehalem的指令队列则只是作为指令被解码前的缓冲,因为它的循环缓存在流水线级数中,被放到了解码阶段的后面。
2、解码