8) Ein tieferes Eindringen
Ich erwähnte es bereits: Man kann dem REC noch viel mehr Kommandos geben als offensichtlich ist. Eine Gruppe von Kommandos sind die (ich nenne sie mal so) Total-RAM-Commands. Man erkennt sie unschwer an ihrem gelöschten Bit 4.
Ihre Namen sind:
- 128 STASH (C64->REU)
- 129 FETCH (REU->C64)
- 130 SWAP (C64<>REU)
- 131 VERIFY (C64--REU)
Mit diesen Kommandos ist es möglich auch im Bereich von $D000 bis $DFFF das RAM zu lesen und zu schreiben.
Aber wie soll das gehen?
Nun, durch die obigen Kommandos führt die REU die gewünschte Aktion nicht sofort aus, sondern wartet auf ein bestimmtes Ereignis. Dadurch hat man Gelegenheit den IO-Bereich (nach Übermittlung der Werte an den REC!) auf RAM zu schalten. Und das bestimmte Ereignis ist ein Schreibzugriff auf $FF00. (Ich sage es nochmal: $FF00, nicht $DF00 oder irgend etwas anderes).
Der Wert in $FF00 wird dadurch nicht verändert.
Der Ablauf in der Übersicht:
Aktion Wert $01
------ --------
a) Parameter an den REC $37,36,35
übermitteln ($DF01-$DF0A)
b) spätestens jetzt: SEI
c) IO auf RAM schalten $34,30
d) etwas in $FF00 schreiben $34,30
um REU zu starten
e) bei Bedarf: ROM an $37
f) bei Bedarf: CLI
Das SEI ist natürlich für die REU unwichtig. Blenden wir aber Basic u/o Kernal aus, täte es schon Not. Und an das RAM unter IO kommen wir ohne ausgeblendetes Basic & Kernal nicht heran!
So, und nun können wir unser Programm aus dem vorigen Kapitel verbessern:
£ba $010b ;Diese Startadresse ist $010b=SYS 267
lda #128
£by $2c ;Diese Startadresse ist $010e=SYS 270
lda #129
gemeinsam:
sta werte
jsr $aefd ;prüft auf Komma
jsr $b79e ;holt Bank nach x
stx werte+5 ;ab in Tabelle
ldx #$09 ;neun Werte
loop1:
lda werte,x ;laden und
sta $df01,x ;in REC speichern
dex
bpl loop1
lda 1 ;Prozessorport
pha ;merken
lda #$30 ;ganzer Computer: RAM
sei ;Interrupt sperren
sta 1 ;RAM-Konfig. einstellen
sta $ff00 ;Transfer starten
pla ;alte Speicherkonfig.
sta 1 ;wiederherstellen
cli ;Interrupt freigeben
rts ;Programmende
werte:
£by 128,1,8,0,0,0,$ff,$f7,0,0
Ich finde, dies ist recht selbsterklärend. Beachtet die Änderungen in der Tabelle (nun $F7FF Bytes statt $C7FF) und die Änderung der Adresse 1, die nun nach der Werteübertragung an den REC stattfindet. Selbstredend haben sich auch die Kommandocodes geändert. Denn diese erst sagen dem REC, daß er auf einen Schreibzugriff bei $FF00 warten soll.
9) Das Eingemachte
Wir wissen jetzt bereits eine Menge über die REU, nicht? Wir können schon Daten an die REU übertragen und diese auch wieder zurückholen. Es gibt jedoch noch einige Spezialfunktionen, die selbst den Profis oft unbekannt sind. Und für diese ist die genaue Kenntnis der REC-Register unerläßlich.
ADRESSE FUNKTION
=======================================
$DF00 Status-Register, nur Lesen
--------------------------
Bit 7: 1=noch kein Interrupt
Bit 6: 1=Transfer beendet
Bit 5: 1=Fehler bei Verify
Bit 4: Ramgröße
Bit 3-0: Version (1764=0,0,0)
DIE BITS 7-5 WERDEN DURCH EINEN LESEZUGRIFF GELÖSCHT.
---------------------------------------
$DF01 Kommandoregister
----------------
Bit 7: 1=Aktion beginnen
Bit 6: <<RESERVIERT>>
Bit 5: 1=Autoload zugelassen
Bit 4: 1=Warte auf $FF00
Bit 3: <<RESERVIERT>>
Bit 2: <<RESERVIERT>>
Bit 1-0: Art der Aktion:
00: STASH C64->REU
01: FETCH REU->C64
10: SWAP C64<>REU
11: VERIFY C64--REU
---------------------------------------
$DF02 Adresse im C64 Low-Byte
---------------------------------------
$DF03 High-Byte
---------------------------------------
$DF04 Adresse in der REU Low-Byte
---------------------------------------
$DF05 High-Byte
---------------------------------------
$DF06 Bank in der REU
---------------------------------------
$DF07 Anzahl der Bytes Low-Byte
---------------------------------------
$DF08 High-Byte
---------------------------------------
$DF09 Interrupt Mask Register
-----------------------
Bit 7: 1=Interrupts erlauben
Bit 6: 1=Interrupt nach Ende
der Aktion
Bit 5: 1=Interrupt bei Verify-
Error
Bit 4-0: <<UNBELEGT>>
---------------------------------------
$DF0A Adress Control Register
-----------------------
Bit 7-6:
00=beide Adressen hochzählen
01=REU-Adresse nicht erhöhen
10=C64-Adresse nicht erhöhen
11=beide Adressen n. erhöhen
Bit 5-0: <<UNBELEGT>>
---------------------------------------
Ich hoffe,ihr habt einen guten Drucker, damit ihr den Überblick nicht verliert. Denn was ihr da überflogen habt ist manchmal schwer verständlich, aber nur bis man es erklärt bekommt. Und anstatt hier eine weitere Tabelle zu schreiben führe ich die neuen Möglichkeiten besser anhand von Beispielen auf.
a) Am Ende einer Aktion (STASH, FETCH, (SWAP, VERIFY) ist Bit 6 des Statusregisters gesetzt.
Durch Lesen wird dieses (wie auch Bit 7 und 5) wieder gelöscht. Wir kennen das ja schon vom Sprite-Kollisionsregister des VIC. Bit 4 ist bei einer 1764 (AUCH EINER AUFGERÜSTETEN!) als einziges im Urzustand gesetzt. Der Wert ist also 16. Nach einer Aktion ist er dann beim ersten Lesen des Registers 80, danach wieder 16. Bei einer 1700 ist Bit 4 gelöscht. Die Bits 3-0 sollen die Version angeben. Tun sie aber wohl nicht. (1764=0,0,0)
b) Wir vergleichen einen Speicherbereich im C64 mit einem in der REU. DAZU LESEN WIR ZUERST DAS STATUSREGISTER $DF00, UM ES ZURÜCKZUSETZEN! Dann setzen wir die Bits 0 und 1 des Kommandoregisters ($DF01) auf 1. Also statt z.B. 252 für STASH schreiben wir 223. Die anderen Register beschreiben wir wie gewohnt. Das Ergebnis erfahren wir in Bit 5 der Adresse $DF00: 0=Speicherinhalt ist gleich. 1=Speicherinhalt ist nicht gleich. Also
10 IFPEEK(57088)AND223 THEN 20
15 PRINT "VERIFY OK":END
20 PRINT "VERIFY ERROR BEI:";
21 PRINTPEEK((57090)+256*PEEK(57091))-1
Eine weitere wichtige Erkenntnis: Tritt ein Fehler auf, vermindern wir die Adresse in $DF02/03 um 1. So erhalten wir die Computeradresse, an der die REU bei VERIFY einen Unterschied fand. Und klar ist: Dasselbe mit $DF04-06 (wieder minus 1) ergibt die Adresse in der REU. DAS ALLES FUNKTIONIERT NICHT BEI AUTOLOAD!
c) Wir AUTOLOADen uns einen.
Gemeinhin verlieren unsere Register bei einer Aktion ihren Wert. D.h., wir müssen jedesmal aufs neue alle Register beschreiben, auch wenn sich einige Werte gar nicht geändert haben (z.B. Adresse im Computer ist immer noch der Bildschirmspeicher). Hier hilft uns die AUTOLOAD-Funktion aus der Patsche. Setzen wir Bit 5 im Kommandoregister bleiben die Werte der Register $DF02-08 am Leben, auch nach der gewünschten Aktion.
Also: Bei 252 für STASH ist Bit 5 bereits gesetzt. Wollen wir keinen AUTOLOAD, schreiben wir 220. Wie wir wissen, ist bei aktivierter AUTOLOAD-Funktion die Ermittlung der Fehler-Adresse bei VERIFY nicht möglich.
d) Schreiben wir ein Kommando ins Kommandoregister ($DF01), so muß Bit 7 dabei gesetzt sein, ansonsten das Kommando nicht ausgeführt wird. Also keine Kommandos kleiner 128!
e) Interrupt - steh' ich drauf.
Wir können die REU am Ende einer Aktion und/oder bei Eintreten eines Fehlers einen Interrupt generieren lassen. Dazu beschreiben wir unsere Register wie gewohnt. Nur $DF09 bleibt diesmal nicht Null. Wir können schreiben:
POKE 57097,192 : Interrupt nach Ende der Aktion
POKE 57097,160 : Interrupt NUR bei VERIFY-Error
BITTE BEACHTET, DAß $DF00 VOR JEDER AKTION EINMAL AUSGELESEN WERDEN SOLLTE, UM ES ZURÜCKZUSETZEN!
Nur so können wir sicher feststellen ob ein Interrupt von der REU generiert wurde.
Unsere Interruptroutine ($0314/15) haben wir natürlich bereits verbogen
bit $df00 ;Kommt Interrupt von REU?
bmi vonreu ;Ja, dann vonreu
jmp $ea31 ;sonst Systeminterrupt
vonreu:
bvs error ;Bit 6=1 Verify Error!
... ;Fehlerlose Aktion ist
;zu Ende
error:
... ;Bei VERIFY trat ein
;Fehler auf
f) Adress Control, eine fesselnde Versuchung.
Das letzte Register bietet noch einmal ein Schmankerl. Normalerweise erhöht der REC beim Datentransfer die Zähler in $DF07/08 (Die Anzahl der zu übertragenden Bytes, die wir ja vorher setzten). Wir können nun folgendes festlegen:
- belasse Adresse im C64
- belasse Adresse in der REU
- belasse beide Adressen.
Der Sinn? Nun, bei gleicher Adresse im C64 können wir die REU löschen, ohne gleich ewig viel RAM im Computer vollzuschreiben. Wir bringen den Wert, der in die REU soll in eine einzige C64-Adresse, setzen die Register darauf, Anzahl der zu übertragenden Bytes auf $FFFF (eine Bank), aktivieren Autoload, fixieren den Byte-Counter in $DF0A (Moment, gleich...) und starten die Übertragung mit dem STASH-Kommando.
Nun erhöhen wir den Bank-Zeiger ($DF06) so lange bis die gesamte REU gefüllt ist. Dank AUTOLOAD brauchen wir die übrigen Register nicht neu zu beschreiben. Umgekehrt läßt sich natürlich auch (blitzschnell!) ein beliebiger Bereich im C64 mit einem Wert aus der REU füllen.
Und eine feste Adresse nur im C64? Commodore sagt dazu, daß man damit den Inhalt der REU an eine IO-Adresse übergeben kann. Z.B. einen CIA-Port, an dem eine Floppy hängt, oder irgendein Gerät am Userport. Die Anwendungsmöglichkeiten sind groß. Man muß nur ein Gerät finden, daß 1 MB pro Sekunde Datendurchsatz verkraften kann. :)
Wir schreiben nach $DF0A:
POKE 57098,0 alles bewegt sich
POKE 57098,64 REU-Counter steht
POKE 57098,128 C64-Counter steht
POKE 57098,192 nichts bewegt sich
g) Zum Abschluß (Ja, wir sind fertig!) noch eine Tabelle der möglichen Kommandos für $DF01. Bedenkt, daß es durch die drei reservierten, nutzlosen Bits (Bit 6,3,2) noch viel mehr Kombinationen gibt, allerdings mit gleicher Funktionalität.
(A+ mit AUTOLOAD, A- ohne AUTOLOAD)
(F+ mit $FF00-Verzögerung, F- ohne)
KOMMANDO A+F+ A+F- A-F+ A-F-
-------------------------------
STASH 236 252 204 220
FETCH 237 253 205 221
SWAP 238 254 206 222
VERIFY 239 255 207 223
h) Und ganz zum Schluß die Adresse, bei der man noch ungebrauchte REUs 1764 bekommen kann
(Dies ist keine Werbung und ich verdiene nichts daran):
Hier stand die Adresse. Es war die des GEOS User Clubs.
Aber die haben schon lange keine REUs mehr.
Angebote (Preise Stand August 1996)
REU 1764 256 KB 70,- DM
REU 1764 512 KB 120,- DM
REU 1764 1 MB 300,- DM
REU 1764 2 MB 700,- DM
10) Ade
Das war alles und noch mehr über die REU. Die Beispiele aus diesem Artikel sollen zu eigenen Experimenten anregen.
Viel Freude dabei wünscht euch
Willcox