Anpassung von Programmen für ZX Spectrum an TR-DOS mit modernen Mitteln. Teil 3

Wie wir im vorherigen Teil herausgefunden haben , können Maschinencodes des Spiels nicht direkt von der Diskette an die Zieladresse heruntergeladen werden. Wir werden sie an einen anderen Ort hochladen und nach dem Herunterladen bei Bedarf verschieben. Außerdem möchten wir einen Ein-Block-Bootloader erstellen, wenn sich sowohl der Bootloader als auch die geladenen Daten in derselben Basisdatei befinden. Ein solcher Lader kann nur in Maschinencodes geschrieben werden. Da wir eine Monoblock-Datei haben, muss der Lader in Maschinencodes in den Kommentaren zum Lader in BASIC platziert werden.


Diskette 5,25 "


Insgesamt ergibt sich folgender mehrstufiger:


  1. Von BASIC übertragen wir die Steuerung in Maschinencodes an das Programm.
  2. Das Programm in Maschinencodes überträgt den Bootloader vom BASIC-Bereich in einen anderen Bereich, der nicht von den Maschinencodes des Spiels betroffen ist, und überträgt die Kontrolle an diesen.
  3. Laden Sie das Boot-Image herunter und entpacken Sie es.
  4. Wir laden die Spielmaschinencodes in einen Bereich, der den Bereich der Systemvariablen nicht überlappt.
  5. Wir übertragen Maschinencodes an die Zieladresse.
  6. Wir übertragen die Kontrolle auf das Programm.

Die Entwicklung muss in der Mitte beginnen (Absatz 3). Tatsache ist, dass Sie zum Schreiben eines Programms zum Verschieben die Größe des zu verschiebenden Programms kennen müssen. Um Maschinencodes in ein Basisprogramm einzubetten, müssen Sie die Größe des Programms zum Verschieben kennen.


Monoblock-Bootloader (Teil der Maschinencodes)


Unter TR-DOS ähnelt das Laden von Daten aus einer Monoblock-Datei eher dem Herunterladen einer Datei ohne Header von einem Band, wenn Daten einer vorgegebenen Größe einfach von der aktuellen Position gelesen und in einen bestimmten Speicherbereich geladen werden. Dafür ist in TR-DOS die Routine unter #3D13 . Laden Sie zuerst das Bild herunter und entpacken Sie es:


 LD DE, ($5CF4) ;        LD BC, $0805 ;  B  -  (9)*, ;   —   #05 ( ) LD HL, $8000 ;    32768** CALL $3D13 ;   TR-DOS CALL $8000 ;    

& ast; - siehe Komprimierung des Boot-Images im vorherigen Teil;
& ast; & ast; - Der Entpacker ist umsetzbar, sodass Sie ihn überall herunterladen können.


Laden Sie in ähnlicher Weise die Spielautomatencodes herunter:


 LD DE, ($5CF4) ;        LD BC, $2505 ;  B  - , ;   —   #05 ( ) LD HL, $6000 ;    24576 CALL $3D13 ;   TR-DOS 

Zu diesem Zeitpunkt benötigen wir kein TR-DOS mehr. Wir können Maschinencodes mithilfe der LDIR Prozessoranweisung an die Zieladresse übertragen:


 LD HL, $6000 ;  (,      ) LD DE, $5B00 ;  LD BC, $2500 ;     (  data.bin) LDIR 

Nun, am Ende übertragen wir die Kontrolle auf die gleiche Weise wie im ursprünglichen Bootloader auf das Programm - indem wir den Stapelzeiger bewegen:


 LD SP, $5D7C RET 

Nachdem der Loader-Code fertig ist, müssen Sie ihn kompilieren, um seine Größe zu ermitteln, die wir weiter benötigen werden.


 $ pasmo tmp.asm tmp.bin $ wc -c tmp.bin 44 tmp.bin 

Bootloader-Übertragungsverfahren


Der Bootloader benötigt 44 Bytes. Jetzt müssen Sie die Prozedur zum Verschieben des Bootloaders aus den Kommentaren in BASIC (Punkt 2 der Liste am Anfang des Artikels) schreiben. Das Problem ist, dass die Adresse, an der sich der BASIC-Bereich befindet, je nach den an den Computer angeschlossenen Peripheriegeräten variieren kann. PROG zu bestimmen, wohin Sie Daten übertragen möchten, müssen Sie sich daher auf die PROG Systemvariable (wie im ursprünglichen Bootloader) oder konzentrieren zum Software-Zähler ( PC Prozessorregister).


Der Zugriff auf den Software-Zähler ist nicht so einfach - es gibt keine Prozessoranweisungen wie LD HL, PC . Ich habe die Lösung in Laser Compress ausspioniert und sie sieht folgendermaßen aus (nicht wirklich gezielte Verwendung der UNSTACK_Z Prozedur):


 LD DE, $00 ;     ,     , ;    .     ;    1 INC E ;  1  E,    ,    ;      .     1  CALL $1FC6 ;    ( ,  LD HL, PC) ADD HL, DE ;       LD DE, $F800 ;    LD BC, $002C ;  ,   (44 ) LDIR JP $F800 ;    ;      ;        

Zum Zeitpunkt des Aufrufs der ROM-Prozedur #1FC6 befindet sich die Adresse des nächsten Befehls ( ADD HL, DE ) auf dem Stapel. Er wird als Ergebnis des Aufrufs der Prozedur in HL aufgezeichnet. Um die Zahl zu bestimmen, die in der ersten Zeile geschrieben werden muss, müssen Sie dementsprechend bis zum Ende erneut ein Stück aus ADD HL, DE kompilieren und sehen, wie viel es kostet:


 $ pasmo tmp.asm tmp.bin $ wc -c tmp.bin 12 tmp.bin 

Es stellte sich heraus, 12 Bytes. Dementsprechend schreiben wir in der ersten Zeile 11 ( #0B ).


Als nächstes erstellen wir die Verschiebungsprozedur mit dem Loader (siehe die fertige Datei ), die verschoben und erneut kompiliert wird. Es sollte 56 Bytes ergeben.


Es sollte hier angemerkt werden, dass ich nach dem Schreiben dieses Stücks herausgefunden habe, dass es möglich war, anstatt die Länge des zu verschiebenden Programms zu berechnen, Beschriftungen zu verwenden und den Assembler es herausfinden zu lassen. Aber für die historische Gerechtigkeit lassen wir es so, wie es ist.


Monoblock Bootloader (Basisteil)


Nachdem wir die Größe des Bootloaders in Maschinencodes kennen, können wir den Bootloader in BASIC schreiben und alles in einer Monoblock-Datei sammeln.


Maschinencodes werden entweder in einem Kommentar oder am Ende einer Datei in eine Basisdatei eingebettet. Die zweite Option erschwert normalerweise das Studium der Datei und ist besser für den Schutz geeignet. Daher verwenden wir die erste Option. Die Kommentaroption lautet wie folgt:


  1 REM @#$%... 10 RANDOMIZE USR (PEEK 23635+256*PEEK 23636+5) 

23635 ( #5C53 ) ist die Adresse der zuvor erwähnten PROG Systemvariablen. 5 ist der Versatz des ersten Zeichens des Kommentars relativ zu PROG (2 Bytes sind die Zeilennummer, 2 Bytes sind die Länge der Zeile und 1 Byte ist der REM Operator). Wenn Sie vor den Maschinencodes weitere Kommentare hinzufügen möchten, z. B. Ihren Namen, Ihre Telefonnummer oder Ihre Postanschrift, muss der Wert 5 angepasst werden.


Wenn wir keine zusätzlichen Dienstprogramme zum Erstellen des Bootloaders verwenden würden, müssten wir nach REM beliebige Zeichen in einer Menge eingeben, die nicht geringer ist als die Länge des Programms in Maschinencodes, die wir anstelle des Kommentars einfügen möchten (in unserem Fall 56 Byte). Danach könnte man das Programm über LOAD "" CODE PEEK 23635+256*PEEK 23636+5 und die Datei speichern.


bas2tap kann den Vorgang jedoch erheblich vereinfachen. Es kann eine Basisdatei kompilieren und Binärdaten darin einbetten, wenn jedes Byte als hexadezimale Zahl in geschweiften Klammern dargestellt wird. Führen Sie dazu den kompilierten Bootloader über hexdump :


  $ hexdump -ve '1/1 "{%02x}"' loader.bin {11}{0b}{00}{1c}{cd}{c6}{1f}{19}{11}... 

hexdump setzen die hexdump Ausgabe an die Stelle des Kommentars in der ersten Zeile nach REM und kompilieren den Bootloader auf der -sboot ( -sboot ist der Name der Datei auf dem Band, -a10 ist die Zeilennummer des -a10 ):


 $ bas2tap -sboot -a10 boot.bas boot.tap 

Konvertieren Sie den Bootloader vom tap Format in hobeta durch das Zwischenformat 0 :


 $ tapto0 -f boot.tap $ 0tohob boot.000 

Erstellen einer einteiligen Datei


Zu diesem Zeitpunkt verfügen wir bereits über alle erforderlichen Dateien zum Erstellen eines Diskettenabbilds. Sie können ein Bild erstellen und alle erforderlichen Dateien darin kopieren:


 createtrd Pac-Man.trd hobeta2trd boot.\$$B Pac-Man.trd hobeta2trd screen.\$$C Pac-Man.trd hobeta2trd data.\$$C Pac-Man.trd 

Das resultierende Disketten-Image sollte bereits funktionieren. Sie können es im Emulator ausführen und überprüfen, aber das ist noch nicht alles. Da der Bootloader nachfolgende Dateien nicht namentlich, sondern basierend auf der Position des Laufwerkskopfs herunterlädt, funktioniert das Laden nur, wenn sich die Dateien nacheinander auf der Festplatte befinden. Dies muss behoben werden.


Das Prinzip lautet wie folgt: TR-DOS speichert redundante Informationen zur Dateigröße:


  1. Größe in Sektoren - wird verwendet, um Dateien auf einer Diskette abzulegen und zu kopieren.
  2. Größe in Bytes - wird zum Laden von Inhalten verwendet.

Normalerweise entsprechen diese Größen einander (256 Bytes pro Sektor), dies ist jedoch nicht erforderlich. Wir werden dies nutzen. Wenn Sie die Größe der Startdatei in Sektoren auf einen Wert ändern, der der Gesamtgröße aller Dateien entspricht, die wir herunterladen möchten, aber die Größe in Byte nicht ändern, kopiert TR-DOS alle Daten als eine große Datei, aber beim Booten wird nur die Basisdatei geladen Teil.


Auf einem realen Spektrum oder in einem Emulator kann die Nullspur mit Programmen wie Disk Doctor, z. B. Hex Disk Editor , bearbeitet werden:


Hex-Disk-Editor


Aber es kann einfacher gemacht werden: Ein trd-Image ist nichts anderes als eine Byte-Kopie aller Daten auf einer Diskette, sodass es in jedem Hex-Editor bearbeitet werden kann:


 $ hexdump -C Pac-Man.trd | head -4 00000000 62 6f 6f 74 20 20 20 20 42 d0 00 d0 00 01 00 01 |boot B.......| 00000010 73 63 72 65 65 6e 20 20 43 40 9c 14 07 08 01 01 |screen C@......| 00000020 64 61 74 61 20 20 20 20 43 00 5b 00 25 25 09 01 |data C.[.%%..| 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 

Wie Sie sehen können, befindet sich ganz am Anfang der Diskette (auf Spur Null) eine Dateizuordnungstabelle, in der Informationen zu jeder Datei 16 Byte benötigen. Die Größe in Sektoren wird in Byte mit dem Offset #0D (dritte Spalte rechts) gespeichert. Die Größe unserer Dateien beträgt die Sektoren #01 , #08 und #25 , was insgesamt #2E . Wir schreiben diesen Wert in das entsprechende Byte und löschen die restlichen Header, weil Sie werden nicht mehr benötigt:


 $ hexdump -C Pac-Man.trd | head -4 00000000 62 6f 6f 74 20 20 20 20 42 d0 00 d0 00 2E 00 01 |boot B.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 

Jetzt haben wir ein ausgewachsenes Disketten-Image. Es muss korrekt geladen und vollständig von Festplatte zu Festplatte kopiert werden. Es bleibt nur, um die Größe des Bildes zu reduzieren. Da ein trd-Image eine Bytekopie ist, werden immer 640 KB benötigt. In der Praxis ist es in den meisten Fällen bequemer, das scl-Format zu verwenden, das eher dem direkten Speichern von Dateidaten durch Hobeta ähnelt:


 $ trd2scl Pac-Man.trd Pac-Man.scl 

Nun sicher. Der Anpassungsprozess von Anfang bis Ende befindet sich im Projekt-Repository auf dem Github.


Werkzeuge:


  1. Pasmo ist ein Cross-Assembler für den Z80.
  2. bas2tap ist ein Cross-Compiler des Spectrum BASIC-Dialekts.
  3. trd2scl - trd-Bildkonverter zu scl.

Verwandte Links:


  1. "Anpassung von Programmen an das TR-DOS-System" von Nikolai Rodionov.
  2. "TR-DOS-Funktionen" aus dem Info Guide Magazine Nr. 1.
  3. "Die Struktur der TR-DOS-Diskette" aus dem Buch "TR-DOS für Profis und Amateure".
  4. Ein Verweis auf Systemvariablen und Spectrum ROM-Prozeduren .

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


All Articles