2017-07-21 2 views
1

Ich möchte zuerst meine Frage vorbringen, indem ich zuerst sage, dass ich ein ziemlich erfahrener Programmierer bin, vor allem, weil Java ihn seit 8 Jahren benutzt.Z80 DAA-Implementierung und Blarggs Test-ROM-Ausgaben

Ich beschloss, in einem Versuch, mein Verständnis von Hardware-Betrieb und Betriebssystem Themen zu verbessern, einen einfachen Gameboy-Emulator zu programmieren. Nachdem ich die Kernfunktionalität in nur wenigen Tagen programmiert hatte, testete ich den Emulator, um festzustellen, dass nichts auf dem Bildschirm gezeichnet wurde. Nachdem ich nacheinander mehrere hundert Opcodes in meinem Emulator durchgespielt und mit den im BGB-Emulator gefundenen Werten verglichen hatte, erkannte ich, dass die fraglichen Kacheln und Sprites in den Speicher geladen wurden, nur nicht gezeichnet. Daraus ging hervor, dass das Problem in einer oder mehreren meiner Opcode-Implementierungen liegen muss, was dazu führt, dass das Programm irgendwann ein falsches Verhalten zeigt. Aus diesem Grund habe ich mich entschieden, Blarggs CPU-Test-ROMs (http://gbdev.gg8.se/files/roms/blargg-gb-tests/) zu verwenden, um mir dabei zu helfen, das Problem zu identifizieren. Um jedoch das erste Test-ROM ausgeführt wird, gibt die folgende Fehlermeldung:

01-special 

36E1FE30 
DAA 

Failed #6 

ich die DAA Operation mehrmals überprüft und es scheint richtig zu mir umgesetzt werden. Der angegebene Fehlercode ("36E1FE30") ist absolut nicht hilfreich, da ich nicht finden kann, was das bedeutet. Für mich bedeutet dies, dass entweder DAA falsch implementiert ist und ich meinen Fehler nicht sehen kann oder eine der Operationen, die verwendet werden, um die Richtigkeit von DAA zu validieren, ist falsch. Wenn ich einen der anderen Tests ausgeführt erscheinen sie in einer Schleife auf unbestimmte Zeit

03-op sp,hl 

03-op sp,hl 

03-op sp,hl 

03-op sp,hl 

Als Referenz meine DAA-Implementierung auf Github ist (https://github.com/qkmaxware/GBemu/blob/master/src/gameboy/cpu/Opcodes.java) oder unten wie folgt zu sehen:

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); 
}); 

Wo solche Anrufe als reg.a() bedeutet gelesen aus dem Register a, reg.a (Wert) bedeutet Schreiben in Register a (Maske auf 8 oder 16 Bits abhängig vom Register). In ähnlicher Weise können die Flags Z, N, H, C erhalten oder mit den Null-, Subtrahier-, Halbcarry- und Übertragsfunktionen des "reg" -Objekts gesetzt/zurückgesetzt werden.

Also meine Frage ist dreifach, habe ich die DAA-Operation falsch implementiert, so dass es Blargg Tests fehlschlägt, weiß jemand, was der Fehlercode ich habe, oder hat jemand irgendwelche Ideen, wie ich meine Suche nach dem falschen konzentrieren kann Betrieb.

Antwort

3

Sieht aus wie Blarggs Tests aus einem alten Z-80-Testprogramm namens zexlax, das den pragmatischen Ansatz der Behandlungstests als einfachen Datenvergleich behandelt. Für DAA führt es alle möglichen Kombinationen von Eingaben aus und überprüft das effektiv gegen die erwartete Antwort. Wenn man jedoch alle Antworten einhält, wird der Testcode unpraktisch groß. Stattdessen vergleicht es die CRCs der Daten. Wie Sie erfahren haben, ist dies sehr effektiv, um die korrekte Funktionsweise eines Emulators zu überprüfen, aber es ist ziemlich nutzlos, wenn Sie darauf hinweisen, wie Sie es beheben können.

Während es ideal wäre, wenn jemand die korrekte Ausgabe speichert, so dass Sie es gegen Ihre Implementierung überprüfen können, können Sie dies dennoch tun, indem Sie den Test auf einem bekannten guten Emulator ausführen. Oder vergleichen Sie einfach Ihre Implementierung mit einem guten Emulator.

Hier ist, wie MAME tut es:

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; 

Weiteren Kontext, hier ist ein Link auf die ganze Quelle:

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

Sieht aus wie es einige Unterschiede mit Ihrem Code sein könnte, aber ich habe nicht wirklich genau hingesehen.

Ich bemerke, dass die Blargg Tests die undokumentierten Flag Bits 3 und 5 enthalten. Wenn dies ein Z-80 Prozessor wäre, würde es einen Emulator nicht, der diese Bits nicht setzt, was tatsächlich nicht vorhersagbar ist dokumentiert als alles, auf das Sie sich verlassen können. Ich weiß nicht, ob das Sharp LR35902 ein ähnliches Problem hat, aber wenn es so ist, ist es durchaus möglich, dass MAME das nicht implementiert. Diese Bits werden wahrscheinlich niemals einen Unterschied für ein "echtes" Programm ausmachen.

+1

Wow, danke für die tollen Informationen über die Test-ROMs und den Link zu den MAME-Opcode-Implementierungen. Die Opcode-Implementierungen sind so viel besser zu lesen als einige der anderen Open-Source-Projekte. – Hals

+0

@Hals: Hast du jemals herausgefunden, was das Problem in deinem eigenen Code war, oder hast du es einfach weggeworfen und stattdessen MAME's benutzt? – usr2564301

+0

@ usr256430: 1 Am Ende habe ich eine Kombination aus der MAME-Version und anderen Versionen von anderen Emulatoren auf GitHub verwendet, anstatt meiner eigenen. – Hals

Verwandte Themen