Arcade Reverse Engineering: Nehmen Sie Michael Jordan bei NBA Jam auf


Letzten Sommer wurde ich zu einer Party in Sunnyvale eingeladen. Es stellte sich heraus, dass die Besitzer in der Garage einen Arcade-Automaten NBA JAM Tournament Edition für vier Spieler haben. Trotz der Tatsache, dass das Spiel bereits über 25 Jahre alt ist (es wurde 1993 veröffentlicht), ist es immer noch sehr interessant, es zu spielen, insbesondere für begeisterte Fans.

Ich war überrascht von der Liste der Chicago Bulls-Spieler, zu denen Michael Jordan nicht gehörte. Quellen [1] zufolge erhielt MJ eine eigene Lizenz und war nicht Teil des Geschäfts, das Midway mit der NBA abgeschlossen hatte.

Nachdem ich den Besitzer der Maschine gefragt hatte, fand ich heraus, dass die Hacker einen Mod für SNES "NBA Jam 2K17" veröffentlicht haben, mit dem neue Spieler und MJ spielen können, aber niemand hat daran gearbeitet, wie die Arcade-Version funktioniert. Deshalb musste ich unbedingt reinschauen.

Hintergrund


Die Geschichte des NBA Jam beginnt nicht mit Basketball, sondern mit Jean-Claude Van Damme. Ungefähr zur gleichen Zeit, als Universal Soldier veröffentlicht wurde, entwickelte Midway Games eine Technologie zur Manipulation großer, digitalisierter, fotorealistischer Sprites, die Ähnlichkeit mit echten Schauspielern haben. Es war ein großer technologischer Durchbruch: Animationen mit 60 Bildern pro Sekunde, bisher nicht sichtbare Sprites mit einer Größe von 100 x 100 Pixel, von denen jedes eine eigene 256-Farben-Palette hatte.

Das Unternehmen setzte diese Technologie mit großem Erfolg im beliebten Shooter „Terminator 2: Judgement Day“ [2] ein , konnte jedoch keine Lizenz für den „Universal Soldier“ erwerben (die finanziellen Bedingungen von JCVD ​​waren für Midway nicht akzeptabel [3] ). Als die Verhandlungen scheiterten, änderte Midway seinen Kurs und begann 1991 mit der Entwicklung eines Capcom-Megahit-Kampfspiels namens Street Fighter II: The World Warrior.

Ein vierköpfiges Team wurde zusammengestellt (Ed Boone schrieb den Code, John Tobias machte Kunst und Drehbuch, John Vogel zeichnete Grafiken und Dan Forden war Toningenieur). Nach einem Jahr harter Arbeit [4] startete Midway 1992 den Mortal Kombat.

Der visuelle Stil unterschied sich stark von der üblichen Pixelkunst, und das Design des Spiels war, gelinde gesagt, "kontrovers". Das Spiel mit Litern Blut auf dem Bildschirm und wahnsinnig grausamem „Tod“ wurde sofort zum Welthit und verdiente in einem Jahr fast 1 Milliarde Dollar [5] .


SF2: 384 × 224 mit 4.096 Farben.


MK: 400 × 254 mit 32.768 Farben.

Interessante Tatsache: Wie im VGA-Modus 0x13 auf dem PC waren die Pixel in diesen Spielen nicht quadratisch. Obwohl der Mortal Kombat-Rahmenpuffer eine Größe von 400 × 254 hat, wird er auf ein Verhältnis von 4: 3 eines CRT-Bildschirms gedehnt, was eine Auflösung von 400 × 300 ergibt [6].

Midway T-Unit Ausrüstung


Die von Midway für Mortal Kombat entwickelte Hardware erwies sich als sehr gut. So gut, dass er seinen eigenen Namen T-Unit erhielt und in anderen Spielen wiederverwendet wurde.

  • Mortal Kombat.
  • Mortal Kombat II.
  • NBA Jam.
  • NBA Jam Tournament Edition.
  • Richter Dredd (wurde nicht freigelassen).

T-Unit besteht aus zwei Platinen. Die meisten von ihnen beschäftigen sich mit Spielelogik und Grafik.


NBA JAM TE Edition-Prozessorkarte (ca. 40 x 40 cm oder 15 Zoll).


Das andere Board ist weniger kompliziert, kann aber auch viel. Es ist für Audio konzipiert, kann jedoch nicht nur Musik mit FM-Synthese, sondern auch digitalen Sound wiedergeben.

Die Soundkarte ist an eine Stromquelle angeschlossen und eine Grafikkarte ist auf der Rückseite installiert. Achten Sie auf den riesigen Kühler in der oberen linken Ecke.

Zusammen enthalten diese beiden Karten mehr als zweihundert Chips, Widerstände und EPROM. All dies nur anhand von Seriennummern zu verstehen, wäre sehr zeitaufwändig. Aber überraschenderweise wird manchmal in Geräten aus den 90er Jahren versehentlich Dokumentation entdeckt. Und im Fall von NBA Jam war sie einfach großartig.

Midway T-Unit Architektur


Auf der Suche nach Daten stieß ich auf ein NBA Jam Kit. Der Detaillierungsgrad dieses Dokuments ist erstaunlich [7] . Unter anderem gelang es mir, eine detaillierte Beschreibung der Kabelverbindungen einschließlich EPROMs und Chips zu finden.


Die Informationen aus dem Dokument ermöglichten es uns, ein Diagramm der Platinen zu zeichnen und die Funktion jedes Teils zu bestimmen. Um die Suche nach Komponenten zu erleichtern, hat die Karte Koordinaten mit einem Anfang in der unteren rechten Ecke (UA0), der bis zur oberen linken Ecke (UJ26) ansteigt.


Das Herzstück der Hauptplatine ist Texas Instrument TMS34010 (UB21) mit einer Frequenz von 50 MHz und 1 Mebibyte-Code in EPROMs und 512-Kibibyte-DRAM [8] . 34010 ist ein 32-Bit-Chip mit einem 16-Bit-Bus, der so bemerkenswerte grafische Anweisungen wie PIXT und PIXBLT enthält [9] . In den frühen 90er Jahren wurde dieser Chip in mehreren Hardwarebeschleunigungskarten verwendet [10] , und ich dachte, dass er eine beträchtliche Anzahl von Grafikeffekten verarbeitet. Überraschenderweise beschäftigt er sich nur mit Spielelogik und zeichnet nichts.

Tatsächlich erwies sich der UE13-Chip mit dem Namen „DMA2“ als grafisches Monster. Nach den Diagrammen aus der Dokumentation verfügt es über einen beeindruckenden (damals) 32-Bit-Datenbus und einen 32-Bit-Adressbus, weshalb es zum größten Chip auf der Platine wurde. Diese spezialisierte integrierte Schaltung (ASIC) kann viele grafische Operationen ausführen, auf die ich weiter unten eingehen werde.

Alle Chips (System-RAM, GFX-EPROM, Paletten-SDRAM, Code, Videobanken) werden einem 32-Bit-Adressraum zugeordnet und mit demselben Bus verbunden. Ich konnte keine Informationen zum Busprotokoll finden. Wenn Sie also etwas darüber wissen, schreiben Sie eine E-Mail.

Achten Sie auf einen Trick: Eine EPROM-Komponente (blau markiert) wird verwendet, um ein anderes Speichersystem zu erstellen (und Geld zu sparen). Diese 512-kb-EPROMs verfügen über 32-Bit-Adresspins und 8-Bit-Datenpins. Bei 34010, für den ein 16-Bit-Datenbus erforderlich ist, sind zwei EPROMs (J12 und G12) mit einem doppelten Adresswechsel verbunden, wodurch ein Speicher von 1 Mebibyte entsteht. In ähnlicher Weise werden grafische Ressourcen mit einem vierfachen Adresswechsel verbunden, um eine 32-Bit-Adresse mit einem 32-Bit-Speichersystem zu bilden, das 8 Mebibyte enthält.

Obwohl ich in diesem Artikel hauptsächlich die Grafik-Pipeline betrachten werde, kann ich der Versuchung nicht widerstehen, und deshalb werde ich kurz über das Audiosystem sprechen.


Das Soundkartendiagramm zeigt das Motorola 6809 (U4 mit einer Frequenz von 2 MHz), das Anweisungen von einem EPROM (U3) zur Steuerung von Musik und Soundeffekten empfängt.

Der FM-Synthesechip 2151 (3,5 MHz) von Yamaha erzeugt Musik direkt aus Anweisungen, die von 6809 empfangen wurden (Musik verwendet eine relativ kleine Bandbreite).

OKI6295 (1 MHz) ist für die Wiedergabe von digitalem Audio im ADPCM-Format verantwortlich (zum Beispiel das legendäre „Boomshakalaka“ [11] Tim Kittsrow).

Beachten Sie, dass auf der Hauptplatine dasselbe blaue 512-KByte-EPROM 32a / 8d in einem 16-Bit-System mit doppelter Verschachtelung von Adressen zum Speichern digitalisierter Stimmen verwendet wird, bei 8-Bit-Anweisungen jedoch Daten / Adressen von Motorola 6809 nicht verschachtelt sind.

Rahmenleben


Der gesamte NBA Jam-Bildschirm ist in einer 16-Bit-Palette indiziert. Farben werden im xRGB 1555-Format in einer 64-KByte-Palette gespeichert. Die Palette ist in 128 Blöcke (256 * 16 Bit) mit 512 Bytes unterteilt. Im EPROM gespeicherte Sprites sind als „GFX“ gekennzeichnet. Jedes Sprite verfügt über eine eigene Palette mit bis zu 256 x 16-Bit-Farben. Ein Sprite verwendet häufig einen ganzen Palettenblock, jedoch nie mehr als einen. Ein CRT-Signal wird unter Verwendung von RAMDAC an den Monitor übertragen, der für jedes Pixel den Index aus den Video-DRAM-Bänken liest und eine Farbsuche in der Palette durchführt.

Die Lebensdauer jedes Frames eines NBA Jam-Videos läuft wie folgt ab:

  1. Die Spielelogik besteht aus einem Strom von 16-Bit-Anweisungen, die von J12 / G12 an 34010 übertragen werden.
  2. 34010 liest Spielereingaben, berechnet den Spielstatus und zeichnet dann einen Bildschirm.
  3. Um auf dem Bildschirm zu zeichnen, findet 34010 zuerst einen nicht verwendeten Block in der Palette und schreibt dort die Sprite-Palette (Sprite-Paletten werden zusammen mit den Anweisungen 34010 in J12 / G12 gespeichert).
  4. 34010 sendet eine Anfrage an DMA2, die die Adresse und Größe des Sprites, den verwendeten 8-Bit-Palettenblock, das Abschneiden, die Skalierung, das Verfahren zum Verarbeiten transparenter Pixel usw. enthält.
  5. DMA2 liest 8-Bit-Sprite-Indizes vom J14-G23-GFX-ROM-Chip, kombiniert diesen Wert mit dem Index eines 8-Bit-Palettenblocks und schreibt einen 16-Bit-Index in Videobanken. DRAM2 kann als Blitter betrachtet werden, der 8-Bit-Werte aus dem GFX-EPROM liest und 16-Bit-Werte in Videobanken schreibt
  6. Die Schritte 3 bis 5 werden wiederholt, bis alle Anforderungen zum Zeichnen von Sprites abgeschlossen sind.
  7. Wenn es um die Bildschirmaktualisierung geht, wandelt RAMDAC die Daten in den Videobanken in ein Signal um, das ein CRT-Monitor verstehen kann. Damit die Bandbreite ausreicht, um den 16-Bit-Index in 16-Bit-RGB umzuwandeln, wird die Palette in einem extrem teuren und extrem schnellen SRAM gespeichert.


Eine interessante Tatsache: Die EPROM-Flash-Firmware ist kein so einfacher Vorgang. Bevor Sie auf den Chip schreiben, müssen Sie den gesamten Inhalt vollständig löschen.

Dazu muss der Chip mit UV-Licht bestrahlt werden. Zuerst müssen Sie den Aufkleber von der Oberseite des EPROM lösen, um das Diagramm zu öffnen. Dann wird das EPROM in ein spezielles Radiergummigerät gelegt, in dem sich eine UV-Lampe befindet.

Nach 20 Minuten ist das EPROM mit Nullen gefüllt und zur Aufnahme bereit.

MAME-Dokumentation


Nachdem ich die Ausrüstung herausgefunden hatte, wurde mir klar, welchen EPROM-Satz Sie an Michael Jordan schreiben konnten (die Palette ist in Code-EPROMs und die Indizes in GFX-EPROMs gespeichert). Ich wusste jedoch immer noch nicht genau, wo oder welches Format verwendet wurde.

Fehlende Dokumentation in MAME gefunden.

Falls Sie nicht wissen, wie dieser erstaunliche Emulator funktioniert, erkläre ich dies kurz. MAME basiert auf dem Konzept der "Treiber", die eine Nachahmung des Boards sind. Jeder Treiber besteht aus Komponenten, die (normalerweise) jeden Chip nachahmen. Im Fall von Midway T-Unit interessieren uns folgende Dateien:

  mame / includes / midtunit.h
 mame / src / mame / video / midtunit.cpp
 mame / src / mame / drivers / midtunit.cpp
 mame / src / mame / machine / midtunit.cpp
 CPU / tms34010 / tms34010.h 

Wenn Sie sich drivers / midtunit.cpp ansehen, werden Sie sehen, dass jeder Speicherchip Teil eines einzelnen 32-Bit-Adressraums ist. Aus dem Treiberquellcode ist ersichtlich, dass die Palette bei 0x01800000 beginnt, gfxrom bei 0x02000000 beginnt und der DMA2-Chip bei 0x01a80000 beginnt. Um dem Datenpfad zu folgen, müssen wir den C ++ - Funktionen folgen, die ausgeführt werden, wenn das Objekt der Lese- oder Schreiboperation die Speicheradresse ist.

void midtunit_state::main_map(address_map &map) { map.unmap_value_high(); map(0x00000000, 0x003fffff).rw(m_video, FUNC(midtunit_vram_r), FUNC(midtunit_vram_w)); map(0x01000000, 0x013fffff).ram(); map(0x01400000, 0x0141ffff).rw(FUNC(midtunit_cmos_r), FUNC(midtunit_cmos_w)).share("nvram"); map(0x01480000, 0x014fffff).w(FUNC(midtunit_cmos_enable_w)); map(0x01600000, 0x0160000f).portr("IN0"); map(0x01600010, 0x0160001f).portr("IN1"); map(0x01600020, 0x0160002f).portr("IN2"); map(0x01600030, 0x0160003f).portr("DSW"); map(0x01800000, 0x0187ffff).ram().w(m_palette, FUNC(write16)).share("palette"); map(0x01a80000, 0x01a800ff).rw(m_video, FUNC(midtunit_dma_r), FUNC(midtunit_dma_w)); map(0x01b00000, 0x01b0001f).w(m_video, FUNC(midtunit_control_w)); map(0x01d00000, 0x01d0001f).r(FUNC(midtunit_sound_state_r)); map(0x01d01020, 0x01d0103f).rw(FUNC(midtunit_sound_r), FUNC(midtunit_sound_w)); map(0x01d81060, 0x01d8107f).w("watchdog", FUNC(watchdog_timer_device::reset16_w)); map(0x01f00000, 0x01f0001f).w(m_video, FUNC(midtunit_control_w)); map(0x02000000, 0x07ffffff).r(m_video, FUNC(midtunit_gfxrom_r)).share("gfxrom"); map(0x1f800000, 0x1fffffff).rom().region("maincpu", 0); /* mirror used by MK*/ map(0xff800000, 0xffffffff).rom().region("maincpu", 0); } 

Am Ende derselben Datei "drivers / midtunit.cpp" sehen wir, wie der Inhalt der EPROMs in den RAM geladen wird. Bei den grafischen Ressourcen „gfxrom“ (die der Adresse 0x02000000 zugeordnet sind) können wir sehen, dass sie 8 Mebibyte Adressraum in den Chipblöcken mit vierfachem Adresswechsel umfassen. Beachten Sie, dass die Dateinamen dem Speicherort der Chips entsprechen (z. B. UJ12 / UG12). Der Satz dieser EPROM-Dateien in der Welt der Emulatoren ist besser als "ROM" bekannt.

 ROM_START( nbajamte ) ROM_REGION( 0x50000, "adpcm:cpu", 0 ) /* sound CPU*/ ROM_LOAD( "l1_nba_jam_tournament_u3_sound_rom.u3", 0x010000, 0x20000, NO_DUMP) ROM_RELOAD( 0x030000, 0x20000 ) ROM_REGION( 0x100000, "adpcm:oki", 0 ) /* ADPCM*/ ROM_LOAD( "l1_nba_jam_tournament_u12_sound_rom.u12", 0x000000, 0x80000, NO_DUMP) ROM_LOAD( "l1_nba_jam_tournament_u13_sound_rom.u13", 0x080000, 0x80000, NO_DUMP) ROM_REGION16_LE( 0x100000, "maincpu", 0 ) /* 34010 code*/ ROM_LOAD16_BYTE( "l4_nba_jam_tournament_game_rom_uj12.uj12", 0x00000, 0x80000, NO_DUMP) ROM_LOAD16_BYTE( "l4_nba_jam_tournament_game_rom_ug12.ug12", 0x00001, 0x80000, NO_DUMP) ROM_REGION( 0xc00000, "gfxrom", 0 ) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_ug14.ug14", 0x000000, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_uj14.uj14", 0x000001, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_ug19.ug19", 0x000002, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_uj19.uj19", 0x000003, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_ug16.ug16", 0x200000, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_uj16.uj16", 0x200001, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_ug20.ug20", 0x200002, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_uj20.uj20", 0x200003, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_ug17.ug17", 0x400000, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_uj17.uj17", 0x400001, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_ug22.ug22", 0x400002, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_uj22.uj22", 0x400003, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_ug18.ug18", 0x600000, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_uj18.uj18", 0x600001, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_ug23.ug23", 0x600002, 0x80000, NO_DUMP) ROM_LOAD32_BYTE( "l1_nba_jam_tournament_game_rom_uj23.uj23", 0x600003, 0x80000, NO_DUMP) ROM_END 

Eine interessante Tatsache: Im obigen Codebeispiel wurde der letzte Parameter der Funktion durch "NO_DUMP" ersetzt, damit modifizierte EPROMs geladen werden konnten. Diese Felder sind normalerweise [12] ein CRC / SHA1-Hash des Inhalts des EPROM. Auf diese Weise bestimmt MAME, welches Spiel zum ROM gehört, und zeigt an, dass eines der ROMs im Set fehlt oder beschädigt ist.

Herz-Video-Engine: DMA2


Der Schlüssel zum Verständnis des Grafikformats ist die Funktion, die das Schreiben / Lesen von DMA in 256 DMA2-Registern verarbeitet, die sich an Adressen von 0x01a80000 bis 0x01a800ff befinden. Die ganze harte Arbeit des Reverse Engineering wurde bereits von den MAME-Entwicklern geleistet. Sie haben sich sogar die Zeit genommen, das Befehlsformat hervorragend zu dokumentieren.

  DMA-Register
  ------------------

   Registrieren |  Bit |  Bewerbung
  ---------- + - FEDCBA9876543210 - + ------------
      0 |  xxxxxxxx -------- |  Pixel, die am Anfang jeder Zeile verworfen wurden
            |  -------- xxxxxxxx |  Pixel, die am Ende jeder Zeile verworfen werden
      1 |  x --------------- |  Aufzeichnung aktivieren (oder löschen, wenn Null)
            |  -421 ------------ |  bpp-Bilder (0 = 8)
            |  ---- 84 ---------- |  Passgröße nach = (1 << x)
            |  ------ 21 -------- |  Durchlaufgröße bis = (1 << x)
            |  -------- 8 ------- |  Aktivieren Sie das Überspringen vor / nach
            |  --------- 4 ------ |  Abschneiden aktivieren
            |  ---------- 2 ----- |  y Spiegelung
            |  ----------- 1 ---- |  x Spiegelung
            |  ------------ 8 --- |  Nicht-Null-Pixel als Farben übertragen
            |  ------------- 4-- |  Übertragung von null Pixeln als Farben
            |  -------------- 2- |  Pixelübertragung ungleich Null
            |  --------------- 1 |  Null-Pixel-Übertragung
      2 |  xxxxxxxxxxxxxxxxx |  Quelladresse niedriges Wort
      3 |  xxxxxxxxxxxxxxxxx |  hohe Wortquellenadresse
      4 |  ------- xxxxxxxxx |  x Empfänger
      5 |  ------- xxxxxxxxx |  y Empfänger
      6 |  ------ xxxxxxxxxx |  Bildspalten
      7 |  ------ xxxxxxxxxx |  Bildlinien
      8 |  xxxxxxxxxxxxxxxxx |  Palette
      9 |  xxxxxxxxxxxxxxxxx |  farbe
     10 |  --- xxxxxxxxxxxxxx |  x Skala
     11 |  --- xxxxxxxxxxxxxx |  y-Skala
     12 |  ------- xxxxxxxxx |  oben / links trimmen
     13 |  ------- xxxxxxxxx |  unten / rechts trimmen
     14 |  ---------------- |  der Test
     15 |  xxxxxxxx -------- |  Nullerkennungsbyte
            |  -------- 8 ------- |  zusätzliche Seite
            |  --------- 4 ------ |  Empfängergröße
            |  ---------- 2 ----- |  Auswahl der oberen / unteren oder linken / rechten Kante für Register 12/13 

Es gibt sogar eine Debugging-Funktion, mit der Sie die ursprünglichen Sprites beim Übertragen auf DMA2 speichern können (die Funktion wurde von einem langjährigen Teilnehmer des MAME-Projekts, Ryan Holtz [13], geschrieben ). Es war genug für mich, das Spiel einfach zu spielen, damit alle Dateien mit Metadaten auf der Festplatte gespeichert wurden.

Es stellte sich heraus, dass Sprites aus einfachen Elementen einer 16-Bit-Palette ohne Komprimierung bestehen. Allerdings haben nicht alle Sprites die gleiche Anzahl von Farben. Einige Sprites verwenden nur 16 Farben mit 4-Bit-Farbindizes, während andere 256 Farben verwenden und 8-Bit-Farbindizes erfordern.

Patch


Jetzt kenne ich die Position und das Format der Sprites, sodass nur noch ein Minimum an Reverse Engineering durchgeführt werden muss. Ich habe ein kleines Programm über Golang geschrieben, um den Wechsel der EPROMs „Code“ und „gfx“ zu vermeiden. Durch das Eliminieren des Stripings ist es einfach, nach ASCII oder bekannten Werten zu suchen, da ich genau damit gearbeitet habe, wie RAM während der Programmausführung aussieht.

Danach können Sie leicht die Eigenschaften des Spielers finden. Es stellte sich heraus, dass sie alle nacheinander im 16-Bit-Big-Endian-Format ohne Vorzeichen gespeichert wurden (was sehr logisch ist, da 34010 mit Big-Endian funktioniert). Ich habe einen Patcher hinzugefügt, um die Spielerattribute zu ändern. Ich war nicht besonders an Basketball interessiert und gab SPEED = 9, 3 PTS = 9, DUNKS = 9, PASS = 9, POWER = 9, STEAL = 9, BLOCK = 9 und CLTCH = 9 ein.

Ich habe auch den Code zum Patchen des Spiels mit neuen Sprites mit der einzigen Einschränkung geschrieben - neue Sprites sollten die gleichen Größen haben wie austauschbare. Für das MJ-Foto habe ich ein 256-farbig indiziertes PNG erstellt (Sie können es hier sehen ).

Schließlich habe ich Code hinzugefügt, um das Zwischenformat in das verschachtelte Format zum Schreiben in einzelne EPROM-Dateien zu konvertieren.

Starte das Spiel



Nach dem Patchen des Inhalts des EPROM zeigte das NBAJam-Diagnosetool, dass der Inhalt einiger Chips als „BAD“ markiert ist. Ich habe dies erwartet, weil ich nur den Inhalt der EPROMs gepatcht habe, mich aber nicht darum gekümmert habe, nach dem CRC-Format und sogar nach ihrem Speicherort zu suchen.

GFX-EPROMs sind rot markiert (UG16 / UJ16, UG17 / UJ17, UG18 / UJ18, UG20 / UJ20, UG22 / UJ22 und UG23 / UJ23), da sie Bilder enthalten, die ich geändert habe. Die beiden EPROMs, in denen die Anweisungen (UG12 und UJ12) gespeichert sind, sind ebenfalls rot, da Paletten vorhanden sind.

Glücklicherweise werden CRCs hier nicht zum Schutz vor modifizierten Inhalten verwendet und nur zur Überprüfung der Integrität der Chips benötigt. Das Spiel hat begonnen. Und verdient!


Hasta La Vista, Baby!



Nachdem ich mit technischen Schwierigkeiten fertig war, verlor ich schnell das Interesse an dem Tool und hörte auf, es zu entwickeln. Ideen für diejenigen, die mit dem Code herumspielen möchten:

  • Zur Ostkonferenz hinzufügen Toronto Raptors.
  • Fügen Sie die Möglichkeit hinzu, Spielernamen zu ändern. Leider bestehen sie nicht aus ASCII, sondern sind vorgenerierte Bilder.

Buch über NBA Jam


Wenn Sie ein Fan des NBA Jam sind, dann hat Reyan Ali ein ganzes Buch über sie geschrieben [14] . Sie können es hier kaufen.

Quellcode


Wenn Sie einen Beitrag leisten möchten oder nur sehen möchten, wie alles funktioniert, wird die vollständige Quelle hier auf github hochgeladen.

Referenzen


[1] Quelle: 'NJA Jam' von Reyan Ali

[2] Quelle: 'NJA Jam' von Reyan Ali

[3] Quelle: 'NJA Jam' von Reyan Ali

[4] Quelle: Mortal Kombat 1 hinter den Kulissen

[5] Quelle: 'NJA Jam' von Reyan Ali

[6] Quelle: 4: 3 gegenüber quadratischen Pixeln

[7] Kommentar: Leider ist die Ära einer solch hervorragenden Dokumentation längst vorbei

[8] Quelle: Startbildschirm von Mame NBA Jam

[9] Quelle: Befehlssatz TMS34010

[10] Quelle: T34010 Benutzerhandbuch

[11] Quelle: NBA Jam - BoomShakaLaka-Video

[12] Quelle: MAME T-Unit driver.cpp

[13] Quelle: Commit 'midtunit.cpp: Optionaler DMA-Blitter-Viewer hinzugefügt'

[14] Quelle: "NBA JAM Book" von Reyan Ali

Source: https://habr.com/ru/post/de473660/


All Articles