Tips und Tricks zum C 128
Wir haben Ihnen wieder neue und nützliche Tips, Tricks und Befehle zu bieten. Einen kleinen Kurs, OLD- und Spritebefehle sowie eine bessere INPUT-Routine.
Wieder einmal bieten wir Ihnen kleine Kniffe und Routinen, die Ihnen helfen werden, leichter mit Ihrem C 128 umzugehen.
Die Floppy 1571 und Originalprogramme
Es häufen sich die Anfragen von Lesern, wonach sich ein Teil ihrer gekauften Programme nicht in den Computer laden lassen. Diesen Lesern möchten wir nun Antwort geben. Die in den Floppylaufwerken VC 1541 und VC 1571 eingebauten DOS-Versionen (Floppy-Betriebssystem) sind untereinander leider nicht voll kompatibel. Originalprogramme sind jedoch in der Regel mit einem Kopierschutz versehen. Wenn dieser Schutz einer der besseren Art ist, so benutzt er das FloppyDOS für seine Routinen. Diese Routinen sind jedoch auf das DOS der VC 1541 zugeschnitten. Versucht der Kopierschutz nun, eine Routine in der VC 1571 auszuführen, die von der der VC 1541 abweicht, so kann die Kopierschutzabfrage nicht mehr richtig ausgeführt werden und das Programm läßt sich nicht weiter laden. Dagegen ist leider kein Kraut gewachsen. Hier sind die Benutzer von Raubkopien leider in der besseren Lage, da aus einem »gecrackten« Programm eben diese Abfragen entfernt wurden.
(dm)Die Variablen-Behandlung beim C 128
Das Format der Integer- und Gleitkommavariablen im C 128-Modus ist identisch mit denen im C 64-Modus. Nur bei den Stringvariablen hat sich das Format geändert. Es wird genau wie beim C 64 ein Stringdeskriptor angelegt, der die Adresse, an der der String tatsächlich abgelegt wurde und die Länge des Strings beinhaltet. An den Inhalt des Strings, also an seine ASCII-Zeichen, wird wie beim CBM 8032 ein Zwei-Byte-Zeiger angehängt. Dieser zeigt auf das Längenbyte im Stringdeskriptor. Zwar wird dadurch mehr Platz im Speicher benötigt, der Vorteil ist jedoch unschätzbar — die berühmt gefürchtete »Garbage Collection« schlägt nicht mehr in dem vom C 64 gewohnten Ausmaß zu. Es wird nur noch höchstens eine Sekunde zur »Stringmüllbeseitigung« gebraucht.
Die Variablenformate
In der folgenden Aufstellung steht »NAME« für den ASC-Wert eines Zeichens.
Integer-Variable
Die ganzzahligen Integer-Variablen werden in zwei Speicherzellen mit dem höchstwertigen Byte (MSB) an erster Stelle abgelegt. Es sind vorzeichenbehaftete Zahlen im Bereich von -32768 bis + 32767. Ist das höchstwertige Bit in einer Zahl gesetzt, so ist sie negativ. Im Commodore-Basic werden Integer-Variablen durch ein nachgestelltes Prozentzeichen dargestellt (zum Beispiel AA% oder Z%). Für die interne Kennzeichnung werden in den beiden Namen-Bytes die höchstwertigen Bits gesetzt.
Einzelvariable
Jede Einzelvariable belegt 7 Byte. Den Aufbau ersehen Sie aus Bild 1:
| Name 1 + 126 | Name 2 + 128 | MSB | LSB | 00 | 00 | 00 |
Felder
Ein Feld belegt 5 + 2 x Dimension + (Dimension n x Dimension (n-1) x Dimension (n-2)…) x 2 Byte.
Aufbau des Deskriptorblockes
- Byte Name + 128
- Byte Name + 128
- Byte Gesamtlänge Array (Lowbyte)
- Byte Gesamtlänge Array (Highbyte)
- Byte Anzahl der Dimensionen
- Byte Anzahl Elemente Dimension n, Low
- Byte Anzahl Elemente Dimension n, High
- Byte Anzahl Elemente Dimension n-1, Low
- Byte Anzahl Elemente Dimension n-1, High und so weiter für die restlichen Dimensionen.
Die Feldelemente werden direkt hinter dem Deskriptorblock in je 2 Byte (MSB-LSB) gespeichert (siehe Bild 2).
| MSB 1 | LSB 1 | MSB 2 | LSB 2 | etc. |
Bei mehrdimensionalen Feldern wird die letzte Dimension als erste angelegt.
Gleitkomma-Variable
Die Gleitkommazahlen sind in 5 Byte abgelegt. Im ersten Byte wird der Exponent gespeichert. Die Mantisse liegt in den folgenden 4 Byte als 32-Bit vorzeichenbehaftete Zahl. Die Gleitkommazahlen werden im Commodore-Basic nur durch die ASC-Werte der ersten beiden Zeichen dargestellt (zum Beispiel AA oder B).
Intern wird die Gleitkommazahl mit ihrem Namen in 2 Byte mit den ASC-Werten gekennzeichnet. Besteht der Name nur aus einem Zeichen, so lautet das zweite Byte Null.
Einzelvariable
Jede Einzelvariable belegt 7 Byte, wie Sie aus Bild 3 ersehen können.
| Name 1 | Name 2 + 128 | Exponent | Mantisse 32-Bit | |||
Felder
Ein Feld belegt 5 + 2 x Dimension + (Dimension n x Dimension (n-1) x Dimension (n-2)…) x 2 Byte.
Aufbau des Deskriptorblockes
- Byte Name + 128
- Byte Name + 128
- Byte Gesamtlänge Array (Lowbyte)
- Byte Gesamtlänge Array (Highbyte)
- Byte Anzahl der Dimensionen
- Byte Anzahl Elemente Dimension n, Low
- Byte Anzahl Elemente Dimension n, High
- Byte Anzahl Elemente Dimension n-1, Low
- Byte Anzahl Elemente Dimension n-1, High und so weiter für die restlichen Dimensionen.
Die Feldelemente werden direkt hinter dem Deskriptorblock in je fünf Speicherzellen gespeichert. (Siehe Bild 4)/
| Expon 1 | Mantisse 1 | Expon 2 | Mantisse 2 | usw. |
Bei mehrdimensionalen Feldern wird die letzte Dimension als erste angelegt.
Stringvariable
Stringvariablen werden in zwei Teilen gespeichert. In einem Deskriptorblock finden sichdie für die Verwaltung notwendigen Angaben. Im oberen RAM-Bereichwird der String selbst als Folge von ASC-Werten abgelegt. Im Deskriptorblock zeigt ein Zeiger auf eine Adresse im oberen RAM-Bereich, an der der String abgelegt ist. Jeder String wird von einem Zwei-Byte-Zeiger, der auf das Längen-Byte im Deskriptor zeigt, abgeschlossen.
Aufbau der ASCII-Zeichenformate
| Text-String | Zeiger | |
| Lowbyte | Highbyte | |
Im Commodore-Basic werden Stringvariable mit einem nachgestellten Dollarzeichen dargestellt (zum Beispiel A$ oder AB$). Intern werden Strings mit 2 Byte gekennzeichnet, wobei das höchstwertige Bit im zweiten Namen-Byte gesetzt ist. Besteht der Name nur aus einem Byte, so hat das zweite Namen-Byte den ASC-Wert 128.
Einzelvariable
Jede Einzelvariable belegt 7 Byte und im oberen RAM-Bereich zwei Byte + Länge des Strings. Der Aufbau wird aus Bild 5 ersichtlich.
| Name 1 | Name 2 + 128 | String-länge | Zeiger in RAM | 00 | 00 | |
| low | high | |||||
Felder
Jedes Feld belegt 5 + 2 x Dimension-Byte + (Dimension n x Dimension (n-1) x Dimension (n-2)…) x 3 und im oberen RAM-Bereich (Länge aller Strings + (2 x Anzahl aller Strings)). Es müssen nur Strings, deren Länge größer Null ist, berücksichtigt werden.
Aufbau des Deskriptorblockes
- Byte Name + 128
- Byte Name + 128
- Byte Gesamtlänge Array (Lowbyte)
- Byte Gesamtlänge Array (Highbyte)
- Byte Anzahl der Dimensionen
- Byte Anzahl Elemente Dimension n, Low
- Byte Anzahl Elemente Dimension n, High
- Byte Anzahl Elemente Dimension n-1, Low
- Byte Anzahl Elemente Dimension n-1, High und so weiter für die restlichen Dimensionen.
Die Feldelemente werden direkt hinter dem Deskriptorblock in je 3 Byte gespeichert (Bild 6).
| String 1 länge | Zeiger 1 low/high | String 2 länge | Zeiger 2 low/high | usw. |
Bei mehrdimensionalen Feldern wird die letzte Dimension als erste angelegt.
Funktionsvariable
Funktionen, die man mit der Anweisung
DEF FN name(var) = ausdr.
definiert, werden von Basic ebenfalls als Variable mit dem Namen »name« im RAM abgelegt.
Intern wird das höchstwertige Bit im ersten Namen-Byte gesetzt. Hat der Variablenname nur ein Zeichen, so ist das zweite Namen-Byte Null. Im Gegensatz zu den anderen Variablen gibt es aber hier keine Felder.
Jede Funktionsvariable belegt 7 Byte und im oberen RAM-Bereich 2 + Länge der Funktionsvariablen. Ansonsten entspricht die Ablage der einen einfachen Stringvariablen (Bild 7).
| Name 1 + 128 | Name 2 | String-länge | Zeiger in RAM | 00 | 00 | |
| low | high | |||||
Damit sind alle Variablentypen, die der C 128 kennt, dargestellt.
Im Normalzustand werden die Variablen in Bank 1 ab Adresse $0400 (dezimal 1024) aufwärts und die Inhalte der Strings und Funktionsvariablen ab Adresse $FEFF (dezimal 65279) abwärts gelegt.
In Tabelle 1 sind die Adressen einiger Zeiger aus der erweiterten Zeropage, die für die Verwaltung der Variablen wichtig sind, aufgeführt. Die aktuellen Adressen in der jeweiligen Bank kann man leicht nach folgender Formel berechnen:
Adresse = PEEK(Zeigeradresse) +
PEEK(Zeigeradresse +1) * 256
| Label | Adresse | Funktion | |
|---|---|---|---|
| Dez | Hex | ||
| TXTTAB | 45 | 002D | Zeiger auf Start BASIC B0 |
| VARTAB | 47 | 002F | Zeiger auf Start Variablen B1 |
| ARYTAB | 49 | 0031 | Zeiger auf Start Variablenfelder B1 |
| STREND | 51 | 0033 | Zeiger auf Ende der Variablenfelder + 1 B1 |
| FRETOP | 53 | 0035 | Zeiger auf Start String B1 |
| FRESPC | 55 | 0037 | Hilfszeiger für Stringverwaltung |
| MAXME1 | 57 | 0039 | Höchste verfügbare Variablenadresse B1 |
| BASTOP | 4624 | 1210 | Zeiger auf BASIC-Text Ende B0 |
| MAXME0 | 4626 | 1212 | Höchste verfügbare BASIC-Text-Adresse B0 |
Doch Achtung: Zum Nachschauen muß man dann noch die richtige Bank angeben.
(Michael Bauer/dm)Anti-C 128-POKE
Wer seinen C 128 häufiger im C 64-Modus benutzt, wird feststellen, daß dies der Commodore-Taste nicht unbedingt gut tut. Und das Umschalten mit GO 64 wird mit der Zeit auch lästig.
Gibt man im C 128-Modus folgende Zeile im Direkt- oder Programmodus ein, so springt der C 128 in den C 64-Modus und ist auch durch einen Reset nicht mehr in den C 128-Modus zu bringen.
BANK1:POKE 65528,77:POKE 65529,255:GO 64
Neue Befehle und Tri<ks für den C 128
Das Handbuch des Commodore 128 ist zwar etwas besser geraten als beim C 64, trotzdem lassen sich noch einige Fehler finden. So wurde beschrieben, daß die Umschaltung auf die DIN-Tastatur mit POKE 1,PEEK(1) AND 191 im Programm erfolgen kann. Vor diesem POKE ist aber noch das Datenrichtungsregister auf Ausgabe zu setzen. Dies erfolgt mit POKE 0, PEEK (0) OR 64. Mit POKE 1, PEEK(1) OR 64 wird die ASCII-Tastatur wieder aktiviert. Weiterhin wurde behauptet, daß mit POKE 2757,129 die Umschaltmöglichkeit auf die DIN-Tastatur verhindert werden kann und nur ein Druck auf den Reset-Knopf dies rückgängig macht. POKE 2757,0 tut es auch.
ESC 0 schaltet den Einfüge-, Anführungs- und Invers-Modus aus. Wenn Sie die ESC-Taste zweimal kurz hintereinander drücken, erreichen Sie den gleichen Effekt, nur schneller.
Der USR-Vektor wurde nur für den C 64-Modus beschrieben und das auch noch falsch. Im C 64-Modus liegt der USR-Vektor an den Speicherstellen 785 und 786 und im C 128-Modus bei 4633 und 4634.
Im C 128-Modus hat der Basic-Interpreter eine Verbesserung aufzuweisen. Während beim C 64 die Abfrage auf einen Leerstring beim ASC-Befehl die Fehlermeldung ILLEGAL QUANTITY hervorruft, erhalten Sie beim C 128 als Ergebnis den Wert 0.
Um Zahlen in andere Zahlensysteme umzurechnen, gibt es beim C 128 die Befehle DEC und HEX$. Mit dem eingebauten Maschinensprachenmonitor haben Sie eine sehr komfortable Möglichkeit zur Zahlenumrechnung. Sie rufen mit dem Befehl MONITOR den Maschinensprachenmonitor auf und geben die umzurechnende Zahl mit vorangestelltem Umrechnungssymbol ein ($ = hexadezimal, + = dezimal, & = oktal und °/o = binär). Wenn Sie nun die RETURN-Taste drücken, so wird die Zahl in allen vier Zahlensystemen ausgegeben.
Zum Spritehandling gibt es beim C 128 komfortable Befehle. So können Sprites unabhängig vom laufenden Programm bewegt werden. Dieses geschieht in der Interruptroutine. In der Speicherstelle 4861 steht ein Flag, welches angibt, ob die Interruptroutine für die Spritesteuerung ausgeführt werden soll. Wenn Sie in diese Speicherstelle einen Wert ungleich Null schreiben, so bleiben alle Sprites sofort stehen. Aber Achtung! Der PLAY-Befehl funktioniert dann nicht mehr. Mit POKE 4861,0 bewegen sich die Sprites weiter. Für die Geschwindigkeit können beim MOVSPR-Befehl Werte bis 15 angegeben werden. Wenn Sie aber direkt die Register für die Spritegeschwindigkeit mit POKE ansprechen, so sind auch höhere Geschwindigkeiten möglich. Errechnen läßt sich die Speicherstelle durch 4478+(SN-1)*11. Hierbei steht SN für die Spritenummer (1 bis 8). Wollen Sie die Spritegeschwindigkeit drosseln, so können Sie dies mit dem Programm SPRITES-LOW (Listing 1) tun. Mit
BANK 15: SYS DEC("1300"),X
wird das Programm aufgerufen. Für X setzen Sie den Wert der Verzögerung ein. Die Spritegeschwindigkeit, die mit dem Befehl MOVSPR eingegeben wurde, sollte aber nicht größer als 1 sein. Experimentieren Sie ruhig ein bißchen!
Kommen wir gleich zum zweiten Maschinenprogramm (Listing 2). Dies Programm rekonstruiert ein mit NEW gelöschtes Programm. Solange noch keine neuen Programmzeilen eingegeben wurden, kann mit
BANK 0: SYS DEC("1300")
ein mit NEW oder nach einem RESET gelöschtes Programm gerettet werden.
Das Basic V 7.0 wurde zwar um etliche Befehle erweitert, trotzdem gibt es immer noch keinen vernünftigen INPUT-Befehl. Die Eingaberoutine aus Listing 3 können Sie als Unterprogramm in Ihren eigenen Programmen benutzen.
Es erlaubt, nur bestimmte Zeichen einzugeben. Außerdem kann eine maximale Eingabelänge festgelegt werden. Zu diesem Programm nun noch einige Erklärungen:
In Zeile 45 werden die erlaubten Zeichen der Stringvariablen EZ$ übergeben. In Zeile 50 wird in der Variablen Ql die maximale Eingabelänge festgelegt und das Unterprogramm mit GOSUB 100 aufgerufen. Nach der Rückkehr aus dem Unterprogramm steht die Eingabe in der Stringvariablen Y2$. In der Eingaberoutine wird in Zeile 110 der aktuelle Cursormodus der Variablen Q9 übergeben und mit POKE 2598,0 der blinkende Cursormodus eingeschaltet. POKE 2599,01äßt den Cursor auch bei dem Befehl GET oder GETKEY blinken. Zeile 150 prüft auf die maximale Eingabelänge und Zeile 160 auf die erlaubten Zeichen. Wird versucht, unerlaubte oder zuviele Zeichen einzugeben, so wird dies durch ein akustisches Signal angezeigt. Zeile 180wartet darauf, daß der Cursor sich nicht in der Blinkphase befindet. Wurde Return gedrückt, so wird mit POKE 2599,1 das Cursorblinken bei GET wieder ausgeschaltet und der vorher in Q9 festgehaltene Cursormodus in Speicherstelle 2598 eingetragen.
PROGRAMM : SPRITESLOW C128 1300 132D ----------------------------------- 1300 : 78 85 FA 85 FB A9 11 8D 16 1308 : 14 03 A9 13 8D 15 03 58 A9 1310 : 60 C6 FA A5 FA D0 0C A9 00 1318 : 00 8D FD 12 A5 FB 85 FA E7 1320 : 4C 65 FA A9 01 8D FD 12 AB 1328 : 4C 65 FA 00 13 E3
PROGRAMM : OLD C128 1300 134C ----------------------------------- 1300 : A5 2D A4 2E 85 FA 84 FB 65 1308 : A0 03 C8 B1 FA D0 FB C8 4A 1310 : 98 18 65 FA A0 00 91 2D 18 1318 : A5 FB 69 00 C8 91 2D A5 2E 1320 : 2D 85 FA A5 2E 85 FB A0 C3 1328 : 01 B1 FA F0 0B AA 88 B1 6A 1330 : FA 85 FA 86 FB 4C 27 13 61 1338 : A5 FA 18 69 02 8D 10 12 7F 1340 : 90 02 E6 FB A5 FB 8D 11 9D 1348 : 12 60 01 1C E5
10 :rem eingaberoutine mit getkey 20 : 30 : 40 :rem beispiel einer eingabe 45 ez$="1234567890+-." 50 print"eingabe : ";:q1=5:gosub100:eg$=y2$:end 60 : 100 rem beginn der eingaberoutine 110 q9=peek(2598):poke2598,0:q4=0:y2$="":poke2599,0 120 getkeyy1$ 130 ify1$=chr$(13)then220 140 ify1$=chr$(20)then270 150 ifq4=q1thenprintchr$(7);:goto120 160 q5=instr(ez$,y1$):ifq5=0thenprintchr$(7);:goto120 170 poke2600,2 180 ifpeek(2598)then180 190 printy1$;:y2$=y2$+y1$:q4=q4+1:goto120 200 : 210 : rem return gedrueckt 220 poke2600,2 230 ifpeek(2598)then230 240 poke2599,1:poke2598,q9:return 250 : 260 : rem del taste gedrueckt 270 ifq4=0thenprintchr$(7);:goto120 280 poke2600,2 290 ifpeek(2598)then290 300 printchr$(20);:q4=q4-1:y2$=left$(y2$,q4):goto120
Eine Grafik-Spielerei
Mit dieser kleinen Routine können Sie bezaubernde Grafik-Bilder erzeugen. Durch Verändern des Wertes X können die Steigungen der Kurven variiert werden. Ebenfalls kann man einen verkleinernden oder vergrößernden Faktor wählen (Zeile 30).
10 GRAPHIC 1,1
20 FOR A = 200 T0 0 STEP-3
30 B=B+3
40 CIRCLE, 160, 100, A, A, 0, 0, B, X
50 NEXT