发射队列与仲裁
发射队列(Issue Queue,简称IQ)是用来保存尚未执行的指令的队列(一部分文献称之为“保留站”)。在发射队列中,指令会等待其两个源操作数都就绪(即被前面相关的指令唤醒),然后仲裁器会基于其年龄信息,选取一条最旧的指令发射到后端流水线中开始执行。
发射队列的组织
Zircon-2024的发射队列事实上并不是一个严格的“队列”,因为每个周期写入的指令并不一定位于队头,被发射出去的指令并不一定位于队尾。在设计时,作者吸取了Zircon-2023的教训(参看往期经验),并没有采用压缩式发射队列,而是采用了非压缩式队列的结构来组织。
发射队列不仅仅是用来暂存待发射的指令,它还有一个重要功能是:为仲裁器提供一个足够大的仲裁窗口,使其能够发现更多可同时执行的就绪指令。不过,随着仲裁窗口能够审视的指令变多,仲裁发射逻辑也变得越来越复杂。因此,对于那些单周期多发射的发射队列而言,Zircon-2024做出的权衡设计是:尽可能用简单的逻辑让更多的指令能够同时出现在发射队列中,但每一个仲裁逻辑能看到的指令窗口有限。
空闲表项管理
Zircon-2024的发射队列采用了类似空闲物理寄存器列表的管理方式,采用一个Cluster的“空闲发射队列表项”来统一管理发射队列的空闲表项。每当若干指令到达分派阶段,这个空闲列表都会为其分配一个表项,指令会将其信息写入该表项中(如果列表中没有空闲表项,那么前端将会被阻塞)。
当一条指令被确认发射后(“确认发射”的概念请参考后文),这个表项就会被空闲列表回收,且空闲列表在回收时是按照FIFO逻辑执行的。因此,如果译码宽度为ndcd,那么空闲列表中最多会浪费掉发射队列中ndcd-1个表项。在这种设计下,发射队列更像是一个“池”,用来尽可能多的暂存指令,使得后续的仲裁逻辑能够有更多的指令可以进行选择。
仲裁器
当一条指令的两个源操作数都就绪后,仲裁器就会从发射队列中选取最旧的一些指令,将它们发射到后续流水线里。然而,严格的从n个表项中选取年龄最大的m条指令,这是非常困难的,因此Zircon-2024采用了近似最旧的算法来实现这个功能。
对于拥有相同功能部件的每一个后端流水线,Zircon-2024都为其配备一个仲裁器。若发射队列一共n项,功能单元有k个,那么每个仲裁器都只能静态地看到n/k项指令,每个周期从这些指令中选取一条最旧的指令发射。显然这样是不一定能选取到全局最旧的k条指令的,但这也不失为一种降低仲裁器复杂度的方法。
load-store队列的仲裁
由于load-store指令操作的内存对象无法进行重命名,因此load-store必须按照一定的顺序来发射。Zircon-2024采用了store顺序,store间的load可以乱序的策略,来尽可能加快load指令的执行速度。load指令往往位于相关链的顶端(因为几乎所有的程序都是从内存中读取数据开始的),所以这种部分乱序的策略能够降低整体程序因为相关问题而导致的延迟。
唤醒
处理器后端配备了多条唤醒总线,用来将发射队列中某条指令的源操作数置为有效。对于一个功能流水线而言,当其中的某条指令的结果已经可预见的通过寄存器堆或旁路网络传递给另一个功能流水线时,前者就可以通过唤醒总线,唤醒后者对应的发射队列中的指令。同时,唤醒总线也会讲分派阶段的寄存器就绪表中对应的表项置置位。
推测唤醒
为了进一步加快load指令唤醒其他指令的速度,降低相关链延迟,Zircon-2024对load指令的相关指令采用了推测唤醒的激进策略。DCache确认一条load是否miss需要很多个流水级,一种保守的唤醒策略是:等待DCache确认load指令命中,该load指令才能唤醒其他指令。然而,DCache的命中率应当是非常高的,当load指令的DCache访问指令发出时,Zircon-2024就推测该load指令必定命中,尽可能在较早的流水级唤醒所有与之相关的指令。
然而,如果load指令的DCache访问指令发出后,DCache却给出了miss的结果,那么所有被唤醒的其他功能单元的指令就会读取到load指令执行前的旧值,这显然是不正确的。因此,解决这个问题的一个基本思想是:如果load出现DCache miss情况,那么其唤醒的所有指令都应该重新放回发射队列重新执行——这听起来是一个很难以实现,或者实现了也会造成很多时序问题的方法。
Zircon-2024借鉴了《超标量处理器设计》中的方法,为每个被load指令唤醒的指令打包一个加载位置向量(Load Postion Vector,简称LPV),用来记录唤醒该指令的load指令在流水线中的位置。每一条被load指令推测唤醒的指令虽然会被发射到后续流水线,但其在发射队列中的表项不会被回收。只有当与其相关load指令的DCache访问被确认命中后,该指令才会被认为确认发射,其发射队列表项才会被回收。如果LPV指示的与其相关的load指令发生了DCache miss,那么该指令在发射队列中的表项会被重新置为有效,且后端中的该指令会被抹除。这个过程称之为指令重演(Instruction Replay)。