Reverse-engineering von MC86B09 MCU Code und Hardware

Es gibt 2 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

    Reverse-engineering von MC86B09 MCU Code und Hardware

    Ich habe hier ein Williams D-11581 Audio Board und bereits einiges an Infos zusammengesammelt.

    Erst mal ein paar Resourcen:
    Foto des Teils:
    Offizieller Schaltplan: D-11581 Schematic (Scan).pdf
    Meine - übersichtlichere, wie ich finde - Interpretation des Schaltplans: D-11581 Schematic (Eagle).png
    Eine kurze Liste der relevanten Bauteile. Äquivalente Typen in Klammern angegeben.
    • 68B90E Microprocessor MC68B09E MCU.pdf
    • 68B21 - Peripheral Interface Adapter
    • 74LS04 - Hex NOT Gate
    • 74LS10 - Triple 3-In NAND Gate
    • 74LS74 - Dual D-FlipFlop
    • 74LS138 - 3 To 8 Decoder
    • 74LS139 - Dual 2 To 4 Decoder
    • 74LS175 - Quad Combined D-FlipFlop
    • 27256/27512 - 32K/64K Parallel EPROM
    • DOC-20NA - Crystal Oscillator
    • MB8417 - 2K RAM
    • MC1408L6 - 8-bit Parallel DAC (~DAC0808)
    • MC1458P1 - Dual OpAmp (~LM358)
    • TDA2002 - Audio Amplifier
    • YM2151 - Sound Generator
    • YM3012 - Serial DAC

    Jumperfunktionen:
    • W1 (NC) / W6 (NO)
      Verbindet U3.!IC und U1.!IC ("Initial Clear" des Soundgenerators und DACs) mit...
      W6: der allgemeinen Reset-Leitung.
      W1: U12.CB1 (Special purpose I/O Pin des PIA).
    • W2 (NC) / W3 (NO)
      Verbindet Pin 1 aller EPROMs mit...
      W3: +5V. Wird bei 27256 (32K) EPROMs verwendet. Pin 1 = VPP.
      W2: U13.Q2. Wird bei 27512 (64K) EPROMs verwendet. Pin 1 = A15.
    • W4 (NO)
      Verbindet U3.!IC und U1.!IC ("Initial Clear" des Soundgenerators und DACs) mit...
      U12.CB2 (Special purpose I/O Pin des PIA) und J3.Pin12. Funktion unbekannt.
    • W5 (NC)
      Verbindet die allgemeine Reset-Leitung mit J3.Pin18. Das erlaubt einen Reset durch das externe CPU-Board.
    • W7 (NO)
      Verbindet +12V mit +5V. Funktion unbekannt. Der Audioverstärker benötigt immer +-12V.
    • W8 (NO) / W9 (NC)
      Verbindet U5.!WE ("Write Enable" des RAM) mit...
      W9: allgemeiner R/W-Leitung.
      W8: Masse. Funktion unbekannt.

    Mein Ziel ist es, herauszufinden, wie das Board über J3 Befehle entgegennimmt, und dann solche Befehle zu senden um diverse Sounds abzuspielen.
    Das funktioniert in manchen Fällen recht einfach, in manchen aber nicht.
    Zum Beispiel kann man einfach 0x04, 0x06, 0x08, 0x0A oder 0x0E an PB des PIA anlegen und dann CB1 kurz auf 0 ziehen. Dann wird Musik abgespielt. Aber das funktioniert nur mit diesen paar Songs. Andere Werte spielen teilweise die gleichen Songs (interessanterweise mit schlechterer Tonqualität) ab, teilweise hört man Soundeffekte bei gewissen Kombinationen von 0x02 und anderen Werten, aber ich konnte da noch nichts Reproduzierbares finden.

    Deshalb wollte ich mir den Code ansehen, der auf den EPROMs gespeichert ist, und den reverse engineeren.
    Schritt 1 ist also, eine Kopie der EPROMs zu finden. Die gibt's im Internet zu Hauf. Hier die Daten von "Taxi":
    U4: Taxi_U4.bin.txt bzw. Taxi_U4.hex.txt
    U19: Taxi_U19.bin.txt bzw. Taxi_U19.hex.txt
    (Bei Taxi gibt es keinen U20.)
    Es handelt sich um 27256 EPROMs, also ist W2 offen und W3 geschlossen.

    Schritt 2 ist es, herauszufinden, welche Adressen wo hin gemappt sind. Soweit ich das erkennen kann, sieht es folgendermaßen aus:

    Im D-FlipFlop U13 werden bei einem Schreib- oder Lesezugriff (Die R/W-Leitung kann 0 oder 1 sein) bei Adressen 0x7800 bis 0x7FFF die Bits D0 bis D2 gespeichert. D0 und D1 geben an, von welchem EPROM gelesen wird. D2 ist A15, gibt also bei 27512-EPROMs an, ob von 0x0000 bis 0x7FFF oder von 0x8000 bis 0xFFFF gelesen wird. Nach einem Reset sind diese Bits 0, es wird also von der unteren Hälfte von U4 gelesen. Auf Seite 6 des Datenblattes der MCU sind die Interrupt-Vektoren aufgelistet. Der !RESET-Vektor liegt bei 0xFFFE und 0xFFFF.

    Und jetzt geht's schon mit den Problemen los:

    Sieht man sich 0xFFFE und 0xFFFF in U4 an, sieht man: 0x80 0xAD
    Tabelle 9 auf Seite 28 des Datenblatts zeigt eine Liste aller OpCodes nach Wert sortiert. Dort findet man "80 SUBA". In Figure 18 auf Seite 31 findet man "SUBA" mit folgenden Eigenschaften:
    Op = 80: Der OpCode hat den Wert 80 (wie in Tabelle 9 gefunden).
    # = 2: Insgesamt werden 2 Bytes für diese Operation verwendet.
    "A - M -> A": M wird von A subtrahiert.
    Unter "Addressing Modes" -> "Immediate": Auf Seite 15 wird erklärt, dass "the data" (also das, was in Figure 18 als "M" bezeichnet wird) direkt nach dem OpCode im Speicher liegt, also bei 0xFFFF, also 0xAD.
    Hier wird also 0xAD (bzw. 173 in dezimal) von Register A abgezogen.

    Das alleine macht schon keinen Sinn. Hier sollte eigentlich ein Sprung abgelegt sein.

    Jetzt könnte man sagen, vielleicht soll der Program Counter einfach überlaufen und die Ausführung bei 0x0000 fortgesetzt werden, aber da liegt der RAM und es wäre schon sehr ungewöhnlich, einfach zufällige Werte, die noch im RAM sind, als Code auszuführen.

    Auch die Interrupt-Vektoren !FIRQ und !NMI sehen so aus.

    Also irgendwo muss ich hier falsch abgebogen sein.
    Hat jemand Ideen?
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Des Rätsels Lösung ist einfach: An 0xFFFE und 0xFFFF liegt nicht der auszuführende OpCode, sondern eine Adresse, zu der gesprungen wird. Von dort aus wird dann die Ausführung fortgesetzt. (Hier konkret wird beim Reset zur Adresse 0x80AD gesprungen.)
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils