C 64
Basic erweitert

Commodore-Basic erweitert

Mit dem hier vorgestellten Maschinenprogramm wird der Basic-Befehlssatz des VC 20 oder des C 64 um sechs Befehle erweitert.

Die 6 Befehle lauten, in die Basic-Schreibweise übersetzt, GOTO N, GOSUB N, RESTORE N, READ D,A, READ N,D,A, und POP. Einen kleinen Nachteil muß man dabei allerdings in Kauf nehmen, denn diese Routinen kann man nur dem SYS-Befehl ansprechen. Es ist also nicht möglich, eine der Routinen direkt mit einem Basic-Befehlswort aufzurufen.

Der Zugriff auf diese Befehle kann insbesondere dann von großem Nutzen sein, wenn man Programme von anderen Computern umschreiben will, die diese Befehle benutzen.

Will man einen der neuen Befehle in einem Basic-Programm benutzen, muß man nur das Basic-Wort in der oben aufgeführten Liste durch ein »SYS (Adresse)« ersetzen. Die Parameter hinter dem Befehl werden genauso hinter den SYS-Befehl geschrieben, als ob sie hinter dem Basic-Befehl stehen würden.

Bei den nun folgenden Erläuterungen wird davon ausgegangen, daß sich das Maschinenprogramm im Kassettenpuffer ab Adresse 828 befindet. Wurde eine andere Anfangsadresse gewählt, ändern sich auch die Adressen der einzelnen Routinen.

Der Befehl GOTO N sieht in der Form, wie er im Programm verwendet werden muß, so aus: SYS(828)N; also doch noch recht einfach. Dieser Befehl bewirkt, daß man direkt zu einer beliebigen Zeile springen kann, deren Zeilenummer »N« vorher berechnet wurde. Nun zur Syntax. Bei diesem, wie auch bei allen folgenden Befehlen ist darauf zu achten, daß die Startadresse der Routine nach dem SYS-Befehl, (hier 828) in Klammern steht, um Sie von der darauf folgenden Parameterliste zu trennen und so als Adresse kenntlich zu machen. »N« repräsentiert hier, wie auch bei den weiter folgenden Befehlen, eine beliebige gültige numerische Variable, eine Zahl oder einen numerischen Ausdruck. Für »N« ist also beispielsweise auch der Ausdruck »INT(RND( 1) * 20) * 10 +100« erlaubt. Der Ausdruck muß nur einen Ganzzahlenwert zum Ergebnis haben. Noch zu bemerken ist, daß zwischen der geschlossenen Klammer der Adresse und der ersten Variablen oder dem Ausdruck kein Komma stehen darf. Das Komma wirkt wie bei PRINT oder READ wie ein Trennzeichen. Da dieser Befehl aber nur eine Variable oder einen Ausdruck enthalten darf, würde das zu einem »SYNTAX ERROR« führen. Dies gilt auch bei allen folgenden Befehlen. Ist die berechnete Zeilennummer nicht im Programm enthalten, erfolg die Fehlermeldung »UNDEF’D STATEMENT ERROR«.

Für den Befehl GOSUB N gilt das gleiche, was auch zu GOTO N gesagt wurde, unter Berücksichtigung der Tatsache, daß es sich hier um einen Unterprogramm-Aufruf handelt Mit diesem Befehl kann man also zu einer vorher berechneten Unterprogramm-Adresse springen (SYS(834) N).

RESTORE N ermöglicht es, den DATA-Zeiger auf eine bestimmte Zeile zu setzen. SYS(866)100 beispielsweise setzt den DATA-Zeiger auf das erste Datum der Zeile 100. Mit einem anschließenden READ-Befehl kann man dann gezielt auf diesen Datensatz zugreifen. Ist die angegebene Zeilennummer im Programm nicht vorhanden, erfolgt ein »UNDEF’D STATEMENT ERROR«.

READ D, A (SYS(890) d, a) liest direkt den D-ten DATA-Wert in die Variable A. Anstelle von »A« kann sowohl eine numerische als auch eine Stringvariable stehen. »SYS(890) 5, A$« entspricht beispielsweise der Basic-Befehlsfolge »FOR I = 1 TO 5 : READ A$ : NEXT«. Auf etwas ist noch zu achten: Will man numerische Daten mit einer numerischen Variable lesen, darf keiner der vorhergehenden DATA-Werte ein String sein. Dies ist programmtechnisch bedingt und liegt daran, daß in Wirklichkeit die entsprechende Anzahl von READ-Befehlen durchgeführt wird. Ein direktes Lesen nur des gesuchten Datums würde das Maschinen-Programm dreimal so lang machen. Sollte es doch einmal vorkommen, daß man versucht, in eine numerische Variable einen String einzulesen, wird ein »SYNTAX ERROR« mit Angabe der entsprechenden DATA-Zeile ausgegeben. Am besten benutzt man immer Stringvariable zum Lesen.

Dann wäre da noch der Befehl »READ N,D,A« (entspricht SYS(927)N,D,A). Dieser Befehl ist eine Mischung des RESTORE- und des READ-Befehls.

SYS(927)N,D,A liest aus der Zeile N das D-te Datum dieser Zeile in die Variable »A«. Ist D größer als die Anzahl der Daten in dieser Zeile, wird in der nächsten DATA-Zeile weitergelesen.

Nun noch zu »POP« (SYS(937)). Springt man aus einem Unterprogramm anstatt mit »RETURN« mit einem direkten Sprungbefehl in die nächsthöhere Ebene (zum Beispiel ins Hauptprogramm) zurück, dann kann mit SYS(937) die letzte gespeicherte Rücksprungadresse im Stack, die dann nicht mehr gebraucht wird, gelöscht werden. Damit wird verhindert, daß der Stack überläuft, da er maximal 23 Rücksprungadressen speichern kann. Außerdem wird ein korrekter Programmablauf sichergestellt, wenn man »hart« aus einem Unterprogramm herausspringt, beispielsweise, um in eine Fehlerbehandlungsroutine zu gehen.

Tips für die Eingabe

Als erstes sollte man nur den Basic-Lader (Listing 1 oder 2, je nach Computer) ab Zeile 10000 eintippen und dann, ohne ihn zu starten, sicherheitshalber erst mal abspeichern. Dann gibt man noch eine Testzeile ein, und zwar: »10 GOSUB 10000:PRINT"Prüfsumme=";AS:END« und startet das Ganze mit »RUN«. Ergibt sich für die Prüfsumme ein anderer Wert als 18 413 für den VC 20 oder 17 901 für den C64, dann hat man sich irgendwo vertippt und die Datazeilen sind mit dem abgedruckten Listing noch einmal zu vergleichen. Eine genaue Kontrolle sollte man sowieso vornehmen, da sich durch Zufall eine richtige Prüfsumme ergeben kann, obwohl vielleicht zwei Werte falsch sind, die sich aber gegeneinander aufheben.

Sind alle Datazeilen fehlerfrei, löscht man Zeile 10 und speichert das Programm noch einmal ab, damit man den Basic-Lader an jedes gewünschte Programm anhängen kann.

Ist dies geschehen, kann man das Umrechnungsprogramm (Listing 3) eingeben. Es dient dazu, das Maschinenprogramm aus dem Kassettenpuffer an eine andere Stelle im Speicher zu verschieben. Der Kassettenpuffer hat ja den Nachteil, daß das Maschinenprogramm bei jeder Kassettenoperation zerstört wird. Außerdem können auch andere Befehlserweiterungen diesen Bereich benutzen, um Werte zwischenzuspeichern. Dadurch würde dann das Maschinenprogramm auch zerstört. Werden in einem Programm, das den Basic-Lader enthält, noch weitere DATA-Zeilen verwendet, so ist sicherzustellen, daß deren Zeilennummern größer sind als die höchste Zeilennummer des Basic-Laders, da sonst falsche Werte eingelesen würden.

Und noch ein Tip. Um die Adressen der Befehle nicht ändern zu müssen, wenn man das Maschinenprogramm in einen anderen Speicherbereich verlegt, verwendet man am besten Variablen, denen man am Anfang des Programms die Adresse zuweist. Dies könnte zum Beispiel so aussehen: »SM% = 828«.Für die einzelnen Befehle würde dann folgendes gelten:
GOTO N = SYS(SM%)
GOSUB N = SYS(SM% + 6)
RESTORE N = SYS(SM% + 38)
READ D,A = SYS(SM% + 62)
READ N,D,A = SYS(SM% + 99)
POP = SYS(SM% + 109)

Da alle diese Routinen weitgehend in das Betriebssystem des Computers eingebunden sind, werden bei Fehlern in der Ausführung die entsprechenden Systemfehlermeldungen ausgegeben.

(Wolfgang Thauer / ev)
1 rem basic-lader vc 20
2 rem
3 rem wolfgang thauer
4 rem am schiedsberg 45
5 rem 5205 st.augustin 2
6 rem
7 rem
10000 as=0:fori=828+abto(828+144)+ab:readap:pokei,ap:as=as+ap:nexti:return
10005 data 32
10010 data 198,3:rem**
10020 data 76,163,200,169,3,32,251,195,165,123,72,165,122,72,165,58,72
10030 data 165,57,72,169,141,72,32,121,0,32
10040 data 198,3:rem**
10050 data 32,163,200,76,174,199,32
10060 data 198,3:rem**
10070 data 32,19,198,176,3,76,227,200,165,95,233,1,133,65,165,96,233,0,133,66,96,32
10080 data 29,200,32
10090 data 198,3:rem**
10100 data 165,20,133,253,166,21,232,134,254,32,253,206,32,6,204
10110 data 198,253,240,11,32,28,204,198,253,208,249,198,254,208,245,96,32
10120 data 98,3 :rem**
10130 data 32,253,206,32
10140 data 125,3:rem**
10150 data 96,169,255,133,74,32
10170 data 192,3:rem**
10180 data 154,201,141,240,3,76,224,200,104
10190 data 104,104,104,104,76,248,200,186,232,232,76,139,195,32,138,205,32,247,215,96
Listing 1. Basic-Lader »6 neue Befehle« (VC 20-Version)
1 rem basic lader c 64
2 rem
3 rem wolfgang thauer
4 rem am schiedsberg 45
5 rem 5205 st.augustin 2
6 rem
7 rem
10000 as=0:fori=828to(828+144)+ab:readap:pokei,ap:as=as+ap:nexti:return
10005 data 32
10010 data 198,3:rem**
10020 data 76,163,168,169,3,32,251,163,165,123,72,165,122,72,165,58,72
10030 data 165,57,72,169,141,72,32,121,0,32
10040 data 198,3:rem**
10050 data 32,163,168,76,174,167,32
10060 data 198,3:rem**
10070 data 32,19,166,176,3,76,227,168,165,95,233,1,133,65,165,96,233,0,133,66,96,32
10080 data 29,168,32
10090 data 198,3:rem**
10100 data 165,20,133,253,166,21,232,134,254,32,253,174,32,6,172
10110 data 198,253,240,11,32,28,172,198,253,208,249,198,254,208,245,96,32
10120 data 98,3:rem**
10130 data 32,253,174,32
10140 data 125,3:rem**
10150 data 96,169,255,133,74,32
10160 data 192,3:rem**
10170 data 154,201,141,240,3,76,224,168,104
10180 data 104,104,104,104,76,248,168,186,232,232,76,139,163,32,138,173,32,247,183,96
Listing 2. Basic-Lader »6 neue Befehle« (C 64-Version)
1 rem adressen umrechnen
2 rem
3 rem wolfgang thauer
4 rem am schiedsberg 45
5 rem 5205 st.augustin 2
6 rem
10 :
20 rem das machinenprogramm ist 145 bytes lang
30 :
40 rem zeichererklaerung
50 rem chr$(147)= clear home
60 rem chr$(17) = cursor down
70 rem chr$(18) = reverse on
80 rem chr$(13)  = return
90 :
100 :
110 :
120 printchr$(147)
130 print"dieses programm rechnet die absoluten adressen in der maschinenrou";
135 print"tine fuer einen anderen speicherbereich um und poket es";
140 print"lauffaehig in diesen speicherbereich."
150 printchr$(17);"gebe die gewuenschte  anfangsadresse ein,ab"
160 print"der das maschinenpro- gramm im speicher     liegen soll."
170 printchr$(17);"(die normale adresse   ist 828 = kassetten-  puffer)."
180 printchr$(17):inputaa
190 printchr$(17);"die anfangsadresse    ist ";aa
200 printchr$(17);"ist das richtig ?"
210 input"(j/n)";a$
220 ifa$<>"j"anda$<>"n"then210
230 ifa$="n"thenprint:goto150
240 ab=aa-828
245 printchr$(147);"bitte warten"
250 gosub700
260 ifaa=828then490
270 :
280 rem angabe der zu aendernden datazeilen
290 rem diese datazeilen sind im listing durch ein angehaengtes   ':rem**'gekennzeichnet
300 :
310 printchr$(17);"die zu aendernden datazeilen mit den ent-   sprechenden neuen"
320 print"werten lauten:"
330 print
340 ad=aa+138:gosub630
350 print"10010 data";al;",";ah
360 print"10040 data";al;",";ah
370 print"10060 data";al;",";ah
380 print"10090 data";al;",";ah
390 ad=aa+38:gosub630
400 print"10120 data";al;",";ah
410 ad=aa+65:gosub630
420 print"10140 data";al;",";ah
430 ad=aa+132:gosub630
440 print"10170 data";al;",";ah
450 printchr$(17);"weiter mit <return>"
460 geta$:ifa$=""then460
470 ifa$<>chr$(13)then460
480 :
490 print
500 print"die startadressen der routinen lauten:"
510 printchr$(17);"goto n  = sys(";aa;")";chr$(17)
520 print"gosub n = sys(";aa+6;")";chr$(17)
530 print"restore n=sys(";aa+38;")";chr$(17)
540 print"restore d,a$":print"        = sys(";aa+62;")";chr$(17)
550 print"restore n,d,a$":print"        = sys(";aa+99;")";chr$(17)
560 print"pop     = sys(";aa+109;")"
570 end
580 :
590 :
600 rem subroutine
610 rem berechnung von low- und high-byte einer adresse
620 :
630 ah=int(ad/256):al=ad-ah*256:return
640 :
650 :
670 rem subroutine
680 rem maschinenprogramm wird in speicher gepoket
690 :
700 gosub10000
710 ifas=18413thenprintchr$(17);"pruefsumme korrekt.":return
712 rem  18413 = pruefsumme fuer vc 20
714 rem fuer c 64 ist die pruefsumme 17901
720 printchr$(147);"pruefsumme =";as
730 printchr$(17);"pruefsummenfehler !"
740 print
750 print"moegliche fehler-     quellen :"
760 print
770 print"*eine date wurde ver-  gessen oder falsch    einge-tippt."
780 print
790 print"*sie haben die  data-  zeilen geaendert, um  das maschinenprogramm";
800 print" an einen anderen      speicherbereich anzu- passen."
810 print"*sie haben die falsche pruefsumme in zeile   710 eingesetzt."
820 end
830 :
960 :
970 rem unterprogramm
980 rem basiclader
990 :
10000 as=0:fori=828+abto(828+144)+ab:readap:pokei,ap:as=as+ap:nexti:return
10005 data 32
10010 data 198,3:rem**
10020 data 76,163,200,169,3,32,251,195,165,123,72,165,122,72,165,58,72
10030 data 165,57,72,169,141,72,32,121,0,32
10040 data 198,3:rem**
10050 data 32,163,200,76,174,199,32
10060 data 198,3:rem**
10070 data 32,19,198,176,3,76,227,200,165,95,233,1,133,65,165,96,233,0,133,66,96,32
10080 data 29,200,32
10090 data 198,3:rem**
10100 data 165,20,133,253,166,21,232,134,254,32,253,206,32,6,204
10110 data 198,253,240,11,32,28,204,198,253,208,249,198,254,208,245,96,32
10120 data 98,3 :rem**
10130 data 32,253,206,32
10140 data 125,3:rem**
10150 data 96,169,255,133,74,32
10170 data 192,3:rem**
10180 data 154,201,141,240,3,76,224,200,104
10190 data 104,104,104,104,76,248,200,186,232,232,76,139,195,32,138,205,32,247,215,96
Listing 3. Der Adressen-Umrechner
PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →