Assembler-Kurs Teil 7 Bevor wir uns den ROM-Routinen des C64 zuwenden, werden noch die vier Bit-Verschiebebefehle ASL, LSR, ROL und ROR erklärt. Diese Befehle benötigen wir erst im Kursteil 9 bei der Multipli- kation und Division von Ganzzahlen. Trotzdem sollen diese Befehle schon jetzt behandelt werden, da Sie in der Folge 9 genug Probleme mit dem Verständnis der Fließkomma-Zahlen haben werden und nicht noch zusätzlich mit neuen Befehlen konfrontiert werden sollen. Die Verschiebebefehle
ASL (Arithmetic Shift Left) ---------------------------
Bei diesem Befehl wird der gesamt Akku- inhalt, oder der Inhalt der angegebenen Speicherstelle bitweise nach links ver- schoben. Das Bit 7 wird in das Carry-Bit ausgelagert, in Bit 0 des Bytes wird eine 0 eingefügt.
7 6 5 4 3 2 1 0 Carry <= * * * * * * * * <= 0
Ein einmaliges Linksverschieben ent- spricht einer Verdoppelung der ur- sprünglichen Zahl.
Beispiel: LDA #$19 ASL STA $1000
$19 entspricht der binären Bitfolge: 00011001. Ein ASL führt nun zu 00110010 ($32) und einer 0 im Carry-Bit. Das Ergebnis der Verschiebung wird in der Speicherstelle $1000 abgelegt. Aber neben der Möglichkeit der Ver- doppelung einer Zahl kann man mit ASL auch bequem die Bits einer Speicher- stelle über das Carry-Bit testen. Es werden das Negativ- und das Zero-Flag beeinflußt. Der Befehl ASL bietet folgende Adressierungsmöglichkeiten:
ASL Akku-orientiert ASL $1000 absolut ASL $1000,X absolut X-indiziert ASL $FA Zeropage-absolut ASL $FA,X Zeropage-abs. X-indiziert
LSR (Logical Shift Right) -------------------------
LSR bildet das Gegenstück zu ASL. Das betroffene Bit wird nun nach rechts geschoben. Dabei gelangt das bit 0 in das Carry-Bit und in Bit 7 wird eine 0 eingesetzt.
7 6 5 4 3 2 1 0 0 => * * * * * * * * => Carry Beispiel: LDA #$19 LSR STA $1000
Aus der Bitfolge 00011001 wird durch LSR ein 00001100. Außerdem enthält das Carry-Bit jetzt die links aus dem Byte geschobene 1. Das Ergebnis wird wieder in der Speicherstelle $1000 abgelegt. LSR hat in diesem Fall die dezimale Zahl 25 ($19) ganzzahlig halbiert. Das gesetzte Carry-Bit signalisiert dabei, daß ein Rest aufgetreten ist (25 :2 = 12 Rest 1). LSR erlaubt die selben Adressierungs- arten und beeinflußt die gleichen Falggen wie der ASL-Befehl.
ROL (ROtate Left) -----------------
Der ROL-Befehl hat große Ähnlichkeit mit dem ASL, nur daß das Byte jetzt nicht mehr nur verschoben wird, sondern um 1 Bit rotiert. Wie auch bei ASL landet das Bit 7 im Carry. Das Carry-Bit wird anschließend in Bit 0 übertragen. Somit ist das Bit 7 schließlich in Bit 0 gelangt.
7 6 5 4 3 2 1 0 Carry <= * * * * * * * * <= Carry Beispiel: LDA #$B1 ROL STA $1000
In den Akku wird die Bitkombination 10110001 geladen. Nach dem ROL befindet sich der Wert 01100011 ($63) im Akku, der in die Speicherstelle $1000 abgelegt wird. Das Carry-bit enthält ebenfalls eine 1.
ROR (ROtate Right) ------------------
Wie nicht anders zu erwarten war, ist ROR wieder das Gegenstück zu ROL. Jetzt wird das Byte nicht um ein Bit nach links, sondern nach rechts rotiert. Es befindet sich daher Bit 0 im Carry. Der Inhalt des Carry-Bits rotiert nun in Bit 7 hinein.
7 6 5 4 3 2 1 0 Carry => * * * * * * * * => Carry Beispiel: LDA #$B1 ROR STA $1000
Auch für ROR wird das Beispiel durchge- führt. Aus 10110001 wird nach ROR die bitfolge 11011000. Das Carry-Bit ist auch in diesem Beispiel gesetzt. Die zuletzt besprochenen Befehle lassen dieselben Adressierungsarten wie der ASL-Befehl zu, und auch sie verändern die Flaggen N und Z.
ROM-Routinen ------------
Unsere Assembler-Programme stehen immer im RAM (Random Access Memory), dem Lese-/Schreib-Speicher. In das ROM (Read Only Memory) können wir nicht hinein- schreiben, es kann nur gelesen werden. Folglich sind die oben erwähnten ROM- Routinen einige gegebene unterprogramme, die wir in unsern eigenen Assembler- Programmen verwenden können. Der Sinn der Benutzung dieser ROM- Routinen soll Ihnen am Beispiel des "Bildschirm löschens" verdeutlicht werden: Bisher benötigten wir eine Schleife, die den gesamten sichtbaren Bildschirm- bereich mit dem SPACE-Zeichen " " voll- gePOKEd hat. Es war also ein erheblicher Programmieraufwand erforderlich. Nun geht das Ganze aber viel kürzer. Wir springen einfach mit JSR ein ROM-Unter- programm an, das das Bildschirmlöschen für uns übernimmt. Ein "Clear Screen" wird jetzt einfach mit JSR $E544 ausgeführt. Übrigens werden alle ROM-Routinen mit einem JSR angesprungen, da diese allesamt mit RTS enden. Einige ROM-Routinen benötigen vor ihrem Aufruf gewisse Informationen, ohne die sie nicht fehlerfrei arbeiten können. Zum Beispiel braucht die Routine zum Setzen des Cursors die Zeilenposition im X-Register und die der Spalten im Y- Register.
LDX #$00 LDY #$08 JSR $E50C
Dieses Programm setzt den Cursor in der Zeile 0 auf die Spalte 8. Das folgende Programm gibt den ASCII- Text an der aktuellen Cursorposition aus
LDA #$00 LDY #$C1 JSR $AB1E
Der auszugebende Text für diese Routine muß im Speicher an der Stelle $C100 beginnen, und mit einem Byte $00 enden. Als Zeiger auf diese Textstelle fun- gieren hierbei der Akku (niederwertiges Byte der Adresse) und das Y-Register (höherwertiges Byte). Wie Sie einen ASCII-Text direkt im Speicher ablegen können, verrät Ihnen das Handbuch Ihres Assemblers. Oft gibt es dafür einen Befehl der Art C100 .ASC "beispieltext" Der Text liegt dann folgendermaßen im Speicher:
C100 42 45 49 53 50 49 45 4C beispiel C108 54 45 58 54 00 00 00 00 text
Eine weitere wichtige Routine ist die Tastaturabfrage JSR $FFE4. Hierbei steht der ASCII-Code der gedrückten Taste im Akkumulator.
Das Beispielprogramm C000 JSR $FFE4 C003 BEQ $C000 überprüft, ob irgendeine Taste gedrückt wurde. In BASIC hätten wir 10 GET A$ 20 IF A$ = "" THEN 10 geschrieben.
Natürlich kann ich Ihnen in diesem Kurs nicht alle verfügbaren ROM-Routinen vor- stellen. Wenn ich aber Ihr Interesse daran geweckt habe, dann sollten Sie sich ein Buch zulegen, das "dokumentierte ROM-Listings" enthält. Aber wo genau liegt eigentlich der ROM- Bereich im Speicher? Wir haben bis jetzt von $AB1E bis $E50C aufgerufen. Bei $C000-$CFFF liegt aber ein RAM-Bereich, den wir schon oft genutzt haben. Es muß daher mehr als nur einen ROM-Bereich geben. In der Tat gibt es 3 unterschiedliche ROM-bereiche. Von $A000-$BFFF liegt das ROM des BASIC-Interpreters. Dieser Interpreter sorgt dafür, daß Sie gleich nach dem Einschalten des Computers das BASIC verfügbar haben. Zwischen $D000- $DFFF befinden sich die I/O-Bausteine, die für die Ein- und Ausgaben verantwortlich sind. Ab $E000 bis zum Ende des Speichers $FFFF liegt das Betriebssystem-ROM. Speicherbelegungsplan des C64:
$FFFF ------------------------------ |Betriebssystem| RAM | $E000 ---------------------------------- | I/O | Zeichensatz |RAM| $D000 ---------------------------------- | RAM | $C000 ------------------------------ | BASIC-ROM | RAM | $A000 ------------------------------ | | | RAM | | | $0800 ---------------- | (RAM) | $0000 ----------------
Der mit "Zeichensatz" gekennzeichnete Bereich enthält den Zeichensatz- Generator (character generator), den ich im Kursteil 8 mit der Erstellung selbst- definierter Zeichen näher erläutern werde. Wenn Sie den Speicherbelegungsplan ansehen, stellen Sie fest, daß einige bereiche mit derselben Adresse mehrfach belegt sind. So liegt z.B. von $E000 bis $FFFF nicht nur das Betriebssystem, "darunter" befindet sich auch noch ein RAM-Bereich. Ähnlich verhält es sich mit dem Bereich von $D000-$DFFF, der sogar dreifach belegt ist. Aber wie kann man zwischen den mehrfach belegten bereichen auswählen? Dazu dient die Speicherstelle $01, der sogenannte Prozessorport. Je nachdem, welcher Wert in dieser Speicherstelle steht, verändern sich die Zugriffs- möglichkeiten auf den Speicher. Als Assembler-Programmierer könnten wir zum Beispiel mit
LDA #$36 STA $01
das gesamte BASIC abschalten un das darunterliegende RAM für unsere Zwecke nutzen. Wir hätten somit einen durchgehenden RAM-Speicher von $0800 bis $CFFF geschaffen. Leider können wir aber nicht mehr auf die ROM-Routinen des BASIC-Interpreters zugreifen.
LDA #$37 STA $01 stellt den Ausgangszustand wieder her und schaltet das BASIC-ROM an.
$01 $A000-$BFFF $D000-$DFFF $E000-$FFFF ----------------------------------------
$37 BASIC I/O ROM $36 RAM I/O ROM $35 RAM I/O RAM $34 RAM RAM RAM $33 BASIC Charset ROM $32 RAM Charset ROM $31 RAM Charset RAM $30 RAM RAM RAM
Diese Tabelle des Prozessorports zeigt Ihnen die Möglichkeiten auf. Auf den ersten Blick wirkt das mit der Mehrfachbelegung un dem Umschalten zwischen Bereichen alles etwas umständlich. Anders geht es aber nicht. Mit unserem maximal 2 Byte langem Adressteil (z.B. LDA $FFFF) können wir nur den Bereich von $0000-$FFFF, also 64 KByte andressieren. Würde man alle mehrfach belegten Bereiche hintereinander schreiben, käme man aber auf einen Speicherbereich von 64 KByte + 24 KByte = 88 KByte. Als praktischen Anschauungsunterricht laden Sie nun am Besten das Beispiel- programm aus dem Menü: ASSEMBLER-KURS 7.
(rt/wk)