几乎可以肯定 Game Boy 中使用的 SM83 CPU 核心具有 8 位 ALU,这意味着 16 位 ALU 操作实际上由两个 8 位操作组成。与普通的 Z80 CPU 一样,它还有一个专门的 16 位递增/递减/加载单元,可以快速处理某些 16 位操作,但无法更新标志位。基本上:
- 如果更新了标志位,则 16 位操作一定涉及 ALU,因此在底层实际上使用了两个 8 位 ALU 操作
- 如果未更新标志位,并且 16 位操作仅为 +1/-1/load,则使用 16 位递增器单元
因此,每当你涉及标志位时,如果想考虑操作,请尝试以 8 位操作(低字节优先,然后是高字节)为基础进行推理。
问答:
1. 在操作码 0xE8 中,半进位标志如何行为?
正如其他答案所指出的那样,当从位 3 中存在进位时,H 被设置。(当从位 7 中存在进位时,C 被设置)
这是一个有趣的思维练习:如果
SP=$FFFF
并执行
ADD SP, -1
,则会得到
SP=$FFFE
,
同时设置 H 和 C. 你能理解为什么会这样吗?
提示 ↑
2. 操作码 0xE8 在物理硬件中如何实现?
我们尚未完全理解它在最低可能级别上的工作原理,但我知道有两个 8 位操作。通过我的 Game Boy 测试系统,我确认首先进行了更新标志(H,C)但不更新 SP 的 ALU 操作,然后进行另一些操作,最后 SP 一次性更新。这表明
ADD SP, e
可能实际上会在两个分离的 8 位操作中将结果计算到某个临时寄存器中(例如,真正的 Z80 对于某些 ALU 操作具有不可见的 WZ 临时寄存器),然后从中加载 SP。
我认为
ADD HL, BC
是一个更有趣的例子…通过我的测试系统,我确认它首先更新 L,然后是 H,并且
标志位被更新两次。这意味着它实际上执行了类似以下内容的操作:
ADD L, C
ADC H, B
后面的8位操作更新标志寄存器,因此我们看不到“ADD L, C”的结果标志。但是如果从L的第3位进位,那么半进位标志可能暂时被设置!
3. 半进位是从第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位递增/递减单元执行)
- DEC rr:没有标志更新(由16位递增/递减单元执行)