5) Die Praxis - Ein Beginn

Um die REU zu programmieren braucht man genaue Kenntnis der REC-Register, und ich laß keins davon aus, versprochen.
Für unser erstes kleines Experiment sind allerdings nur die folgenden wichtig: Der Speicher in der REU ist in Bänken zu je 64 KB organisiert. Maximal sind also ansprechbar:Für unser erstes kleines Beispiel kopieren wir den Bildschirm in die Bank 0 und holen ihn dort auch wieder zurück.
10 REC=50788
20 PRINTCHR$(147)"BILDSCHIRM 1"
30 POKE REC+2,0:POKE REC+3,4
40 POKE REC+4,0:POKE REC+5,0
50 POKE REC+6,0
60 POKE REC+7,0:POKE REC+8,4
70 POKE REC+9,0:POKE REC+10,0
80 POKE REC+1,252
100 PRINTCHR$(147)"BILDSCHIRM 2"
101 PRINT"TASTE FUER BILDSCHIRM 1"
110 POKE198,0:WAIT198,1
120 POKE REC+2,0:POKE REC+3,4
130 POKE REC+4,0:POKE REC+5,0
140 POKE REC+6,0
150 POKE REC+7,0:POKE REC+8,4
160 POKE REC+1,253
Das sieht jetzt sehr, sehr schlimm aus, ist es aber nicht. Wie Du weißt, liegt der Bildschirmspeicher gemeinhin bei 1024 ($0400) und ist einschließlich der Spritepointer 1024 ($0400) Bytes lang. Das Low-Byte von $0400 ist 00 und das Hi-Byte 04. Und damit kann man nun prima rechnen. Der Übersichtlichkeit wegen hier die wichtigsten Werte für das Kontrollregister 1 ($DF01): Es gibt natürlich noch einige mehr, aber seien wir geduldig.
Hier noch ein universelles Basic-Listing, das ihr in eure eigenen Programme einbauen könnt. Ihr müßt nur die Variablen an das Unterprogramm übergeben.
0  RE=57088
10 REM *** HAUPTPROGRAMM ***
20 CS=1024 : REM STARTADRESSE COMPUTER
21 RS=0    : REM STARTADRESSE REU
22 RB=0    : REM BANK IN DER REU
23 AB=1024 : REM ANZAHL DER BYTES
24 CO=252  : REM KOMMANDO STASH
28 GOSUB 10000
30 REM *** WEITER IM PROGRAMM ***
999 REM *** UNSERE SUBROUTINE ***
1000 POKE RE+3,CS/256
1001 POKE RE+2,CS-PEEK(RE+3)*256
1002 POKE RE+5,RS/256
1003 POKE RE+4,RS-PEEK(RE+5)*256
1004 POKE RE+6,RB
1005 POKE RE+8,AB/256
1006 POKE RE+7,AB-PEEK(RE+8)*256
1007 POKE RE+9,0:POKE RE+10,0
1008 POKE RE+1,CO
1009 RETURN
Dieses Beispiel kopiert, wie gehabt, den Bildschirm in die REU-Bank 0. Durch Übergabe anderer Werte an das Unterprogramm habt ihr die REU voll im Griff.

6) Eine weitere Überlegung

Wie wär's denn damit:
Ihr kennt das Problem, ihr habt ein Basic-Programm gecodet, groß und schön, es werden auch viele DATAs eingelesen. Das Programm nimmt seinen Verlauf und am Ende ist ein Neustart erforderlich (z.B. Game Over bei einem Spiel), damit die Variablen wieder die Anfangswerte haben. Also wieder alle DATAs einlesen.
Und warten.
Wir jedoch brauchen dies nicht, denn wir sind klug. Am Programmstart, nachdem alle Variablen ihren Wert besitzen, kopieren wir die ganzen Variablen einfach in die REU und bei einem Neustart holen wir alles wieder zurück. Wir übergeben an die obige Subroutine dazu folgende Werte:
20 CS=PEEK(45)+256*PEEK(46)
21 RS=0
22 RB=1    : REM ZUR ABWECHSLUNG BANK 1
23 AB=40960-(PEEK(45)+256*PEEK(46))
24 CO=252
25 GOSUB 10000
26 CS=45:RS=40960:RB=1:AB=8:CO=252
27 GOSUB 10000
Es wird der gesamte Speicher vom Beginn der Variablen bis zum Ende des Basic-Speichers in REU-Bank 1 übertragen. In Zeile 26 werden die Zeropageadressen der Variablengrenzen in die REU-Bank 1 ab 40960 gebracht. Um alle diese Werte zurückzubekommen ist an das Unterprogramm genau das gleiche abzuliefern, nur mit dem Kommandocode CO=253. Einfacher wäre es, den gesamten Speicher in die REU zu bringen, einschließlich der Zeropage, dann würde unser Programm aber gehörig durcheinandergeraten, da dann z.B. der Zeiger auf das nächste Element im Basic-Text nicht mehr stimmen würde, ebenso der Stack.
Und das ist nicht gut.
Habt ihr es schon bemerkt? Mit dieser Routine ist noch SEHR VIEL MEHR möglich als nur dies.
Denkt mal einen Schritt weiter.

7) Einen Schritt weitergedacht

Ihr schreibt an einem Dateiprogramm, z.B. um eure vielen Freundinnen zu verwalten. Und plötzlich reicht das RAM nicht!
Dann teilt es euch doch folgendermaßen auf: Das alles in Basic und blitzschnell!
Beachtet aber unbedingt dies: Alle jemals im Programm vorkommenden Variablen, und sei es nur eine pupsige Schleifenvariable, muß vor der ersten REU-Aktion schon definiert sein, zur Not halt mit einem Dummy, z.B.  X=0. Ansonsten verschieben sich die Variablen im Speicher und die Pointer zeigen auf ganz falsche Werte.
Die Variablen im Computer werden von denen in der REU natürlich überschrieben. Werte, die sich verändert haben und wichtig sind, z.B. AZ für die Anzahl der Freundinnen sollten vorher in Sicherheit gepoket werden, z.B. in den Kassettenpuffer.
Wenn ihr dies beachtet, dann könnt ihr Programme schreiben, wie noch nie jemand zuvor. Und jetzt denkt noch einmal einen Schritt weiter. Seht euch in der Rolle des Anwenders, der verschiedene Programme in verschiedenen Bänken der REU haben kann und im Direktmodus zwischen diesen hin und herwechselt. Eine Textverarbeitung, ein Sprite-Editor, ein Assembler, alles zusammen in der REU...
Günstigerweise befindet sich irgendwo ein Assemblerprogramm, das alles übernimmt und nur noch aufgerufen werden braucht.
Und das geht so:
£ba $010b       ;Diese Startadresse ist $010b=SYS 267
   lda #252
£by $2c         ;Diese Startadresse ist $010e=SYS 270
   lda #253
gemeinsam:
   sta werte
   jsr $aefd    ;prüft auf Komma
   jsr $b79e    ;holt Bank nach x
   stx werte+5  ;ab in Tabelle
   sei          ;kein Interrupt
   lda 1        ;Prozessorport
   pha          ;merken
   lda #$35     ;BASIC & Kernal aus
   sta 1
   ldx #$09     ;neun Werte
loop1:
   lda werte,x  ;laden und
   sta $df01,x  ;in REC speichern
   dex
   bpl loop1
   pla          ;alte Speicherkonfig.
   sta 1        ;wiederherstellen
   cli          ;Interrupt freigeben
   rts          ;Programmende
werte:
£by 252,1,8,0,0,0,$ff,$c7,0,0
Vorteil dieses Programms gegenüber RAMDOS von der Test/Demo-Disk: Es ist viel kürzer, es ist nicht nur schneller geladen (1 Block) sondern auch schneller in der Ausführung. Und es überlebt einen Reset völlig schadlos.
Ein Nachteil ist, daß gepackte Programme denselben Speicherbereich beanspruchen, unser Programm also überschreiben. Aber dagegen ist RAMDOS auch nicht gefeit.
Die Verfahrensweise ist folgende: Zuerst dieses Programm absolut (,8,1) laden. Danach die gewünschten Programme laden und nach jedem Programm
SYS267,Bank
eingeben. Soll das Programm in Bank 3, ist die Eingabe also:
SYS267,3
Um ein Programm zurückzuholen genügt ein:
SYS270,Bank
also zum Beispiel:
SYS270,3
Wird ein gepacktes Programm gestartet, so ist unser Programm bei Bedarf erneut zu laden. Die Daten in der REU bleiben davon unberührt! Mit dem was wir gelernt haben verstehen wir auch bereits, was geschieht: Wozu soll das nur alles gut sein?
Denkt doch mal nach. Ihr habt die REU im Port also kein Action Replay, Final Cartridge o.ä. Nun codet ihr ein Basic-Programm und wollt euch ein Directory ansehen. Und ihr habt kein Supra-Dos oder Jiffy-Dos.
Schade.
Doch die Qualen sind nun vorbei. Mit SYS267,0 das Programm in die REU geschaufelt, Directory geladen und begutachtet, und mit SYS270,0 die Mühen vieler Stunden wieder zurückgeholt. Für Basic-Coder ist dies ideal,
ABER
erkennt ihr's? Auf diese Art kann man nur 202 Blocks große Programme in die REU bringen. Schalten wir den IO-Bereich auf RAM, können wir dem REC ja keine Mitteilungen mehr machen. Oder doch?
Damit beschäftigen wir uns jetzt!

Gehe zu:
Seite 1 Seite 2 Seite 3 Druckerfreundliche Version Disk zum Kurs