Der gläserne VC 20 – Teil 1
Der VC 20, schon etwas betagt und oft genug totgesagt, ist immer noch der meistverbreitete Computer seiner Klasse. Mit diesem Kurs wollen wir den legendären »Volkscomputer« endlich für alle Anwender vollkommen transparent machen.
Das Betriebssystem und das Basic des VC 20 sind äußerst flexibel gestaltet. Es gibt viele Möglichkeiten, das Bestehende zu ändern oder zu ergänzen. Diese Serie soll über die üblichen Tips und Tricks hinausgehen. Es werden also nicht nur POKEs, sondern auch weitergehende Maschinenprogramme wie zum Beispiel Funktionstastenabfrage oder die Definition neuer Basic-Befehle besprochen. Dieser erste Teil soll dabei bereits einen tieferen Einblick in das VC 20-System geben.
Wie Basic den Speicher verwaltet
Beginnen wir mit der Organisation des verfügbaren RAM durch den Basic-Interpreter.
Der Basicbeginn liegt bei Adresse 4096, das Ende bei Adresse 7680 (die Werte beziehen sich auf die Grundversion). Unmittelbar ab dem Basicbeginn wird das eigentliche Programm abgelegt. An dessen Ende beginnen die Variablen und Felder (Bild 1).

Der Variablenbereich wächst beim Anlegen neuer Variablen von unten nach oben. Nur das Stringende wandert in entgegenlaufender Richtung.
Die wichtigsten Zeiger, wie unter anderem Beginn und Ende von Basic und Variablen, sind in der Zeropage (Adresse 0 bis 256) abgelegt (Tabelle 1). Dabei ist die Reihenfolge Low-Byte/High-Byte zu beachten (Adresse = High-Byte * 256 + Low-Byte).
Um Speicherplatz für Maschinenprogramme oder Sonderzeichen zu schaffen, hat man prinzipiell zwei Möglichkeiten. Entweder man verschiebt den Basicanfang nach oben oder das Basicende nach unten. Letztere Alternative ist in den meisten Fällen günstiger.
Um zum Beispiel das Basicende von Adresse 7680 nach 7168 ( = 512 Byte) zu verlegen, gibt man ein:
POKE 55,0:POKE 56,28:CLR:REM (256 * 28 = 7168)
Bei anderen Speichergrößen verfährt man analog.
Der Befehl CLR ist nötig, damit sich verschiedene Hilfszeiger (Stringbeginn und Felderende) anpassen können.
Die andere Alternative der Platzbeschaffung ist etwas komplizierter. Sie wird nur bei erweitertem Speicher angewendet, um dort Sonderzeichen abzulegen. Um den Anfang des Programmspeichers von 4608 nach 7680 zu schieben, gibt man: POKE 44,30:POKE 30 * 256,0:NEW ein, denn 30 * 256 ist gerade 7680. Der zweite POKE-Befehl ist nötig, da am Anfang des Basicbereichs immer ein Nullbyte stehen muß.
Erste Hilfe — Basicprogramme retten nach NEW oder Reset
Schon oft wurden Verfahren beschrieben, um nach einem versehentlichen NEW das Basicprogramm wieder zurückzuholen. Doch wie funktionieren diese Verfahren? Um das zu verstehen, betrachten wir zunächst kurz den Aufbau eines Basicprogramms (Bild 2).

Am Kopf des Programms steht immer eine Null. Dann folgt die Adresse der nächsten Programmzeile (Koppeladresse) und die Zeilennummer. Danach kommt die eigentliche Programmzeile, die sich aus den sogenannten Tokens — den Basiccodenummern (Tabelle 2) — zusammensetzt. Am Ende dieser Zeile steht dann nochmals eine Null. Die nächste Zeile beginnt wieder mit einem Verbindungszeiger und der Zeilennummer. Das Programm wird mit drei Nullen abgeschlossen. Hieran schließen sich die Variablen an (vergleiche Bild 1).
Code (Dezimal) | Zeichen/ Befehl |
Code (Dezimal) | Zeichen/ Befehl | Code (Dezimal) | Zeichen/ Befehl |
Code (Dezimal) | Zeichen/ Befehl |
0 | Zeilenende | 66 | B | 133 | INPUT | 169 | STEP |
1-31 | Leer | 67 | C | 134 | DIM | 170 | + |
32 | Space | 68 | D | 135 | READ | 171 | — |
33 | ! | 69 | E | 136 | LET | 172 | * |
34 | " | 70 | F | 137 | GOTO | 173 | / |
35 | # | 71 | G | 138 | RUN | 174 | ↑ |
36 | $ |
72 | H | 139 | IF | 175 | AND |
37 | % | 73 | I | 140 | RESTORE | 176 | OR |
38 | & | 74 | J | 141 | GOSUB | 177 | > |
39 | ' | 75 | K | 142 | RETURN | 178 | = |
40 | ( | 76 | L | 143 | REM | 179 | < |
41 | ) | 77 | M | 144 | STOP | 180 | SGN |
42 | * | 78 | N | 145 | ON | 181 | INT |
43 | + | 79 | 0 | 146 | WAIT | 182 | ABS |
44 | , | 80 | P | 147 | LOAD | 183 | USR |
45 | - | 81 | Q | 148 | SAVE | 184 | FRE |
46 | . | 82 | R | 149 | VERIFY | 185 | POS |
47 | / | 83 | S | 150 | DEF | 186 | SQR |
48 | 0 | 84 | T | 151 | POKE | 187 | RND |
49 | 1 | 85 | U | 152 | PRINT# | 188 | LOG |
50 | 2 | 86 | V | 153 | 189 | EXP | |
51 | 3 | 87 | W | 154 | CONT | 190 | COS |
52 | 4 | 88 | X | 155 | LIST | 191 | SIN |
53 | 5 | 89 | Y | 156 | CLR | 192 | TAN |
54 | 6 | 90 | Z | 157 | CMD | 193 | ATN |
55 | 7 | 91 | [ | 158 | SYS | 194 | PEEK |
56 | 8 | 92 | £ | 159 | OPEN | 195 | LEN |
57 | 9 | 93 | ] | 160 | CLOSE | 196 | STR$ |
58 | : | 94 | ↑ | 161 | GET | 197 | VAL |
59 | ; | 95 | " | 162 | NEW | 198 | ASC |
60 | < | 96-127 | Leer | 163 | TAB( | 199 | CHR$ |
61 | = | 128 | END | 164 | TO | 200 | LEFT$ |
62 | > | 129 | FOR | 165 | FN | 201 | RIGHT$ |
63 | ? | 130 | NEXT | 166 | SPC( | 202 | MID$ |
64 | @ | 131 | DATA | 167 | THEN | 203-254 | Leer |
65 | A | 132 | INPUT | 168 | NOT | 255 |
Durch NEW oder durch einen RESET wird nicht das gesamte Programm, sondern nur der Variablenpointer (45/46) und die erste Koppeladresse gelöscht. Durch Rekonstruktion dieser beiden Zeiger kann das scheinbar verlorene Basicprogramm wieder benutzt werden.
Hier nun das »Rezept« zur Rekonstruktion:
• POKE (Basicanfang) + 2,1
Basicanfang in GV = 4097
+ 3K = 1025
+ 8K = 4609
• SYS 50483:POKE 46,PEEK(35): POKE 45, PEEK (781)+2:CLR
Unbedingt wichtig ist hier die Reihenfolge der Befehle! Ferner darf während der gesamten Prozedur keine Variable definiert werden, da diese das gelöschte Programm überschreiben würde.
Die Funktionsweise ist relativ einfach. Die Unterprogrammroutine (SYS 50483) bindet die Programmzeilen neu und stellt dabei den ersten Verbindungszeiger wieder her. Sie übergibt dann in den beiden Speicherstellen (35 und 781) die Adresse des Variablenbeginns —2.
Die CHRGET-Routine
Die Zeropage ist in Maschinensprache besonders einfach zu adressieren. Aus diesem Grund sind hier oft benötigte Daten abgelegt. Doch die Seite Null beheimatet auch ein Unterprogramm aus dem Basicinterpreter namens CHRGET (CHaRacter GET, Tabelle 3). Diese Routine hat die Aufgabe, aus dem Basictext einzelne Zeichen oder Befehle zur Auswertung bereitzustellen. Sie befindet sich gerade deshalb im RAM-Speicher, weil sie einen veränderbaren 2-Byte-Zeiger enthält. Da die Routine bei jeder Ausführung eines Basicbefehls benutzt wird, bietet sich hier eine gute Möglichkeit, in den Ablauf einzugreifen, um damit den Befehlsvorrat zu erweitern. CHRGET endet mit einem Sprung zurück zur Befehlsauswertung. Da die CHRGET-Routine im RAM liegt, kann an dieser Stelle die Routine in das Befehlsauswertungsprogramm des Benutzers umgeleitet werden. Dort wird zuerst das CHRGET-Unterprogramm zu Ende geführt.
Als Beispiel soll der bestehende Befehl π (Tokennummer 255) geändert werden. Das Befehlsauswertungsprogramm nach Tabelle 4 fragt ihn ab und verzweigt dann nach § 1C16, wo ein RESET ausgeführt wird (entspricht SYS 64802).
Man kann aber auch noch zusätzliche Parameter abfragen. Die nun folgende Änderung des π-Befehls steuert den Tongenerator, wobei drei Argumente und zwei Kommata geprüft werden müssen. Die Syntax des neuen Befehls ist aus Tabelle 5 ersichtlich.
Tongenerator Bereich 0-3 | , | Tonhöhe Bereich 0-255 | , | Lautstärke Bereich 0-15 |
Die Steuerungsroutine wird nun aus diesen vorgefertigten Modulen zusammengesetzt.
Zuerst der Baustein zum Abfragen von Argumenten (Tabelle 6).
Die ROM-Routine ($D79B) holt sich aus dem Basictext den numerischen Ausdruck und stellt ihn im X-Register zur Verfügung. Ist der Wert größer als 255, wird eine Fehlermeldung ausgegeben. Die Syntax unseres Befehls erlaubt aber nur Argumente zwischen 0 und 3. Daher wird nochmals eine Bereichsprüfung vorgenommen.
Als nächstes wird das Komma abgefragt (Tabelle 7). CHRGOT holt das laufende Zeichen aus dem Basictext und die Routine vergleicht es mit dem ASCII-Code für das Komma.
Man unterscheidet im übrigen zwischen CHRGET und CHRGOT. CHRGET ($0073) stellt den Zwei-Byte-Zeiger um eins hoch und lädt dann das neue Zeichen in das Akku. CHRGOT ($0079) hingegen holt lediglich das Zeichen.
Um den Soundbefehl zu komplettieren müssen noch die restlichen drei Module eingebaut werden. Wir wollen an dieser Stelle jedoch darauf verzichten, das im einzelnen auszuführen. Es sollte jetzt jedoch klar geworden sein, wie man eine Befehlserweiterung realisieren kann.
Für Assembler-Laien jetzt noch ein komplettes Befehlsprogramm. Es erweitert die bestehenden Kommandos um:
πO = Old (Rekonstruktion),
πS Tongenerator, Höhe, Lautstärke ≙ Soundbefehl (wie oben)
πS Tongenerator, 0 ≙ Tongenerator abschalten,
πP Horizontal, Vertikal, ”..” oder
πP Horizontal, Vertikal, String ≙ Druck an einer spezifizierten Bildschirmstelle.
Das Ladeprogramm (Listing 1) lädt die Maschinenroutine automatisch in den richtigen Speicherbereich (abhängig von der Speichergröße) und gibt dann die Startadresse an. Zur Referenz ist das vollständige Assemblerprogramm als Listing 2 abgedruckt.
Die neuen Befehle können sowohl im Direktmodus, als auch im Programm verwendet werden. Benutzt man sie im Programm, so ist zu beachten, daß sie nie direkt nach der Zeilennummer stehen dürfen. So muß zum Beispiel der Befehl
πS 1,240,15 mit Doppelpunkt im Programm stehen:
10 : πS1,240,15 oder
10 PRINT A$: πS1,240,15
Listschutz für Basicprogramme:
Es wurden bereits mehrfach Methoden veröffentlicht, mit denen man Programme vor unbefugtem Kopieren schützen kann. Hierbei gibt es mehrere Alternativen:
- Man verändert die Koppeladressen so, daß das Programm nicht listfähig ist, es jedoch normal mit RUN bedient werden kann.
- Man verändert den LIST-Vektor mit POKE 774,34:POKE 755,253. Bei einem Listversuch löst dieser Vektor einen RESET aus und das Programm ist weg.
Diese und andere Schutzmaßnahmen haben den Nachteil, daß sie von »Hackern« innerhalb kurzer Zeit umgangen werden können. Es gibt zwar keinen hundertprozentigen Programmschutz, jedoch bietet die nachfolgend beschriebene Methode eine große Sicherheit. Bei diesem Verfahren läßt die Änderung eines Kernalvektors (Tastatureingabe 804/805) das Basicprogramm mit Hilfe einer Maschinenroutine nach Abschluß des Ladevorgangs automatisch starten.
Zunächst zur Verfahrensweise beim Autostart:
Schritt 1:
Eingabe des Ladeprogramms (Listing 3)
Schritt 2:
Programm und Prüfsumme testen (Achtung es zerstört sich selbst mit NEW) und abspeichern
Schritt 3:
POKE 44,A: POKE A*256,0 : NEW (A = 17 für die Grundversion; A = 19 bei Erweiterung ab 8 KByte; A = 5 Erweiterung + 3 KByte
Schritt 4:
Ladeprogramm laden und starten
Schritt 5:
Eigenes Programm nachladen
Schritt 6:
POKE 43,24 : POKE 44,3
Schritt 7:
POKE 792,91 : POKE 793,255 : POKE 808,114
Schritt 8:
POKE 804,0 : POKE 805,X : SAVE "…”,1,1
X wird vom Ladeprogramm angegeben (X = 16 in Grundversion; X = 18 bei Erweiterung ab 8 KByte; X = 4 bei Erweiterung von 3 KByte). Die Befehle von Schritt 8 müssen unbedingt in einer Zeile stehen, sonst stürzt der Computer ab.
Das Ladeprogramm (oder einfacher der Lader) übernimmt die Abspeicherung des Maschinenprogramms, wobei er sich nach einer eventuell vorhandenen Speichererweiterung richtet.
Nun zur Bedienung:
Nach der Prüfsummenkontrolle ist die Speichergröße per Tastendruck einzugeben. Dadurch wird überprüft, ob man vor dem Laden POKE 44,A eingegeben hat, denn sonst würde sich das Programm selbst überschreiben. Dann wird nach der Anfangsadresse für das zu schützende Basicprogramm gefragt. Der Lader gibt der Einfachheit halber bereits die entsprechende Adresse vor. Man kann sie aber auch ändern, wodurch das Auffinden des Basicprogramms nach einem RESET erschwert wird.
Zur Erklärung betrachten wir Bild 3. Es zeigt die Speicheraufteilung beim Autostart, bezogen auf die Grundversion. Das eigentliche Maschinenprogramm benötigt 95 Byte. Es liegt direkt am Basicbeginn (Adresse 4096). Dann folgt eine Lücke. Sie ist, wie bereits gesagt, nicht unbedingt nötig, aber sie erschwert etwaigen Raubkopierern das Auffinden des Programms. Hieran schließt sich das eigentliche Basicprogramm an.

So funktioniert der Autostart
Durch POKE 43,24 : POKE 44,3 wird der gesamte Bereich zwischen Adresse 792 und Programmende aufgezeichnet, wodurch sich die Ladezeit etwas erhöht.
Wie wir bereits gesehen haben, ist das Betriebssystem des VC 20 dank seiner Vektoren äußerst flexibel. Für den Programmschutz machen wir uns dabei folgende Zeiger zu Nutze:
- NMI-Vektor, Adresse 792,793: Dieser Vektor stellt die Verbindung zwischen RESTORE-Taste und NMI-Routine her. Durch die Änderung (siehe Schritt 7) wird die RESTORE-Routine einfach übersprungen; die Taste ist quasi abgeschaltet.
- STOP-Vektor, Adresse 808,809: Auch hier wird die bestehende Routine übersprungen.
Da dieser Vektorenbereich mit abgespeichert wird, ist, nachdem der Computer "FOUND" anzeigt, ein Stoppen des Computers nicht mehr möglich. - INPUT-Vektor, Adresse 804,805: Dieser Zeiger ist der eigentliche Dreh- und Angelpunkt des Autostarts. Er ist für die Tastatureingabe verantwortlich. Da er ständig durchlaufen wird, bewirkt POKE 804,0 : POKE 805,16 (bei geladener Autostartroutine) in der Grundversion einen Start des Basicprogramms. Ändert man den Zeiger hingegen vor dem Abspeichervorgang (wie in Schritt 8) geschieht vorläufig nichts, denn dann wird die Tastatur ja nicht benutzt.
Somit eignet sich dieser Vektor besonders gut für unseren Zweck. Denn solange sich der Computer mit dem Laden beschäftigt, ist die Tastatur »ruhig gestellt«. Der Zeiger wird so lange nicht benötigt, bis das Programm komplett geladen ist. Ist dies geschehen, springt das Betriebssystem über den INPUT-Vektor in die Autostartroutine, die ihrerseits (nach dem Rückstellen des Zeigers auf seinen ursprünglichen Wert) über RUN das Basicprogramm startet.
Damit auch alles wieder in den richtigen Speicherbereich geladen wird, dafür sorgt die Sekundäradresse bei SAVE " ",1,1.
Das Programm kann anschließend ganz normal mit LOAD geladen werden. Zum Schluß noch zwei Tips:
- Wer besonders clever ist, der vernichtet alle »Spuren«, indem er die Maschinenroutine nach ihrer Benutzung im Basicprogramm löscht:
5 FOR T = (Startadresse) TO (Startadresse) + 95 : POKE T, RND(0) + 255 : NEXT
(Startadresse = 4096 in der Grundversion; = 1024 bei Erweiterung von 3 KByte; = 4608 bei Erweiterung ab 8 KByte - Bei einer Erweiterung von 8 KByte liegt ja bekanntlich der Bildschirmspeicher im Bereich zwischen Adresse 4096 und 4607. Somit wird er ebenfalls mit abgespeichert.
Soweit die erste Folge unseres Kurses. Im zweiten Teil wollen wir uns etwas näher mit der Zeropage beschäftigen und unter anderem zeigen, wie man mehrere Basicprogramme gleichzeitig im Speicher halten kann.
100 rem ********************************** 110 rem **** **** 120 rem **** vc-20 befehlsauswertung **** 130 rem **** **** 140 rem **** 1984 by christoph sauer **** 150 rem **** **** 160 rem **** hubertusstrasse 14 **** 170 rem **** **** 180 rem **** 8000 muenchen 19 **** 190 rem **** **** 200 rem ********************************** 210 fort=0to215:readd:p=p+d:next:ifp<>23243thenprint"{down}{down}fehler !!":end 220 poke55,0:poke56,peek(56)-1:clr:a=peek(56) 230 restore:fort=a*256toa*256+215 240 readd 250 ifd=-1thend=a 260 poket,d 270 next 280 print"{clr}{down}{down}fertig. start mit":print"{down}sys"a*256+203 290 print"{down}{down}aktivierung mit 'a'" 300 geta$:ifa$=""then300 310 ifa$<>"a"thenend 320 sysa*256+203:~s1,240,15:fort=1to500:next:~s1,0 330 data201,255,240,018,201 340 data058,176,013,201,032 350 data208,003,076,115,000 360 data056,233,048,056,233 370 data208,096,032,115,000 380 data201,079,208,003,076 390 data049,-01,201,080,208 400 data003,076,075,-01,201 410 data083,208,003,076,134 420 data-01,076,008,207,160 430 data001,145,043,032,051 440 data197,165,034,024,105 450 data002,133,045,165,035 460 data105,000,133,046,032 470 data096,198,076,116,196 480 data032,155,215,224,023 490 data144,003,076,072,210 500 data134,250,032,121,000 510 data201,044,240,003,076 520 data008,207,032,155,215 530 data224,022,144,003,076 540 data072,210,032,121,000 550 data201,044,240,003,076 560 data008,207,024,138,168 570 data166,250,032,010,229 580 data032,115,000,032,160 590 data202,076,193,-01,032 600 data155,215,224,004,144 610 data003,076,072,210,134 620 data250,032,121,000,201 630 data044,240,003,076,008 640 data207,032,155,215,134 650 data251,240,023,032,121 660 data000,201,044,240,003 670 data076,008,207,032,155 680 data215,224,016,144,003 690 data076,072,210,142,014 700 data144,166,250,165,251 710 data157,010,144,165,157 720 data016,003,076,116,196 730 data076,121,000,169,076 740 data133,124,169,000,133 750 data125,169,-01,133,126 760 data096
******************** CHRGET FORTSETZUNG 1D00 CMP #$FF ; PI ? 1D02 BEQ $1D16 ; JA, DANN VERZWEIGEN 1D04 CMP #$3A ; SONST CHRGET ZU ENDE FUEHREN 1D06 BCS $1D15 1D08 CMP #$20 1D0A BNE $1D0F 1D0C JMP $0073 1D0F SEC 1D10 SBC #$30 1D12 SEC 1D13 SBC #$D0 1D15 RTS 1D16 JSR $0073 ; NAECHSTES ZEICHEN HOLEN 1D19 CMP #$4F ; 'O' ? 1D1B BNE $1D20 ; NEIN, DANN WEITER 1D1D JMP $1D31 ; SONST VERZWEIGEN 1D20 CMP #$50 ; 'P' ? 1D22 BNE $1D27 ; NEIN, DANN WEITER 1D24 JMP $1D4B ; SONST VERZWEIGEN 1D27 CMP #53 ; 'S' ? 1D29 BNE $1D2E ; NEIN, DANN FEHLER 1D2B JMP $1D86 ; SONST VERZWEIGEN 1D2E JMP $CF08 ; 'SYNTAX ERROR' AUSGEBEN ******************** O FUER REKONSTRUKTION 1D31 LDY #$01 1D33 STA ($2B),Y ; AM BASICANFANG ABSPEICHERN 1D35 JSR $C533 ; BASICZEILEN NEU BINDEN 1D38 LDA $22 1D3A CLC 1D3B ADC #$02 1D3D STA $2D 1D3F LDA $23 1D41 ADC #$00 1D43 STA $2E ; PROGRAMMENDE in DEZ 43,44 ABSPEICHERN 1D45 JSR $C660 ; CLR DURCHFUEHREN 1D48 JMP $C474 ; ZURUECK IN DEN DIREKTMODUS ******************** P FUER POSITIONSDRUCK 1D4B JSR $D79B ; PARAMETER HOLEN 1D4E CPX #$17 ; >23 ? 1D50 BCC $1D55 ; NEIN, DANN WEITER 1D52 JMP $D248 ; SONST FEHLERMELDUNG 1D55 STA $FA ; HORIZONTAL POSITION ABSPEICHERN 1D57 JSR $0079 ; LFD. ZEICHEN HOLEN 1D5A CMP #$2C ; KOMMA ? 1D5C BEQ $1D61 ; JA, DANN WEITER 1D5E JMP $CF08 ; SONST SYNTAX ERROR 1D61 JSR $D79B ; NAECHSTEN PARAMETER HOLEN 1D64 CPX #$16 ; >22 ? 1D66 BCC $1D6B ; NEIN, DANN WEITER 1D68 JMP $D248 ; SONST FEHLERMELDUNG 1D6B JSR $0079 ; NAECHSTES ZEICHEN HOLEN 1D6E CMP #$2C ; KOMMA ? 1D70 BEQ $1D75 ; JA, DANN WEITER 1D72 JMP $CF08 ; SONST SYNTAX ERROR 1D75 CLC ; VORBEREITUNG FUER DAS UNTERPROGRAMM 1D76 TXA CURSOR SETZEN 1D77 TAY 1D78 LDX $FA 1D7A JSR $E50A ; CURSOR AN POSITION (X/Y REG) 1D7D JSR $0073 ; NAECHSTES ZEICHEN HOLEN 1D80 JSR $CAA0 ; STRING AUSWERTEN UND AUSGEBEN 1D83 JMP $20C1 ; ROUTINE ABSCHLIESSEN ******************** S FUER SOUND 1D86 JSR $D79B ; PARAMETER HOLEN 1D89 CPX #$04 ; >4 ? 1D8B BCC $1D90 ; NEIN, DANN WEITER 1D8D JMP $D248 ; SONST FEHLERMELDUNG 1D90 STX $FA 1D92 JSR $0079 ; LFD. ZEICHEN HOLEN 1D95 CMP $#2C ; KOMMA ? 1D97 BEQ $1D9C ; JA, DANN VERZWEIGEN 1D99 JMP $CF08 ; SONST SYNTAX ERROR 1D9C JSR $D79B ; NAECHSTEN PARAMETER 1D9F STX $FB 1DA1 BEQ $ 1DBA ; BEI 0 TONGENERATOR ABSCHALTEN 1DA3 JSR $0079 ; NAECHSTES ZEICHEN HOLEN 1DA6 CMP #$2C ; KOMMA ? 1DA8 BEQ $1DAD ; JA, DANN WEITER 1DAA JMP $CF08 ; SONSR SYNTAX ERROR 1DAD JSR $D79B ; LETZTEN PARAMETER HOLEN 1DB0 CPX #$10 ; >16 ? 1DB2 BCC $1DB7 ; NEIN, DANN WEITER 1DB4 JMP $D248 ; SONST FEHLERMELDUNG 1DB7 STX $900E ; LAUTSTAERKE 1DBA LDX $FA 1DBC LDA $FB 1DBE STA $900A,X ; TONHOEHE IN DEN TONGENERATOR ******************** ROUTINE ABSCHLIESSEN 1DC1 LDA $9D ; FLAG DIREKTMODUS/PROGRAMM 1DC3 BPL $1DC8 ; FALL PROGRAMM DANN VERZWEIGEN 1DC5 JMP $C474 ; DIREKTMODUS: READY EINSPRUNG 1DC8 JMP $0079 ; ZUR NORMALEN BEFEHLSBEARBEITUNG ******************** INITIALISIERUNG 1DCB LDA #$4C 1DCD STA $7C 1DCF LDA #$00 1DD1 STA $7D 1DD3 LDA #$20 1DD5 STA $7E 1DD7 RTS
100 rem ************************* 110 rem **** **** 120 rem **** basic-autostart **** 130 rem **** **** 140 rem **** 1984 by c.sauer **** 150 rem **** **** 160 rem **** hubertusstr. 14 **** 170 rem **** **** 180 rem **** 8000 munchen 14 **** 190 rem **** **** 200 rem ************************* 210 fort=1to95:readd:p=p+d:next 220 ifp<>9552thenprint"fehler !!":end 230 print"{clr}{rght}{rght}{rght}autostart" 240 print"{rght}{rght}{rght}---------" 250 print"{down}{down}{down}bitte version angeben:" 260 print"{down} 1= gv" 270 print" 2= +3k" 280 print" 3= >8k ":f=0 290 geta$:ifa$=""then290 300 fort=1to3 310 ifa$=chr$(t+48)thenf=t 320 next 330 iff=0then290 340 fort=1to4-f:print"{up}";:next:print"{rvon}"f 350 onfgoto360,370,380 360 s=17:goto390 370 s=5:goto390 380 s=19:goto390 390 ad=peek(44) 400 ifad<>sthenprint"{down}{down}{down}{down}{down}vor dem laden":print"{down}poke 44,"s"eingeben !":end 410 v=(s-1)*256:restore 420 print"{down}{down}{down}anfangsadressse" 430 print"{down}fuer ihr prog. "v+96"{left}{left}{left}{left}{left}{left}{left}";:inputx 440 ifx<v+96thenprint"{down}nicht moeglich !!":goto420 450 x1=int(x/256):x2=x-x1*256 460 fori=vtov+94 470 readd:ifd=-1thend=s-1 480 ifd=-2thend=x1 490 ifd=-3thend=x2 500 pokei,d:next 510 print"{clr}{down}fertig, der poke fuer" 520 print"{down}805 ist"s-1". laden" 530 print"{down}sie jetzt das haupt-" 540 print"{down}programm nach." 550 pokex1*256+x2-1,0:poke43,x2:poke44,x1:new 560 data169,014,141,036,003 570 data169,242,141,037,003 580 data169,194,141,020,003 590 data169,219,141,024,003 600 data169,010,141,137,002 610 data169,112,141,040,003 620 data169,-03,133,043,169 630 data-02,133,044,169,000 640 data198,043,168,145,043 650 data230,043,160,001,152 660 data145,043,032,051,197 670 data165,034,024,105,002 680 data133,045,165,035,105 690 data000,133,046,032,096 700 data198,162,005,189,083 710 data-01,157,118,002,202 720 data208,247,240,004,082 730 data085,078,013,169,004 740 data133,198,076,116,196