Z80 DAA实施和Blargg的测试rom问题

时间:2017-07-21 02:08:18

标签: java debugging emulation z80

我首先要说的是我的问题首先是说我是一位经验丰富的程序员,特别是Java已经使用了8年。

为了提高我对硬件操作和操作系统主题的理解,我决定编写一个简单的Gameboy模拟器。在几天内编写了核心功能后,我测试了模拟器,发现屏幕上没有任何内容。在我的模拟器中逐步执行几百个操作码并将其与BGB模拟器中的值进行比较后,我意识到所讨论的图块和精灵正被加载到内存中,而不是被绘制。从这一点我发现问题必须在我的一个或多个操作码实现中导致程序在某些时候表现出错误的行为。因此,我决定使用Blargg的cpu测试roms(http://gbdev.gg8.se/files/roms/blargg-gb-tests/)来帮助我解决这个问题。但是,运行第一个测试rom,会出现以下错误消息:

01-special

36E1FE30 
DAA

Failed #6

我已经多次检查了DAA操作,它似乎正确地实现了我。给出的错误代码(“36E1FE30”)完全没有用,因为我似乎无法找到这意味着什么。对我来说,这意味着DAA未正确实现,我只是看不到我的错误,或者用于验证DAA正确性的操作之一是不正确的。如果我运行任何其他测试,它们似乎无限循环

03-op sp,hl

03-op sp,hl

03-op sp,hl

03-op sp,hl

作为参考,我的DAA实现在github(https://github.com/qkmaxware/GBemu/blob/master/src/gameboy/cpu/Opcodes.java)上,或者如下所示:

Op DAA = new Op(0x27, "DAA", map, () -> {
    int a = reg.a();

    if(!reg.subtract()){
        if(reg.halfcarry() || (a & 0xF) > 9)
            a += 0x06;

        if(reg.carry() || a > 0x9F)
            a += 0x60;
    }else{
        if(reg.halfcarry())
            a = (a - 0x6) & 0xFF;

        if(reg.carry())
            a = (a - 0x60) & 0xFF;
    }

    reg.a(a);

    reg.zero(isZero(a));
    reg.carry((a & 0x100) == 0x100);
    reg.halfcarry(false);

    clock.m(1);
    clock.t(4);
});

其中诸如reg.a()之类的调用意味着从寄存器a读取,reg.a(值)意味着写入寄存器a(根据寄存器,掩码为8或16位)。类似地,标志Z,N,H,C可以通过'reg'对象的零,减,半运载,进位函数来获得或设置/重置。

所以我的问题是三重的,我是否错误地实施了DAA操作,以致它失败了Blargg的测试,有没有人知道我的错误代码意味着什么,或者有没有人有任何想法如何我可以集中我的搜索不正确的操作。

1 个答案:

答案 0 :(得分:5)

看起来Blargg的测试借鉴了一个名为zexlax的旧Z-80测试程序,它采用实用的方法将指令测试视为简单的数据比较。对于DAA,它运行所有可能的输入组合,并根据预期答案有效地检查。但是保留所有答案会使测试代码变得不切实际。相反,它会比较数据的CRC。正如您所经历的那样,这在验证模拟器的正确操作方面非常有效,但在指出如何修复它时却毫无用处。

虽然如果有人保存了正确的输出以便你可以根据你的实现进行检查,那么你仍然可以通过在已知良好的模拟器上运行测试来实现。或者只是将您的实现与知名的模拟器进行比较。

以下是MAME的表现:

case 0x27: /*      DAA */
    {
        int tmp = m_A;

        if ( ! ( m_F & FLAG_N ) ) {
            if ( ( m_F & FLAG_H ) || ( tmp & 0x0F ) > 9 )
                tmp += 6;
            if ( ( m_F & FLAG_C ) || tmp > 0x9F )
                tmp += 0x60;
        } else {
            if ( m_F & FLAG_H ) {
                tmp -= 6;
                if ( ! ( m_F & FLAG_C ) )
                    tmp &= 0xFF;
            }
            if ( m_F & FLAG_C )
                    tmp -= 0x60;
        }
        m_F &= ~ ( FLAG_H | FLAG_Z );
        if ( tmp & 0x100 )
            m_F |= FLAG_C;
        m_A = tmp & 0xFF;
        if ( ! m_A )
            m_F |= FLAG_Z;
    }
    break;

有关更多背景信息,请参阅以下链接:

https://github.com/mamedev/mame/blob/master/src/devices/cpu/lr35902/opc_main.hxx#L354

看起来您的代码可能存在一些差异,但我没有仔细看过。

我注意到Blargg的测试包括未记录的标志位3和5.如果这是一个Z-80处理器,它将失败一个仿真器,它不会将这些位设置为Z-80,这实际上是可预测的,只是没有记录作为你可以依赖的任何东西。我不知道夏普LR35902是否有类似的问题,但如果是这样的话,MAME完全有可能没有实现。这些位永远不会对“真实”程序产生影响。