Wäre es nicht schön, wenn man sein fertiges Maschinen-Programm (.prg) direkt von Basic aus starten könnte, ohne sich die Einsprungadresse merken zu müssen? Sprich, wir müssen uns nicht mehr den „SYS {Adresse}“-Befehl merken sondern starten das Programm einfach mit RUN. Nachfolgend eine kurze Erklärung, wie das umgesetzt werden kann.
Wenn unser Programm den notwendigen SYS-Befehl zu Beginn des Quellcodes in den Basic-Speicher schreibt, reicht ein RUN aus um an die richtige Stelle im Speicher zu springen und das eigentliche Programm auszuführen. Schauen wir uns dazu an, wie der Basic-Speicher ab Adresse 2048 ($0800) aufgebaut ist und funktioniert. Wir stellen uns dazu vor, dass wir folgende Basic-Zeile eingegeben haben:
10 POKE 53280,1
Führt man dieses kleine Basic-Programm mit dem Befehl RUN aus, so interpretiert der Basic-Interpreter die Zeile Zeichen für Zeichen und startet danach den passenden Maschinencode, in diesem Fall zum Ändern der Rahmenfarbe (boardercolor) in Adresse 53280 ($D020) auf den Wert 1. Mit einer einfachen FOR-Schleife lesen wir nun den Inhalt des Basic-Speichers aus, ohne dass wir dafür einen Maschinensprache-Monitor einsetzen müssen:
FOR A=1 TO 16: PRINT PEEK(2048+A): NEXT A
Wie die Zahl 16 unserer FOR-Schleife zu bestimmen ist, erkläre ich weiter unten. Das Ergebnis wird so aussehen:
Wir müssen nun verstehen, welche Bedeutung die Zeichen 15 bis 0 im Basic-Speicher haben.
Adresse | Zeichen | Bedeutung | Kommentar | |
2049 ($0801) | 15 ($0f) | $080f | Zeiger auf nächste Zeile, low-order byte | |
2050 ($0802) | 8 ($08) | $080f | Zeiger auf nächste Zeile, high-order byte | |
2051 ($0803) | 10 ($0a) | 0010 | Zeilennummer, low-order byte | |
2052 ($0804) | 0 ($00) | 0010 | Zeilennummer, high-order byte | |
2053 ($0805) | 151 ($97) | POKE | Token-Code für den Befehl „POKE“ | |
2054 ($0806) | 32 ($20) | SPACE | Leerzeichen | |
2055 ($0807) | 53 ($35) | „5“ | PETSCII für das Zeichen „5“ | |
2056 ($0808) | 51 ($33) | „3“ | „ | |
2057 ($0809) | 50 ($32) | „2“ | „ | |
2058 ($080a) | 56 ($38) | „8“ | „ | |
2059 ($080b) | 48 ($30) | „0“ | „ | |
2060 ($080c) | 44 ($2c) | „,“ | „ | |
2061 ($080d) | 49 ($31) | „1“ | PETSCII für das Zeichen „1“ | |
2062 ($080e) | 0 ($00) | Term | Terminierung der Basic-Zeile | |
2063 ($080f) | 0 ($00) | End | Ende des Basic-Programms, Byte 1 | |
2064 ($0810) | 0 ($00) | End | Ende des Basic-Programms, Byte 2 |
Der Basic-Speicher startet also mit einem Zeiger auf die nächste Basic-Zeile ($080f), die in unserem Beispiel aus zwei terminierenden Nullen ($00) besteht. Die Zeilennummer ist wie die Endadresse eine 16-bit-Zahl und ist deshalb auf dem C64 in Low-Byte, High-Byte getrennt in zwei 8-bit-Adressen abgespeichert.
An Adresse $0805 folgt der eigentliche Basic-Befehl „POKE“, der vom C64 als ein 1-byte-Token abgespeichert wird, in diesem Fall $97. danach folgen die ASCII-Codes (PETSCII) unserer übrigen Zeichen. Token-Codes und PETSCII-Codes lassen sich einfach in Tabellen nachlesen.
Nun zu unserem echten Anwendungsfall. Unser Programm startet ab Adresse 4096 ($1000). Wir müssen also das Basic-Programm „10 SYS 4096“ in den Basic-Speicher schreiben und können anschließend mit RUN unser Programm ausführen lassen. Unser Assembler-Code dafür sieht so aus:
*= $0801
.byte $0f,$08,$0a,$00,$9e,$20
.byte $34,$30,$39,$36,$00,$00
.byte $00
*= $1000
; hier steht unser Programm
rts
Ab Adresse 2049 ($0801) schreiben wir 13 Bytes in den Basic-Speicher, die unserer Zeile „10 SYS 4096“ entsprechen, terminiert mit einem Zeilenende $00 sowie zwei Null-Bytes. In diesem Fall ist der Token-Code für den Befehl „SYS“ 158 ($9e). $080f ist der Zeiger auf die Endadresse im Speicher, hier die erste Adresse der ersten Doppelnull.
Wenn wir dieses Assembler-Programm kompiliert als .prg Datei gespeichert haben, können wir anschließend das Programm laden und einfach mit RUN ausführen.