15

像许多其他人一样,我正在编写一个 Game Boy 模拟器,并且我对指令 0xE8(ADD SP, n带有 8 位立即数)有几个问题。

这里声称,在 16 位指令中,如果从位 7 到位 8 发生进位,则设置半进位标志,而这里说半进位标志指示从位 11 到位 12 的进位。 Reddit 线程似乎对这个问题有些困惑,而且(我听说是臭名昭著的缺陷)Game Boy CPU 手册似乎也没有什么有用的说法。

我的问题如下:

  1. 半进位标志在操作码 0xE8 中的行为如何?
  2. opcode 0xE8 是如何在物理硬件中实现的?
  3. 哪个是正确的,半进位是从第 7 位到第 8 位,还是半进位是从第 11 位到第 12 位(在 16 位指令的情况下)?
4

2 回答 2

9

TL;DR:对于ADD SP,n,当从位 3 到位 4 发生进位时设置 H 标志。


我决定在真实硬件上进行测试,因此我在 GB-Z80 程序集中编写了一个简单的测试 ROM,用于测试以下场景:

[SP = $000F]
ADD SP,$01

[SP = $00F0]
ADD SP,$10

[SP = $0FF0]
ADD SP,$10

对于每种情况,我将寄存器的值存储FADD内存中,然后在屏幕上显示每个字节的第 5 位(H 标志)。

我在 3 个不同的模型(Gameboy Pocket、Gameboy Color 和 Gameboy Advance SP)上运行了这个,并在所有 3 个设备上得到了以下输出:1 0 0. 因此,位 3->4 的进位导致 H 被设置,而位 7->8 或 11->12 的进位则没有。


对于ADD HL,rr(where rris BC/DE/HL/SP) 来说,这似乎是一个不同的故事。根据我的测试,如果从第 11 位到第 12 位发生进位,则设置 H。

于 2019-09-17T16:36:40.947 回答
8

Game Boy 中使用的 SM83 CPU 内核几乎肯定有一个 8 位 ALU,这意味着 16 位 ALU 操作实际上是由两个 8 位操作组成的。与普通的 Z80 CPU 一样,它也有一个专用的 16 位递增/递减/加载单元,可以快速处理某些 16 位操作但不能更新标志。基本上:

  • 如果更新 flags,一个 16 位操作肯定会涉及到 ALU,所以它实际上使用了两个 8 位 ALU 操作
  • 如果未更新标志,并且 16 位操作只是 +1 / -1 / 加载,则使用 16 位增量单元完成

因此,每当您处理标志时,如果您想对操作进行推理,请尝试从 8 位操作(首先是低字节,然后是高字节)的角度来考虑。

  1. 半进位标志在操作码 0xE8 中的行为如何?

正如另一个答案中所指出的,当第 3 位有进位时设置 H。(当第 7 位有进位时设置 C)。

这是一个有趣的思考练习:如果SP=$FFFF你执行ADD SP, -1,你会得到SP=$FFFE H 和 C 都被设置。你能明白为什么吗?

由于有符号数字的工作方式,在这种情况下,低字节操作基本上只是一个正常的加法。-1= $FF,所以它在计算$FF+ $FF

上面的提示↑</p>

  1. opcode 0xE8 是如何在物理硬件中实现的?

我们还没有在尽可能低的级别上完全理解它,但我知道有两个 8 位操作。使用我的 Game Boy 测试平台系统,我已经确认首先有一个 ALU 操作更新标志(H,C)但不更新 SP,然后是其他一些操作,最后 SP 一次原子更新。这表明ADD SP, e实际上可能在两个单独的 8 位操作中将结果计算到某个临时寄存器中(例如,真正的 Z80 有一个不可见的 WZ 临时寄存器用于某些 ALU 操作),然后从中加载 SP。

我认为这ADD HL, BC是一个更有趣的例子......我的测试平台已经确认它首先更新 L 然后 H,并且标志被更新两次。这意味着它实际上执行了类似

ADD L, C
ADC H, B

后一个 8 位操作会更新标志,因此我们永远不会看到ADD L, C. 但是如果 L 位 3 有进位,半进位标志可能会被临时设置!

  1. 哪个是正确的,半进位是从第 7 位到第 8 位,还是半进位是从第 11 位到第 12 位(在 16 位指令的情况下)?

这取决于指令,但是如果您从 8 位值的角度考虑,标志总是基于相同的位位置进行更新......无论我们谈论的是 16 位的高字节还是低字节,它都会有所不同价值。第 11 位只是高字节的第 3 位。

  • ADD SP, e: H 来自第 3 位,C 来自第 7 位(来自低字节操作的标志)
  • LD HL, SP+e: H 来自第 3 位,C 来自第 7 位(来自低字节操作的标志)
  • ADD HL, rr: H 来自第 11 位,C 来自第 15 位(来自高字节操作的标志)
  • INC rr:无标志更新(由 16 位 inc/dec 单元执行)
  • DEC rr:无标志更新(由 16 位 inc/dec 单元执行)
于 2019-09-17T20:52:28.970 回答