GBZ80 - ADC 指令测试失败

GBZ80 - ADC instructions fail test

我已经 运行 Blarggs CPU tests 通过我的 Gameboy 模拟器,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;
}

我在测试 ROM 中输入了以下内容:

06 FE 3E 01 88

当设置进位标志时,A 的值为 0 (Flags = B0),并且 FF (Flags = 00 ) 当它不是。就我的理解而言,这就是它应该如何工作。然而,它仍然没有通过测试。

根据我的研究,我认为标志以与 ADD 相同的方式受到影响。从字面上看,我的代码与工作 ADD 指令的唯一变化是在前两行中添加了标志 check/potential 增量,我的测试代码似乎证明了它是有效的。

我错过了什么吗?也许 ADD/ADC 之间的旗帜状态有一个特点?作为旁注,SUB 指令也通过,但 SBC 以同样的方式失败。

谢谢

问题是 b 是一个 8 位值。如果 b 为 0xff 并且设置了进位,则将 1 添加到 b 会将其设置为 0,并且如果添加 a >= 1 则不会生成进位。您会遇到类似的问题如果低字节为 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;

这是如何运作的?如果没有进位进入该位,请考虑按位 "xor" 给出每个位的预期结果:0 ^ 0 == 0、1 ^ 0 == 0 ^ 1 == 1 和 1 ^ 1 == 0. 通过对 sumno_carry_sum 进行异或运算,我们得到和与 bit-by-bit 加法不同的位。 sum 只有在进位到特定位位置时才会不同。因此几乎没有开销就可以获得半进位和进位。