计算Intel 8086的时钟周期数

4

我已经在做Intel 8086仿真器约一个月了。我决定开始计算周期以使仿真更准确并与PIT正确同步。

每个指令所用的时钟周期在Intel的用户手册中有详细说明,但我想知道它们是如何计算的。例如,对于XCHG mem8,reg8指令,手册中明确规定需要17个时钟周期,我已经推断出以下步骤:

  1. 解码指令的第二个字节:+1个周期;
  2. 将第一个操作数从内存传输到临时位置:+7个周期;
  3. 将第二个操作数从寄存器传输到内存目标:+8个周期;
  4. 将第一个操作数从临时位置传输到寄存器目标:+1个周期。

但我可能完全错误,因为我的推理似乎并不适用于所有指令。例如,我无法理解为什么PUSH reg 指令需要11个时钟周期,而POP reg指令仅需要8个时钟周期。

所以,你能告诉我每个指令中时钟周期是如何花费的,或者说有一种通用方法来理解这些数字从哪里来吗?
谢谢。

3
PUSH基本上是从寄存器到内存的MOV操作。POP是从内存到寄存器的MOV操作。从表格中可以看出,前者是9+EA,后者是8+EA。由于你可以使用0 EA进行POP(堆栈指针已经指向你将要POP的位置),因此这个过程可以立即开始,并且一旦不再需要读取周期,堆栈指针的减量就可以(我猜想)与读取周期重叠。对于PUSH操作,有2个EA,因为必须在发出MOV之前增加堆栈指针。我认为这可能是额外的时钟周期来自的地方。这只是推测,我不能确定。 - J...
@J... 这很有道理。谢谢您先生!您是否知道为什么从寄存器到内存的 MOV 操作需要 9 个时钟周期,而从内存到寄存器的 MOV 操作只需要 8 个时钟周期?以及它在每个子操作中如何分解时钟周期? - neat
1
@J...我已经阅读了我的原始帖子中链接的手册。除了表格外,它并没有提供更多信息。我还阅读了这个,但是里面的解释(第107页)与我的观察或第一个手册都不一致。 - neat
1
你想要的书是Michael Abrash的《汇编语言禅宗》,这本书已经很久没有再版了,但仍然可以在二手市场上找到。据我回忆,你不能轻易地将这些时间分解为子操作。此外,还有一些隐藏成本,如指令预取和DMA刷新(诚然是特定于平台的),你必须考虑到这些成本。官方指令时间告诉你CPU上正在发生什么,但它们是“最佳情况”,假设支持硬件不会添加任何东西。 - Jim Mischel
@JimMischel 我找到了这本书的在线版本。非常棒的阅读材料,谢谢您先生! - neat
显示剩余7条评论
2个回答

4
如何计算周期,实际上 clock 的作用是什么,这些问题对我来说也是个谜,直到我有机会与硬件人员一起工作,看到他们使用的模型。答案在硬件中。 CPU 是并行机器,尽管对程序员来说,它的设计通常是用一些简化的术语来描述流水线或需要实现的microinstructions等,但 CPU 仍然是并行机器。
为了完成指令,许多微小的 bit-size 信号必须从一端流向另一端。在某些地方,处理单元必须等待所有输入的 bit 到达。这种从一个stage 到另一个stage的协调运动由发送到所有部件的clock-signal驱动。由clock-signal鼓动的每个这样的移动被称为cycle
因此,为了知道完成工作需要多少个“cycle”,您必须考虑“wire”是如何连接的,以及“bit”必须流经哪里以及所需的同步点在哪里以及有多少个。

enter image description here

我怀疑Intel 8086的原理图是否公开可用,即使是可用的,我也怀疑其可读性。但唯一正确的答案就在那里。其他所有内容都只是简化,在软件中复制精确的硬件行为,您需要模拟/解释CPU的硬件。
另请参见:

1
我认为,在指令执行的方式中有一些重复的模式(不考虑“将其放入队列中”这一部分)。但我猜这对于我尝试完成的任务来说太过复杂,所以我直接实现了用户指南中的时钟周期到我的模拟器中,并且似乎工作得还不错。非常感谢!链接:https://github.com/NeatMonster/Intel8086/commit/68e2cb69bebb67e0fedf9028af6b834379220083 - neat

2
这个问题很广泛,因此我只会在这里回答 PUSHPOP 的问题。 PUSH 基本上是从寄存器到内存的 MOV(加上寄存器增量)。POP 是从内存到寄存器的 MOV(加上寄存器减量)。
如果您查看第2-61页,您会发现:

MOV

register, memory 8+EA 1 2-4 MOV BP, STACK_TOP

memory, register 9+EA 1 2-4 MOV COUNT [DI], CX

对于 POP 操作,您已经在一个寄存器中有了堆栈指针,因此有效地址(EA)为零。您可以立即执行 MOV 操作,我只能假设特殊的 POP 操作可以在同一时间减少堆栈指针,在读取操作的后面时钟周期中不再需要地址时。
对于 PUSH 操作,您有一个 EA 为2,因为必须在获取所需地址以执行写入之前递增堆栈指针。这里不能利用并发性,因此您需要9个周期来执行MOV,似乎还需要两个周期来计算有效地址(堆栈指针增量)。

@AlexanderZhak,什么原因可以解释8086读写之间的差异?我的XCHG时钟周期分解方法正确吗? - neat
@AlexanderZhak 是的,OP的问题是关于8086的,所以我回答了这个问题。至于为什么,英特尔多年来一直在改进...怀疑你需要相当深入的CPU架构信息才能回答他们到底做了什么来改变事情。新的CPU需要考虑延迟和吞吐量-我认为8086没有进行流水线处理,因此指令时间包括完整的获取、解码、读/写等序列。 - J...
1
@NeatMonster 听起来你有很多问题。在使用Stack Overflow时,适当的方式是思考你正在做什么,并尝试将你的问题分解为单独的问题。你应该在这里问每一个问题-一个问题,一个答案。这就是它的工作原理。这不是一个帮助论坛-继续在评论中提出越来越多的问题并不是这个网站的工作方式。 - J...
1
@J...我不能比“能否给我一个理解时钟周期如何计数的一般方法”更具体了。是否有另一个网站更容易接受这样的问题? - neat
1
@NeatMonster 我认为这个问题没有普遍的答案 - 我认为每个指令都有自己的故事要讲述,每个指令都需要对CPU架构进行微观分析。考虑到CPU的800多页手册无法充分回答问题 - 这意味着这是一个非常深入的问题,不容易在短短几段文字中回答。一个合适的下一个问题可能是“为什么8086 MOV对于r,m需要8个周期,但对于m,r需要9个周期?”例如。它简洁明了,可回答,并可能使您更接近回答您的更大问题。 - J...
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接