【问题标题】:GBZ80 - ADC instructions fail testGBZ80 - ADC 指令未通过测试
【发布时间】:2017-02-07 13:34:41
【问题描述】:

我一直在通过我的 Gameboy 模拟器运行 Blarggs CPU testsop 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 指令的唯一变化是在前两行中添加了标志检查/潜在增量,我的测试代码似乎证明了这一点。

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

谢谢

【问题讨论】:

    标签: emulation adc z80 gameboy


    【解决方案1】:

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

    它是如何工作的?如果没有进位进入该位,则按位“xor”给出每个位的预期结果:0 ^ 0 == 0、1 ^ 0 == 0 ^ 1 == 1 和 1 ^ 1 == 0。通过对sumno_carry_sum 进行异或运算,我们得到总和与逐位加法不同的位。 sum 仅在进位到特定位时不同。因此,几乎没有开销即可获得半进位和进位位。

    【讨论】:

    • 我也看到了这个问题。要实现,您可以这样做:如果设置了输入进位,则增加 a,如果 a==0,设置 c 标志,然后执行修改后的“add a,b”,它不能重置 c 标志,但可以设置它。然后常规的“add a,b”可以重置 c 标志并调用相同的修改 add。
    • 谢谢,两位。因为我已经通过分别与 0x10 / 0x100 对结果进行与运算来检查 H/C,所以我只需要添加进位 after 对它们求和以正确保留标志。指令现在通过了测试!
    猜你喜欢
    • 1970-01-01
    • 2017-11-16
    • 2017-02-09
    • 1970-01-01
    • 2011-02-10
    • 2016-04-26
    • 1970-01-01
    • 2020-08-08
    • 1970-01-01
    相关资源
    最近更新 更多