C 64
Tips & Tricks

Tips & Tricks für Profis

Bisher erschien es nicht möglich, auf dem C 64 Daten mit 4800 bit/s zu übertragen. Ein kleines Programm schafft Abhilfe. Außerdem läßt sich der eigentlich nicht nutzbare Bildschirmrahmen nun doch sinnvoll beschreiben.

Im Handbuch des C 64 steht überhaupt nichts, im Programmierhandbuch nichts Genaues — was ist mit den freidefinierbaren Übertragungsraten los?

Beim C 64 handelt es sich bei der RS232-Schnittstelle um eine bitserielle, asynchrone Übertragung. Das heißt ein Byte wird in Bits zerteilt und diese werden dann über eine Leitung in Form von Spannungswechseln gesendet. Unter asynchroner Übermittlung versteht man die Verwendung von Kennzeichen für Byteanfang und Byteende. Bei manchen Computern können die Daten wunschweise auch synchron übermittelt werden. Der Computer sendet dann kein Start- oder Stoppbit mehr, es werden nur noch die Daten übertragen. Vorteil: Die Übertragungszeit verkürzt sich, da die Steuerbits entfallen.

RS232 mit 4800 bit/s

Beim C 64 ist die Übertragung rein softwaremäßig geregelt. Er setzt dazu den CIA #2 ein. Dieser Baustein besitzt zwei 16-Bit-Intervall-Timer, die von einem bestimmten Wert auf Null zählen und dann einen NMI auslösen können. Dies nutzt die RS232-Schnittstelle aus. Die Software holt den Wert für den Timer B, der als Interruptgenerator dient, aus einer im ROM verankerten Tabelle. Es existieren hierzu zwei verschiedene Tabellen, aber dazu später mehr. Diese Werte werden in den Timer und in zwei Speicherstellen gebracht. Danach startet der Timer. Da beim C 64 das Senden und Empfangen über RS232 interruptgesteuert geschieht, werden zwei Puffer (Zwischenspeicher) benötigt. Einer der beiden Puffer steht für die zu sendenden Daten bereit. Die Daten werden nur in den Puffer geschrieben. Das Senden geschieht mit Hilfe des NMI-Interrupts, weil man ihn (im Gegensatz zum IRQ) nicht sperren kann. So werden die Daten in jedem Fall gesendet, es sei denn, man stoppt den Timer oder verbiegt den NMI-Vektor. Da die Daten in den Puffer geschrieben werden und das Beschreiben des Puffers normalerweise schneller geht als das Senden der Zeichen, sollte man, nachdem ein Zeichen gesendet wurde, das nächste Zeichen vorbereiten und warten, bis der Puffer frei ist. Nun kann das Zeichen problemlos in den Puffer geschrieben werden. Beachtet man dies nicht, könnte versehentlich ein noch nicht gesendetes Zeichen überschrieben werden. Die Folge wäre eine fehlerhafte Übertragung. Das Empfangen geschieht auf ähnliche Weise, denn die RDX-Leitung (hier gelangen die Daten vom anderen Computer zum C 64) ist nicht nur mit dem Port B des CIA #2 verbunden, sondern auch mit dem Eingang FLAG der CIA, der einen NMI auslösen kann. Das Empfangen geschieht also unabhängig vom Programm, daher werden die Daten in den Empfangspuffer geschrieben, der genauso groß ist wie der Sendepuffer: 256 Byte. Man sollte sich also darum kümmern, daß die Zeichen rechtzeitig aus dem Puffer gelesen werden. Durch die Kernelroutine READST, oder beim C 64 auch durch Auslesen der Speicherstelle $90, läßt sich der Status abfragen. Bei gesetztem Bit 2 lief der Empfangspuffer über. Um nun andere Übertragungsraten zu benutzen, könnten natürlich die Werte in den Timer und die entsprechenden Werte in die beiden Speicherstellen geschrieben werden. Dies hätte nur den großen Nachteil, daß die so erstellten Programme schwer an andere (Commodore-)Computer anzupassen wären, da diese nicht die gleichen Speicherstellen benutzen. Aber dies ist gar nicht nötig, denn es geht auch sehr viel eleganter! Die RS232-Schnittstelle öffneten wir bisher folgendermaßen:

lda #2 ;Logische Filenummer = 2
ldx #2 ;Gerätenummer der RS232
ldy #3 ;Sekundäradresse (ohne Funktion)
jsr setpar ;Werte setzen
lda #2 ;Länge des Filenamens
ldx #<fadr ;Adresse des Filenamens (low)
ldy #>fadr ;(high)
jsr setnam ;Name für OPEN setzen
jsr open ;Datei öffnen
ldx #<ebuf ;Zeiger für Empfangspuffer
ldy #>ebuf ;und
stx $f7
sty $f8
ldx #<abuf ;Ausgabepuffer setzen
ldy #>abuf
stx $f9
sty $fa
fadr .byte %00000110 ;Wert für Steuerregister
     .byte %00000000 ;Wert für Befehlsregister

Übrigens werden die Zeiger auf die Puffer auch vom Betriebssystem gesetzt, das die Puffer an das obere (Basic-) RAM-Ende legt. Dies ist auch der Grund, weswegen beim Öffnen der Schnittstelle ein CLR ausgeführt wird, denn im gleichen Speicherbereich liegen ja auch die Stringvariablen. Wenn wir jetzt zum Beispiel sequentielle Dateien senden oder empfangen wollten, könnte es bei langen Dateien passieren, daß die Puffer und die Datei sich überlappen, so daß Datenverluste entstehen. Darum legen wir die Puffer in uns angenehme Speicherbereiche, was man entweder vor oder nach dem OPEN-Befehl machen kann. Vorher deswegen, da das Betriebssystem die Pufferadressen erst festlegt, nachdem es in den Speicherstellen nachgesehen hat, ob das vom Programm schon gemacht wurde. Ist das High-Byte der Pufferzeiger ungleich Null, wird davon ausgegangen, daß die Zeiger bereits auf die Puffer deuten. Deshalb wird nichts mehr verändert. Und nun geht's los!

Übersicht der Werte für:

Steuerregister Befehlsregister
Bit 7:
0 1 Stoppbit
1 2 Stoppbits
Bit 7,6,5:
000 keine Parität
001 gerade Parität
011 ungerade Parität
101 8. Datenbit = 1
111 8. Datenbit = 0
Bit 5,6:
00 8 Datenbits
01 7 Datenbits
10 6 Datenbits
11 5 Datenbits
Bit 4:
0 Vollduplex
1 Halbduplex
Bit 0,1,2,3:
0000 selbstdef. Übertr.
0001 50 bit/s
0010 75 bit/s
0011 110 bit/s
0100 134,5 bit/s
0101 150 bit/s
0110 300 bit/s
0111 600 bit/s
1000 1200 bit/s
1001 1800 bit/s
1010 2400 bit/s
Bit 0 (Handshake):
0 3-Line (Software-)
1 X-Line (Hardware-)

Der Filename kann auch vier Zeichen lang sein. Die ersten beiden Zeichen behalten ihre Bedeutung bei, aber die nächsten beiden beinhalten den Wert für die Übertragungsrate.

Der Filename sieht also wie folgt aus:

»Steuerregister« »Befehlsregister« »Übertragungsrate-low« »Übertragungsrate-high«

Wie gesagt, das untere Nibble vom »Steuerregister« muß %0000 sein! Die Werte für »Übertragungsrate-low« und »Übertragungsrate-high« berechnet man wie folgt:

Übertragungsrate-high = INT(Prozessortakt/ Übertragungsrate/2-100)/256)
Übertragungsrate-low= INT(Prozessortakt/ Übertragungsrate/2-100-Übertragungsrate-highx256)

Der Prozessortakt beträgt bei der deutschen PAL-Version 985259 Hertz, bei der amerikanischen NTSC-Version 1022730 Hertz. Das heißt nichts anderes, als daß die Programme auf amerikanischen Geräten schneller laufen als auf deutschen. Da dies natürlich auch Auswirkungen auf die Übertragungskapazität hat, sind im Betriebssystem zwei Tabellen für den Timer B vorhanden. Wenn Sie nun Programme mit selbstdefinierten Übertragungsraten schreiben, sollten Sie immer daran denken, daß diese Programme entweder nur auf dem deutschen oder dem amerikanischen C 64 richtig laufen, wenn Sie nur eine Tabelle verwenden. Durch Auslesen der Speicherstelle $02A6 können Sie ganz einfach feststellen, ob Sie eine PAL- oder eine NTSC-Version vor sich haben. Bei einer PAL-Version steht in besagter Speicherstelle der Wert 1, bei NTSC eine Null.

Nun ein Beispiel: Die Übertragungsrate soll 1800 Bit/s betragen. Also erhalten wir für »Übertragungsrate-high«: INT((985250/4800/2-100)/256)=0 und für »Übertragungsrate-low«: INT(985250/4800/2-100-0x256)=2. Der Filename lautet also: %XXXX0000, %XXXXXXXX, %00000010, %00000000 Achtung: Für die X-Bits setzen Sie die entsprechenden Werte aus der Tabelle ein.

Übungen:

Wir möchten ein sequentielles File mit 4800 bit/s, 7 Datenbits, 1 Stoppbit, 3-Line-Handshake und keiner Parität senden. Also: Zuerst das sequentielle File in den Speicher laden. Jetzt müssen wir noch die RS232-Schnittstelle öffnen, wobei wir auf die Abfrage auf PAL- oder NTSC-Version verzichten. Das Programm zum Öffnen ist bis auf den Filenamen und dessen Länge von dem altbekannten nicht zu unterscheiden.

lda #2 ;logische Filenummer = 2
ldx #2 ;Geraetenummer der RS232
ldy #3 ;Sekundaeradresse
jsr setlfs ;Werte setzen
lda #4 ;der Filename ist 2 Zeichen lang
ldx #<fadr ;Adresse des Filenamens (low)
ldy #>fadr ;(high)
jsr setnam ;Name für OPEN setzen
jsr open ;Datei oeffnen
ldx #2 ;Datei mit der logischen Filenummer
jsr chkout ;#2 als Standardausgabegerät

Nun müssen Sie einen Zeiger auf den Anfang des in den Speicher geladenen sequentiellen Files setzen und die Pufferzeiger entsprechend ändern.

(Zeiger »pt« auf Dateianfang setzen)
sende ldy #0 ;aktuelles Zeichen aus dem
lda (pt),y ;File in den Akku holen
(Zeichen nun bearbeiten, zum Beispiel in ASCII-Code
wandeln)
tax ;Zeichen merken
wloop lda $02a1 ;ist das vorherige Zeichen
and #1 ;bereits gesendet worden?
bne wloop ;nein: =>warten
txa ;gemerktes Zeichen zurueckholen
jsr chrout ;auf RS232 ausgeben

Der Zeiger »PT« muß nun erhöht und auf Fileende getestet werden. Ist die Datei noch nicht zu Ende, muß wieder zum Label SENDE gesprungen werden.

jsr clrchn ;Standardwerte Ein-/Ausgabe
lda #2 ;setzen und Datei schließen
jsr close
rts ;das war's!
fadr .byte %00100000
.byte %00000000
.byte %00000010
.byte %00000000

Das folgende Programm (Listing 1, bitte mit dem MSE eingeben) sendet sequentielle Files mit 4800 Bit/s, 8 Datenbits, 1 Stoppbit, keine Parität, Vollduplex und 3-Line-Handshake. Die Syntax lautet: SYS 52480,konv-flag," Name" Wenn konv-flag = 0, werden die Zeichen erst in ASCII-Code gewandelt und dann gesendet. Bei konv-flag = 128 erfolgt die Übertragung unverändert.

Mit dem Namen ist der Titel der sequentiellen Datei gemeint. »,S,R"« wird vom Programm nicht automatisch ergänzt. Sie müssen es also noch an den Namen anhängen. Beispiel: SYS 52480,128," TEST,S,R"

Die Datei TEST wird unkonvertiert gesendet.

(Martin Müller/aw)
PROGRAMM : SCREENCOPY $CF11 CF11 CFFF
-----------------------------------
CF11 : 78 A2 23 A0 CF 8E 14 03   7F
CF19 : 8C 15 03 58 A9 41 8D F2   BC
CF21 : CF 60 AD 8D 02 49 07 29   16
CF29 : 07 F0 03 4C 31 EA AD 0E   30
CF31 : DC 29 FE 8D 0E DC A9 01   84
CF39 : A2 08 A0 01 20 BA FF A9   53
CF41 : 06 A2 ED A0 CF 20 BD FF   1D
CF49 : 20 C0 FF A2 01 20 C9 FF   56
CF51 : A9 40 20 D2 FF A9 00 20   0A
CF59 : D2 FF AD 88 02 85 F8 A9   2B
CF61 : 00 85 F7 A9 19 8D EC CF   A8
CF69 : A9 28 8D EB CF A0 00 20   49
CF71 : F3 CF B1 F7 49 80 91 F7   86
CF79 : 20 F9 CF C9 20 D0 04 A9   AF
CF81 : DF D0 21 C9 A0 F0 1D 49   E2
CF89 : 80 29 7F C9 20 B0 05 09   65
CF91 : 40 4C A5 CF C9 40 90 0C   54
CF99 : C9 60 B0 05 09 80 4C A5   70
CFA1 : CF 18 69 40 20 D2 FF A0   B9
CFA9 : 00 20 F3 CF B1 F7 49 80   B1
CFB1 : 91 F7 20 F9 CF E6 F7 D0   3B
CFB9 : 02 E6 F8 CE EB CF D0 AD   22
CFC1 : A9 28 8D EB CF A9 20 20   6A
CFC9 : D2 FF CE EB CF D0 F6 CE   C9
CFD1 : EC CF D0 94 20 CC FF A9   27
CFD9 : 01 20 C3 FF EE F2 CF AD   FC
CFE1 : 0E DC 09 01 8D 0E DC 4C   15
CFE9 : 31 EA 00 00 42 49 4C 44   B8
CFF1 : 20 41 78 A2 34 86 01 60   60
CFF9 : A2 37 86 01 58 60         A1
Listing 1. RS232 mit 4800 Bit/s. Bitte mit dem MSE eingeben.
0 goto 100
1 list 1000-2100
2 list 1920-2100
3 list 2300-2999
100 poke 53280,0:poke 53281,0:poke 56325,35:poke 646,4:poke 650,128
110 open 1,8,1,"seq-transver .obj"
120 sys 9*4096
130 ;
140 .opt o1
150 ;
160 *= $cd00
170 ;
180 ;
190 ;
199 ;
200 ;----------------------------------
201 ;
210 setlfs = $ffba   ;"log{CBM-@}Filenr.,Geraetnr.,Skundadr. setzen
220 setnam = $ffbd   ;"Filename setzen
230 open   = $ffc0   ;"File oeffnen
240 readst = $ffb7   ;"Statusvariable lesen
290 close  = $ffc3   ;"File schliessen
295 chkin  = $ffc6   ;"File auf Eingabe setzen
300 chkout = $ffc9   ;"File auf Ausgabe setzen
310 chrout = $ffd2   ;"Zeichen ausgeben
315 chrin  = $ffcf   ;"Zeichen holen
320 clrchn = $ffcc   ;"Standardwerte fuer I/O setzen
330 ;
370 chckom = $aefd   ;"Auf Komma testen
380 frmevl = $ad9e   ;"Ausdruck auswerten
390 frestr = $b6a6   ;"weitere Auswertungen fuer Strings
400 getbyt = $b79e   ;"Byte holen
410 ;
500 pt     = $22     ;"Zeiger auf  Textende
510 hpt    = $14     ;"zu sendendes Byte
520 mconv  = $02     ;"Flag fuer ASCII-Konvertierung
530 synerr = $af08   ;"?SYNTAX ERROR ausgeben
600 buf    = $ce00   ;"Buffer fuer RS 232
610 ribuf  = $f7     ;"Zeiger auf Eingabebuffer
620 robuf  = $f9     ;"Zeiger auf Ausgabebuffer
700 start  = $0801   ;"Ladeadresse fuer SEQ-File
710 enable = $02a1   ;"RS 232 Flag: Alle Zeichen gesendet?
1000 ;
1001 ;"--------------------------------
1002 ;"- SEQ-Transfer -- version 1.0 --
1003 ;"- SEQ-Files mit 4800 Baud ------
1004 ;"- ueber RS 232 senden ----------
1005 ;"- geschrieben von --------------
1006 ;"-- Martin Mueller --------------
1007 ;"- (c) by Arnd Waengler, 64'er --
1008 ;"--------------------------------
1009 ;
1010 baudin jsr chckom     ;"Auf Komma testen
1012 ^      jsr getbyt     ;"Konvertierungsflag nach
1014 ^      stx mconv      ;"mconv holen
1016 ^      jsr chckom     ;"Auf Komma testen
1020 ^      jsr frmevl     ;"Ausdruck auswerten
1030 ^      jsr frestr     ;"Stringauswertungen
1040 ^      cmp #5         ;"Laenge des Strings < 5{$a0}?
1050 ^      bcs baudw1     ;"Nein: => weiter
1060 ^      jmp synerr     ;"Sonst: SYNTAX ERROR{$a0}melden
1070 baudw1 ldx pt         ;"Stringadresse als
1080 ^      ldy pt + 1     ;"Adresse des Filenamen
1090 ^      jsr setnam     ;"dem OS uebergeben
1100 ^      lda #1         ;"logische Filenummer: 1
1110 ^      ldx #8         ;"Geraetenummer: 8
1120 ^      ldy #2         ;"Sekundaeradresse: 2
1130 ^      jsr setlfs     ;"setzen
1140 ^      jsr open       ;"Datei eroeffnen
1150 ^      jsr readst     ;"Fehlermeldung holen
1155 ^      beq baud21     ;"Kein Fehler: => weiter
1160 baudw2 jsr clrchn     ;"Standartwere fuer I/O setzen
1165 ^      lda #1         ;"File schliessen
1170 ^      jmp close      ;"Zurueck
1180 ;
1190 baud21 ldx #1         ;"File als Eingabefile
1200 ^      jsr chkin      ;"definieren
1210 ^      jsr readst     ;"Fehler aufgetreten?
1220 ^      bne baudw2     ;"JA: => Zurueck nach BASIC
1230 ^      ldx #<start    ;"Adresse, ab der die
1240 ^      ldy #>start    ;"Daten des SEQ-File abgelegt
1250 ^      stx pt         ;"werden, als Zeiger merken
1260 ^      sty pt + 1     ;"(= Basicanfang)
1270 ;
1280 baudl1 jsr chrin      ;"Zeichen vom File holen
1290 ^      ldy #0         ;"und in den Speicher
1300 ^      sta (pt),y     ;"schreiben
1310 ^      inc pt         ;"Zeiger um
1320 ^      bne baudw3     ;"eins erhoehen
1330 ^      inc pt + 1
1340 ;
1350 baudw3 jsr readst     ;"Fehler aufgetreten?
1360 ^      beq baudl1     ;"NEIN: => weiter
1370 ^      and #%01000000 ;"File zu ende?
1390 ^      beq baudw2     ;"NEIN: => Zurueck nach BASIC
1420 ;
1430 baudw4 jsr baudw2     ;"Datei schliessen
1460 ;"RS 232 Schnittstelle oeffnen
1470 ;"4800 Baud, 8 Datenbits, 1 Stopbit
1480 ;"Parity disabled, 3-Line Handshake,
1485 ;"Full Duplex
1490 ^      lda #1         ;"Logische Filenummer: 1
1500 ^      ldx #2         ;"Geraetenummer: 2
1510 ^      ldy #3         ;"Sekundaeradresse: 3
1520 ^      jsr setlfs     ;"setzen
1530 ^      lda #4         ;"Werte fuer
1540 ^      ldx #<rsnam    ;"RS 232
1550 ^      ldy #>rsnam    ;"setzen
1560 ^      jsr setnam
1570 ^      jsr open       ;"File oeffnen
1580 ^      ldx #3         ;"Zeiger fuer RS 232 Buffer
1590 baudl9 lda rstab,x    ;"setzen
1600 ^      sta ribuf,x
1610 ^      dex
1620 ^      bpl baudl9
1650 ;
1660 ^      ldx #1         ;"File als Ausgabefile
1670 ^      jsr chkout     ;"deklarieren
1680 ^      ldx #<start    ;"Startadresse fuer
1690 ^      ldy #>start    ;"das SEQ-File als Zeiger
1700 ^      stx hpt        ;"merken
1710 ^      sty hpt + 1
1712 ^      lda 56334      ;"Timerirq sperren
1714 ^      and #254
1716 ^      sta 56334
1720 ;
1730 baudl2 ldy #0         ;"Aktuelles Zeichen
1740 ^      lda (hpt),y    ;"holen
1750 ^      bit mconv      ;"Zeichen konvertieren?
1760 ^      bmi baud51     ;"NEIN: => weiter
1770 ^      cmp #65        ;"Sonst: Commodore'ASCII'
1780 ^      bcc baudw5     ;"nach ASCII
1790 ^      cmp #128
1800 ^      bcs baud41
1810 ^      ora #%00100000
1820 ^      bne baudw5
1830 baud41 cmp #192
1840 ^      bcc baudw5
1850 ^      sec
1860 ^      sbc #128
1870 baudw5 and #%01111111
1880 baud51 tax            ;"Zeichen merken
1890 baudl3 lda enable     ;"Ist das vorherige Zeichen
1900 ^      and #%00000001 ;"schon gesendet worden
1910 ^      bne baudl3     ;"NEIN: => Weiter
1915 ^      txa            ;"Zeichen zurueckholen
1917 ^      jsr chrout     ;"und ueber RS 232 ausgeben
1920 ;
1930 ^      inc hpt        ;"Zeiger auf aktuelles
1940 ^      bne baudw6     ;"Zeichen um eins
1950 ^      inc hpt + 1    ;"incrementieren
1960 baudw6 lda pt         ;"Ist bereits das
1970 ^      cmp hpt        ;"letzte Zeichen
1980 ^      bne baudl2     ;"uebertragen worden
1990 ^      lda pt + 1     ;"NEIN: => Weiter uebertragen
2000 ^      cmp hpt + 1
2010 ^      bne baudl2
2020 ;
2022 baudl4 lda enable     ;"Sonst warten, bis das Zeichen
2024 ^      and #%00000001 ;"schon geschickt worden ist!
2026 ^      bne baudl4
2040 ^      jsr baudw2     ;"File schliessen
2060 ;
2070 ^      lda 56334      ;"Timerirqs wieder
2080 ^      ora #1         ;"erlauben
2090 ^      sta 56334
2100 ^      rts            ;"Programmende
2300 rsnam .byte %00000000 ;"1 Stopbit,8 Datenbits,4800 Baud
2310 ^     .byte %00000000 ;"Parity disabled,Full Duplex,
2315 ;"3-Line Handshake
2320 ^     .byte 2         ;"Werte fuer 4800 Baud
2330 ^     .byte 0
2340 ;
2350 rstab .byte <buf         ;"Tabellen fuer Adressen
2360 ^     .byte >buf         ;"der RS 232 Buffer
2370 ^     .byte <(buf + 256)
2380 ^     .byte >(buf + 256)
60000 .end
60010 end
60100 open 15,8,15,"s:seq-transver"
60110 close 15
60120 save "seq-transver",8

Änderung der Tastaturbelegung

Es kommt des öfteren vor, daß man anstelle der alten Tastaturbelegung eine andere benutzen möchte, um beispielsweise Programme leichter eingeben zu können. Oder man möchte anstelle der amerikanischen QWERTY- eine QWERTZ-Tastatur haben. Eine Lösungsmöglichkeit wäre, die Zeichen Y und Z im Zeichensatz umzudefinieren. Die gebräuchlichste Lösung dieses Problems ist, das ROM ins RAM zu kopieren und die Zeichen in der Tastaturtabelle auszutauschen. Will man dies jedoch in Basic ausführen, ist das sehr zeitaufwendig und schwierig.

Das folgende Programm (Listing 2) macht es Ihnen sehr leicht. Bis auf die Tasten <SHIFT>, <CBM>, <CTRL> und <RESTORE> kann jeder Taste des C 64 ein beliebiger CHR$-Code zugeordnet werden. Der Tasten-Code stimmt mit dem jeweiligen Bildschirm-Code überein. Die Syntax des neuen Befehls lautet: !A,B

A ist der Bildschirm-Code, dem der CHR$-Code B zugeordnet wird. Wollen wir beispielsweise das Zeichen A in ein B umwandeln, muß folgender Befehl angewandt werden: !1,66 (und !2,65, falls das B in ein A geändert werden soll).

Die Zahl 1 ist der Bildschirm-Code des Zeichens A, dem der Wert 66 (CHR$-Code von B) zugeordnet wird. Es ist dabei unwichtig, ob das B vorher geändert war oder nicht. Der CHR$-Code wird aus dem ROM gelesen.

Um eine QWERTZ-Tastatur zu erhalten, sind folgende Befehle einzugeben:
!25,90 (wandelt Y in Z um)
!26,89 (wandelt Z in Y um)

Soll die Cursor-Steuerung auf die Funktionstasten gelegt werden, so benötigt man folgende Befehle:
!39,145 (<F1> = <CRSR>-hoch)
!40,17 (<F3> = <CRSR>-unten)
!41,157 (<F5> = <CRSR>-links)
!63,29 (<F7> = <CRSR>-rechts)

Beim Abtippen von »DATA-Wüsten« lohnt es sich, die Komma-Taste zu verschieben. Der Befehl !31,44 verlegt diese auf die <←>-Taste.

Einige der Zeichen können jedoch nicht geändert werden. Es sind die Bildschirmcodes von 33 bis 41 sowie der Code 63. Diese Zeichencodes sind anderweitig belegt.

Zeichencode Neue Belegung
33 <CRSR>-links
34 <CRSR>-hoch
35 <DEL>
36 <HOME>
37 <STOP>
38 <RETURN>
39 <F1>
40 <F3>
41 <F5>
63 <F7>

Im Klartext heißt das, daß Sie, wenn Sie den Bildschirm-Code 33 mit dem Befehl !33,65 ändern wollen, nicht das Ausrufungszeichen, sondern die <CRSR>-links-Taste in ein A umwandeln.

Die Initialisierung der Routine erfolgt durch SYS 49152. Danach steht Ihnen der Befehl !A,B zur Verfügung. Der Wertebereich von A und B liegt zwischen 0 und 255. Löschen läßt sich die Tastenbelegung, indem man die ursprüngliche Belegung aus dem ROM kopiert. Dies geschieht durch: POKE 1,55:SYS 49152

(Andreas Schindler/dm)
0 data120,162,53,142,8,3,162,192,142,9,3,169,0,133,251,133,253,169,160
1 data133,252,169,224,133,254,162,32,160,0,177,251,145,251,177,253,145
2 data253,200,208,245,230,254,230,252,202,208,238,169,53,133,1,88,96,32
3 data115,0,201,33,240,6,32,121,0,76,231,167,32,115,0,32,158,183,134,2
4 data160,0,224,64,144,14,224,128,144,8,224,192,144,2,200,200,200,200,200
5 data200,152,170,189,121,235,133,251,189,122,235,133,252,165,2,41,63,170
6 data189,135,192,133,2,32,253,174,32,158,183,138,164,2,145,251,169,53
7 data133,1,76,174,167,234,46,10,28,20,18,14,21,26,29,33,34,37,42,36,39
8 data38,41,62,17,13,22,30,31,9,23,25,12,64,48,64,54,57,60,2,7,0,51,63
9 data1,4,5,6,49,40,47,43,44,55,56,59,8,11,16,19,24,27,32,35,45,50,64,53,64,3
10 fori=49152to49350:reada:pokei,a:next
11 rem  aktivieren   sys49152
12 rem  syntax       !a,b
Listing 2. Leichtes Umdefinieren der Tastaturbelegung

Laufschrift im Bildschirmrahmen

Seit einiger Zeit ist es in Mode gekommen, im Titelbild mancher Programme mindestens eine Laufschrift darzustellen. Nachdem sich die Programmiertechnik hier immer weiter fortentwickelt hat, so daß sich die Laufschriften jetzt schon hochauflösend und flimmerfrei bewegen, bleibt immer noch ein großes Problem: Jede Laufschrift benötigt Platz auf dem Bildschirm. Will man zum Beispiel eine Laufschrift in ein HiRes-Bild einblenden, mußte bisher immer das Bild so weit angepaßt werden, daß eine oder zwei Zeilen für die Laufschrift freiblieben. Hier stellt sich die Frage: Muß das so sein?

Nein, denn wozu gibt es den weitgehend ungenutzten Bildschirmrand, der lange Zeit immer nur die Farbe annehmen konnte, die in $D020 angegeben war. Vor einiger Zeit kam jemand auf die Idee, diesen Platz dem VIC durch geschicktes Umschalten in den 24-Zeilen-Modus (durch Löschen des Bit ROW SELECT im Register $D011) als nutzbaren Raum zu entlocken. Die Euphorie über diese Entdeckung wurde jedoch rasch wieder gebremst: Außer dem einen Byte am Ende des VIC-Adreßraums, das nur langweilige Streifen erzeugt, kann der VIC in diesem Bereich nur Sprites darstellen. So lag die einzige Nutzung dieses zusätzlichen Raumes darin, ein paar einsame Sprites über den Rand hinauswandern zu lassen. Diese Sprites können aber auch sinnvoller eingesetzt werden!

Bei einigermaßen geschicktem Einsatz der acht zur Verfügung stehenden Sprites läßt sich eine brauchbare Laufschrift auf dem Rahmen erzeugen. Es sind aber durchaus auch zwei Laufschriften möglich. Genau dies tut nun das vorliegende Programm (Listing 3, bitte mit dem MSE eingeben). Es scrollt acht Sprites, deren Inhalt in $3E00 bis $3FFF abgelegt ist, von rechts nach links über den Bildschirm. Das dazugehörige kleine Basic-Programm (Listing 4) berechnet aus den eingegebenen Texten die Daten für diese Sprites und schreibt sie gleich in den richtigen Bereich.

Nachdem das Basic-Programm etwa zehn Sekunden lang gerechnet hat, erscheinen die eingegebenen Texte als Laufschriften ober- und unterhalb des Bildschirms. Ein erneutes Einschalten ist nach <RUN/STOP+RESTORE> durch SYS 49152 möglich, da die Daten im Speicher erhalten bleiben. Achtung: Vor dem erneuten Starten des Basic-Teils muß die Interrupt-Routine durch <RUN/STOP+RESTORE> oder durch Eingabe von »SYS 58648:SYS 64789:SYS 64931« (klappt nicht immer) abgeschaltet werden.

Mögliche Änderungen des Programms: Am einfachsten läßt sich die Farbe der Schrift ändern. Hierzu ruft man die Routine nur mit einer anderen Cursorfarbe auf. Zum Verschieben der Laufschriften in Y-Richtung muß der Inhalt der Speicherstelle 49174 verändert werden (normal = 8). In Adresse 49206 steht die Blocknummer des letzten Sprites (normal = 255). Wird diese verändert, müssen natürlich auch im Basic-Teil die Zahlen 15911 und 15872 in Zeile 270/280 verändert werden. Auch mit einem geänderten Zeichensatz läßt sich die Laufschrift einsetzen. Dazu muß die Variable ZA in Zeile 180 auf den Beginn des neuen Zeichensatzes zeigen. Setzt man hier 55296 ein, erscheint die Laufschrift in Kleinschrift.

(Niklas Nebel/dm)
PROGRAMM : LAUFSCHRIFT    C000 C0B0
-----------------------------------
C000 : 78 A9 5C A0 C0 8D 14 03   47
C008 : 8C 15 03 A9 81 8D 1A D0   A3
C010 : A9 00 8D 0E DC A9 08 A2   5F
C018 : 0F 9D 00 D0 CA CA 10 F9   47
C020 : A9 18 A2 00 9D 00 D0 18   CB
C028 : 69 30 E8 E8 E0 10 D0 F4   BC
C030 : A9 E0 8D 10 D0 A0 FF A2   06
C038 : 07 98 9D F8 07 AD 86 02   0E
C040 : 9D 27 D0 88 CA 10 F2 A9   02
C048 : FF 8D 17 D0 8D 1D D0 8D   0E
C050 : 15 D0 58 60 01 02 04 08   30
C058 : 10 20 40 80 AD 19 D0 8D   9A
C060 : 19 D0 AD 12 D0 C9 F7 90   EB
C068 : 0D A9 31 8D 12 D0 A9 13   BC
C070 : 8D 11 D0 4C 81 EA A9 F7   49
C078 : 8D 12 D0 A9 1B 8D 11 D0   7C
C080 : A2 0E A0 07 DE 00 D0 BD   DF
C088 : 00 D0 C9 FF F0 08 CA CA   73
C090 : 88 10 F1 4C 31 EA AD 10   67
C098 : D0 59 54 C0 8D 10 D0 39   51
C0A0 : 54 C0 F0 EA A9 7F 9D 00   FB
C0A8 : D0 D0 E3 00 06 52 78 14   D6
Listing 3. Laufschriften im Bildschirmrahmen. Bitte mit dem MSE eingeben.
100 rem   ***************************
110 rem   *                         *
120 rem   *   demo - laufschrift    *
130 rem   *                         *
140 rem   *  von n.nebel 21.2.1986  *
150 rem   *                         *
160 rem   ***************************
170 rem
180 poke56,62:clr:za=53248
190 print"{clr}{down}2 texte eingeben, jeweils hoechst. 24 z."
200 input"1.";a$:input"2.";b$
210 print"{clr}"a$:print"{home}{down}{down}"b$
220 fori=15872to16382:pokei,0:next
230 poke56334,0:poke1,51
240 fora=0to7:forb=0to2
250 ad=za+8*peek(1024+a*3+b)
260 a2=za+8*peek(1104+a*3+b)
270 fori=0to7:poke15911+a*64+b+i*3,peek(ad+i)
280 poke15872+a*64+b+i*3,peek(a2+i):next
290 next:next
300 poke1,55:poke56334,1
310 poke53280,0:poke16383,255:sys49152
Listing 4. Editor-Programm zur Rahmen-Laufschrift. Beachten Sie die Eingabehinweise auf Seite 99.
PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →