GBZ80 - ADC 指令测试失败

Tri*_*cer 4 z80 emulation adc gameboy

我一直在通过我的 Gameboy 模拟器运行Blaargs CPU 测试,并且op r,r测试显示我的 ADC 指令无法正常工作,但 ADD 可以正常工作。我的理解是,两者之间的唯一区别是在加法之前将现有的进位标志添加到第二个操作数。因此,我的 ADC 代码如下:

void Emu::add8To8Carry(BYTE &a, BYTE b) //4 cycles - 1 byte
{
    if((Flags >> FLAG_CARRY) & 1)
        b++;
    FLAGCLEAR_N;
    halfCarryAdd8_8(a, b); //generates H flag based on addition
    carryAdd8_8(a, b); //generates C flag appropriately
    a+=b;
    if(a == 0)
        FLAGSET_Z;
    else
        FLAGCLEAR_Z;
}
Run Code Online (Sandbox Code Playgroud)

我将以下内容输入到测试 ROM 中:

06 FE 3E 01 88
Run Code Online (Sandbox Code Playgroud)

当进位标志被设置时,A 的值为0 (Flags = B0),当进位标志未设置时,A 的值为FF (Flags = 00)。据我的理解,这应该是这样的。然而,它仍然未能通过测试。

根据我的研究,我相信标志受到与 ADD 相同的影响。从字面上看,我的代码与工作 ADD 指令相比的唯一变化是在前两行中添加了标志检查/潜在增量,我的测试代码似乎证明了这一点。

我错过了什么吗?也许 ADD/ADC 之间的标志状态有一个特殊之处?附带说明一下,SUB 指令也可以通过,但 SBC 以同样的方式失败。

谢谢

Geo*_*ips 5

问题是这b是一个 8 位值。如果b是 0xff 并且设置了进位,则加 1 将b其设置为 0,并且如果添加 >= 1,则不会生成进位。a如果低位 nybble 为 0xf,则半进位标志会出现类似的问题。

如果您致电并且设置了进位,则此问题可能会得到解决。但是,我怀疑这些例程也采用字节操作数,因此您可能必须在内部对它们进行更改。也许通过将进位添加为单独的参数,这样您就可以避免. 但我只能推测,没有这些函数的来源。halfCarryAdd8_8(a, b + 1);carryAdd8_8(a, b + 1);tmp = a + b + carry;b

在某种程度上相关的说明中,有一种相当简单的方法来检查所有位的进位:

int sum = a + b;
int no_carry_sum = a ^ b;
int carry_into = sum ^ no_carry_sum;
int half_carry = carry_into & 0x10;
int carry = carry_info & 0x100;
Run Code Online (Sandbox Code Playgroud)

这是如何运作的?考虑一下,如果没有进位进入该位,则按位“异或”会给出每个位的预期结果:0 ^ 0 == 0、1 ^ 0 == 0 ^ 1 == 1 和 1 ^ 1 == 0。通过与 进行异或,sum我们no_carry_sum得到总和与逐位加法不同的位。 sum仅当进位到特定位位置时才不同。因此,半进位和进位位都可以在几乎没有开销的情况下获得。

  • 谢谢,两位。由于我已经通过分别将结果与 0x10 / 0x100 进行 AND 运算来检查 H/C,因此我只需要在求和之后添加进位即可正确保留标志。该指令现已通过测试! (2认同)