眠りネ*_*ネロク 9 x86 instruction-set cpu-architecture program-counter riscv
我正在阅读《 RISC-V读者:开放式体系结构图集》一书。为了解释ISA(指令集体系结构)与特定实现(即微体系结构)的隔离,作者写道:
架构师的诱惑是将说明包含在ISA中,以帮助在特定时间实现一种实现的性能或成本,但会给不同的或将来的实现带来负担。
据我了解,它指出,在设计ISA时,ISA应该理想地避免公开实现它的特定微体系结构的细节。
请牢记上面的引号:当涉及程序计数器时,在RISC-V ISA上,程序计数器(pc)指向当前正在执行的指令。另一方面,在x86 ISA上,程序计数器(eip)不包含当前正在执行的指令的地址,而是包含当前指令之后的指令的地址。
x86程序计数器是否从微体系结构中抽象出来了?
我将以MIPS而不是x86来回答这个问题,因为(1)MIPS和x86在该领域具有相似性,并且(2)RISC V由Patterson等人开发,经过数十年的MIPS经验。 。我觉得在比较中可以最好地理解他们书中的这些陈述,因为x86和MIPS都编码相对于指令末尾的分支偏移量(在MIPS中为pc + 4)。
在MIPS和x86中,相对于PC的寻址模式仅在早期ISA版本的分支中都可以找到。后来的修订版增加了PC相对地址的计算(例如auipc,LEA或加载/存储的MIPS 或x86-64的RIP相对寻址模式)。这些都彼此一致:偏移量是相对于指令末尾(即下一条指令的开始)(即过去)编码的,而正如您所注意到的那样,在RISC V中,编码的分支偏移量(和auipc等)相对于指令的开始。
这样做的价值在于,它从某些数据路径中删除了一个加法器,有时这些数据路径中的一个可以位于关键路径上,因此对于某些实现,数据路径的这种较小的缩短意味着更高的时钟速率。
(当然,RISC V仍然必须为pc-next和调用指令的返回地址生成指令+ 4,但是在关键路径上要少得多。请注意,在下图中,两个都没有显示pc + 4的捕获。作为寄信人地址。)
让我们比较一下硬件框图:
MIPS数据路径(简体)
RISC V数据路径(简体)
您可以在RISC V数据路径图上看到标记为#5的行(红色,位于控制椭圆上方),绕过加法器(#4,将pc-next的pc加4)。
图表的归属
为什么x86 / MIPS在最初的版本中做出了不同的选择?
当然,我不能肯定地说。在我看来,可以做出选择,而且对于最早的实现来说根本不重要,因此他们甚至可能都不知道潜在的问题。无论如何,几乎每条指令都需要计算下一条指令,因此这似乎是合理的选择。
充其量,他们可能节省了几根线,因为其他指令(例如调用)确实需要pc-next,而不一定需要pc + 0。
对以前的处理器进行检查可能会发现,这只是当时所做的事情,因此,这可能更多地是继承了现有方法,而不是设计选择。
8086未流水线化(指令预取缓冲区除外),并且可变长度解码在开始执行之前已经找到指令的末尾。
经过多年的事后调查,现在在RISC V中解决了此数据路径问题。
我怀疑他们是否像在分支延迟时隙(MIPS)中那样,在相同水平上做出了有意识的决定。
根据评论中的讨论,8086可能没有任何例外情况会推动指令的起始地址。与更高版本的x86模型不同,除异常将div / idiv后的指令的地址压入。在8086中,在cs rep movsb(或其他字符串指令)推送最后一个前缀的地址之后的中断恢复,而不是包括多个前缀的整个指令。英特尔的8086手册(扫描的PDF)中记录了该“错误” 。因此,很有可能8086确实没有记录指令的起始地址或长度,而只是记录了开始执行之前解码完成的地址。该问题至少由286(也许是186 )修复,但适用于所有8086/8088 CPU。
MIPS从一开始就具有虚拟内存,因此它确实需要能够记录错误指令的地址,以便可以在异常返回后重新运行它。加上软件TLB未命中处理,还需要重新运行错误指令。但是异常的速度很慢,并且无论如何都会刷新管道,并且只有在获取之后才能检测到异常,因此无论如何都需要进行一些计算。
据我了解,它指出,在设计ISA时,ISA应该理想地避免公开实现它的特定微体系结构的细节。
如果您理想的ISA的度量标准是简单性,那么我可能会同意您的看法。但是在某些情况下,通过ISA暴露微体系结构的某些特征以提高性能可能是有益的,并且有许多方法可以使这样做的负担可以忽略不计。考虑例如x86中的软件预取指令。这些指令的行为在体系结构上定义为与微体系结构相关。英特尔甚至可以在将来设计一种微体系结构,使这些指令表现为无操作,而不会违反x86规范。唯一的负担就是定义这些指令的功能1。但是,如果在结构上定义了预取指令以将64字节对齐的数据预取到L3高速缓存中,并且没有CPUID位来允许对此指令的可选支持,那么将来这的确可能使支持这种指令成为巨大的负担。 。
x86程序计数器是否从微体系结构中抽象出来了?
在被@InstructionPointer编辑之前,您在此问题中提到了x86的“第一个实现”,即8086。这是一个具有两个管道阶段的简单处理器:提取和执行。架构寄存器之一是IP,定义为包含下一条指令的16位偏移量(距代码段基础)。因此IP,每条指令的架构值等于偏移量加上指令的大小。在8086中如何实现?实际上,没有物理寄存器存储该IP值。虽然只有一个物理指令指针寄存器,但是它指向要提取到指令队列中的下一个16位,最多可以容纳6个字节(请参阅:https://patents.google.com/patent/US4449184A/en)。如果正在执行的当前指令是控制转移指令,则根据指令的相对偏移量,物理中的当前值IP以及指令队列中的有效字节数,即时计算目标地址。例如,如果相对偏移为15,物理偏移为IP100,并且指令队列包含4个有效字节,则目标偏移为:100-4 + 15 =111。然后可以通过将20-相加来计算物理地址。位代码段地址。显然,建筑IP没有公开任何这些微体系结构细节。在现代Intel处理器中,可能有许多正在运行的指令,因此每个指令都需要携带足够的信息来重构其地址或以下指令的地址。
如果x86体系结构IP被定义为指向当前指令而不是下一条指令怎么办?这将如何影响8086的设计?好吧,相对于控制转移指令的相对偏移变为相对于当前指令的偏移,而不是下一个指令的偏移。在前面的示例中,我们必须从111中减去当前指令的长度,以获得目标偏移量。因此,可能需要其他硬件来跟踪当前指令的大小并将其包括在计算中。但是在这样的ISA中,我们可以将所有控制转移指令定义为具有统一的长度2(其他指令仍可以是可变长度的),从而消除了大部分开销。我想不出一个实际的例子,其中一种定义程序计数器的方法明显优于另一种方法。但是,它可能会影响ISA的设计。
脚注:
(1)解码器可能仍必须能够识别预取指令有效并发出相应的指令。但是,此负担不是定义微体系结构相关指令的结果,而是定义新指令的结果,而与这些指令的功能无关。
(2)或者,当前指令的长度可以存储在一个很小的寄存器中。IIRC,8086中的最大指令长度为6个字节,因此最多需要3位来存储任何指令的长度。即使在8086天内,该开销也很小。
| 归档时间: |
|
| 查看次数: |
198 次 |
| 最近记录: |