November 1995
Februar 2015

Meinungen, Programme und Hardware

Programmprojekte

Autor: Sven Friedrichs



Komfortables Bankswitching mit dem C128

Bankswitching - die Spezialität des C128! Doch wer kommt damit schon problemlos klar?

In den Anfangszeiten als der nicht belegte absolute RAM- Speicherbereich ($1300-$17ff) für die ersten kleinen Pro-gramme noch ausreichend war, konnte man das Bankmanagment getrost links liegen lassen. Doch je mehr das Programm über diesen Bereich hinauswuchs, desto interessanter und leider auch umso komplizierter wurde dieses Thema. So mancher Programmcode verlängerte sich durch Nutzung vorhandener Kernal-Routinen (JSRFAR) enorm.

Würde man beispielswiese einen Programmteil in einer anderen Bank über JSRFAR anspringen wollen, so fielen insgesamt 21 Bytes an. Dies ist jedoch nur unter der Voraussetzung der Fall, daß alle fixen und notwendigen Bytes für JSRFAR bereits gesetzt wurden:

pha 1 ; sichern des Akkus
lda ~jsrbank 2 ; Konfigurationsbyte für Sprung
sta $06 2
lda ~<jsradr 2 ; Lowbyte der Sprungadresse
sta $07 2
lda ~>jsradr 2 ; Highbyte der Sprungadresse
sta $08 2
pla 1 ; holen des Akkus
jsr jsrfar (3) ; Aufruf von JSRFAR mit anschl. Sprung
ldx $07 2 ; holen des neuen X-Register
lda $06 2 ; holen des neuen Akkus
; Y-Register bereits im Prozessorreg.
weiter im Programm

Es kämen also 18 zusätzliche Bytes hinzu, nur um eben kurz mal eine BASIC-Routine aus einem Speicherbereich aufzurufen, der unter dem BASIC-ROM ($4000-$bfff) liegt. Dieser Zustand war untragbar und im Rückblick auf die PRIMM- Routine kam die Idee einer ganz ähnlichen Routine, jedoch mit der Funktion, die JSRFAR-Routine zu verbessern. Hieraus entstand eine relativ kleine Routine namens JIMM, die anstatt 18 zusätzlicher Bytes lediglich drei(!) abknöpft. Der Aufruf (z.B. $fb000) geschieht wie folgt:

jsr jimm (3) ; (JIMM=$0d00)
.byte $00 1 ; Wert vom CR - Konfigurationsregister
.byte $00 1 ; Lowbyte der Ziel-Adresse
.byte $b0 1 ; Highbyte der Ziel-Adresse
weiter im Programm

Bereits nach einigen Programmverzweigungen zu anderen Banks hat sich die kleine Routine amortisiert. Zudem ist sie sehr einfach und läßt übersichtliche Quellcodes zu. Fortan können BASIC-Routinen auch von Programmen aufgerufen werden, die unterhalb des BASIC-ROMs liegen, ohne dabei wertvollen Speicherplatz zu verschwenden.

Eine weitere Verbesserung zu JSRFAR wurde dahingehend unternommen, daß auch Programme unter dem Kernal-ROM ($e000-$ffff) die verschiedenen Banks beliebig anspringen können. JSRFAR allein erlaubt diese Besonderheit nicht, da es ungeschickterweise auf eine Kernal-Routine (jsr $ff6b) zugreift, die anhand eines Bankindexes das Byte für das Konfigurationsregister ausliest.

Zu finden ist dieses Manko in der von JSRFAR angesprun-genen Routine JMPFAR. Diese liegt ab $02e3 als Kopie im Speicher und sieht wie folgt aus:

02e3 a2 00 ldx ~$00 ; Adresse und Status auf den
02e5 b5 03 lda $03,x ; Stack legen (für Sk1rtiSk0)
02e7 48 pha
02e8 e8 inx
02e9 e0 03 cpx ~$03
02eb 90 f8 bcc $02e5
02ed a6 02 ldx $02 ; !Zum Konfigurationsindex
02ef 20 6b ff jsr $ff6b ; !Konfigurationswert holen
02f2 8d 00 ff sta $ff00 ; !und aktivieren
02f5 a5 06 lda $06 ; Registerwerte laden
02f7 a6 07 ldx $07
02f9 a4 08 ldy $08
02fb 40 rti ; Aufruf des Programms ...

(Quellcode aus dem Buch zum Top-Ass plus für den C128)

Über die Speicherstelle $02, die bei $02ed ins X-Register geladen wird, gibt der Programmierer einen Index von 0 bis 15 an, dessen Wirkung in Tabelle 1 erläutert wird. Diese Tabelle befindet sich jedoch nur im ROM ($f7f0-$f7ff)! Dabei wird anhand des Indexes der Tabellenwert ($ff6b) geholt, der dann mit "sta $ff00" die eigentliche Konfiguration angibt. Das geht natürlich nur, wenn vorher das Kernal-Rom eingeschaltet wurde. Von einem Programm, das unter dem Kernal liegt, ist das jedoch nicht möglich: Es käme zum Absturz.

Das Ganze könnte einst der Vereinfachung des Memorymanage-ments gedient haben - jedoch ohne rechten Erfolg. Daher ist es sinnvoller, die direkten Werte für die Konfiguration über $ff00 (CR) zu nutzen. Die Anwendung des Prinzips wird dank der übersichtlichen Tabelle 2 über das Konfigurationsregister (CR) nicht schwerer fallen, als jene mit Index.

Bei der Nutzung von JIMM braucht daher kein Index mehr ver-wendet zu werden! Da JMPFAR und JSRFAR von Betriebssystemroutinen verwendet werden, konnte der Verweis auf die Tabelle (bei $02ef) leider nicht mit NOPs überschrieben werden. Es wurde deshalb eine neue JSRFAR-Routine programmiert, die das Problem umgeht und außerdem ein weiteres beseitigt.

Wer die JSRFAR-Routine kennt, wird wissen, daß es nicht möglich gewesen ist, den Inhalt des Carry-Flags zu ändern. Weil aber Routinen wie die Windows-Funktion auf diesen Zustand angewiesen sind, besitzt JIMM nun ein spezielles Handling, um sich das Carry-Flag zu merken.

JSF V1.1 - das Zusammenspiel wichtiger Routinen

Neben dem JSR-Befehl für verschiedenen Banks wären für ein komfortables Programmieren auch noch Befehle zum Laden und Speichern von Speicherinhalten nötig. Mit den vom Betriebs-system zur Verfügung gestellten Routinen FETCH und STASH war der Programmierer allerdings dazu gezwungen, einen ähnlich hohen Aufwand zu betreiben wie bei JSRFAR.

JSF bricht auch diese Grenze und besteht aus den Routinen JIMM ($0d00) und zudem SIMM ($0d03) und FIMM ($0d06). SIMM speichert den aktuellen Inhalt des AKKUs in eine Adresse, wo-hingegen FIMM das Pendant hierzu darstellt und genau den umgekehrten Weg geht.

Die Anwendung gleicht der von JIMM. Die Zieladresse wird genauso wie beim STA/LDA-Befehl abgelegt: zuerst das Lowbyte, dann das Highbyte. Ein Indexregister gibt es ebenfalls nicht, somit ist eine nahezu grenzenlose Lage des Aufrufs möglich:

jsr fimm ; hole Speicherinhalt von $8000 in Bank 1
.byte $7f ; CR - direkter Inhalt für totale RAM-Bank 1
.byte $00 ; zuerst das Lowbyte
.byte $80 ; dann das Highbyte
sta $6000 ; normaler STA-Befehl

lda $6001 ; normaler LDA-Befehl
jsr simm ; sichere Speicherinhalt in $8001 in Bank 1
.byte $7f ; CR - direkter Inhalt für totale RAM-Bank 1
.byte $01 ; zuerst das Lowbyte
.byte $80 ; dann das Highbyte

JSF V1.1 - Lageplan

Vom Programmierer wurde JSF V1.1 ersteinmal an die Adresse $0d00 im gemeinsamen Speicherbereich gelegt. Daran ist jedoch niemand gebunden und wer den Top-Ass für den C128 besitzt, kann sich auch einen anderen Bereich innerhalb der gemeinsamen Area suchen. Dazu wird einfach die BASE-Adresse und die CODE-Adresse im Quellcodelisting: "JSF V1.1.SRC" auf den neuen Wert angepaßt.

Anschließend erfolgt die Assemblierung. Danach müßten aber auch die Beispiellistings geändert werden, weil sie sonst nicht mehr funktionieren.

Die Beispiellistings haben es allerdings in sich. Sie liegen an allen möglichen und unmöglichen Speicherplätzen. Gezielt wurden Speicherbereiche ausgesucht, die vor JSF so gut wie ungenutzt waren, um zu demonstrieren, was diese knapp 140 Byte lange Routine an Vorteilen bietet.

So hat sich "TEST JIMM" im Speicher ab $fe00 versteckt. Dabei werden die Routinen zum Setzen eines Windows ($c02d im BASIC-ROM) und die Ausgaberoutine: BSOUT ($ffd2 im Kernal- ROM) angesprungen.

"TEST SIMM" speichert eine kleine Botschaft aus Bank 0 in Bank 1 ab $8000. Es selbst befindet sich dabei unterm Kernal- ROM ab $e000 in Bank 0.

"TEST FIMM" holt die Einschaltmeldung aus dem BASIC-ROM und speichert sie im RAM der Bank 0 unterhalb des Kernals.

Q.E.D.: JSF ist seine Bytes wert und verdient es, von allen C128-Programmierern genutzt zu werden. Mir selbst ist es eine große Hilfe, läßt es mir doch mehr Zeit zum Programmieren und hält meine Quellcodes schön übersichtlich.

Start der Demonstrationen:

Testprogramm für JIMM:

bload"test jimm"
bank0:sysdec("fe00")
In einem Window (80-Zeichen-Modus) wird ein Text angezeigt.

Testprogramm für FIMM:

bload"test fimm"
bank0:sysdec("f000")
ab $f0bf in Bank 0 liegt die BASIC-Einschaltmeldung.

Testprogramm für SIMM:

bload"test simm"
bank0:sysdec("e000")
ab $e000 in Bank 1 steht: "hallo test..."

Wichtig für eigene Programme: Wenngleich sich der Speicher nun fast grenzenlos für den Programmierer aufgetan hat; es bleibt dennoch eine Einschränkung für den Bereich $ff00 bis $ffff in allen Banks vorhanden. Dieser Bereich enthält sehr wichtige Routinen und Kopien aus dem Betriebssystem, die für das Bankswitching unverzichtbar sind. Ein Überschreiben kann daher schnell zum Absturz führen!

Sourcen: Disk 15a-jsf-hp.D64

und Disk Image0008.D71

und Disk Image0014.D71



Inhalt

   
Zurueck