SuperCPU durchleuchtet - Folge 5
Nachdem es in der vorigen Ausgabe eine geballte Ladung an Informationen gab,
wenden wir uns heute einem (zunaechst) weniger komplexen Thema zu: Wir werden
neue Adressierungsarten kennenlernen, die der 65816-Prozessor in der
20MHz-Karte von CMD zu bieten hat. Ausserdem lernen wir ein paar neue Befehle
kennen, die das Leben erleichtern!


Bei Adressierungsarten denkt mancher bestimmt noch an die Zeit zurueck, wo er
Assembler gelernt hat (vielleicht ist es gar nicht so lange her?). Da wurde
mit Worten wie "indirekt-y-indiziert" um sich geschmissen, und es dauerte
eine Weile, bis man sich an die gebraeuchlichsten Adressierungsarten gewoehnt
hat.

Mehr davon

Beim 65816, der ja die direkte Weiterentwicklung des 6510 im C64 darstellt,
sind einige neue Adressierungsarten hinzugekommen. Fangen wit gleich mit
einer etwas ungewoehnlichen an: Die meisten kennen sicher den Befehl
JMP($A000), er steht im ROM und springt nicht nach $A000, sondern an die
Adresse, die im $A000 und $A001 steht. Fuer Spruenge ueber Vektoren ist
dieser Befehl gut zu gebrauchen, viele benutzen aber in eigenen Programmen
lieber selbstmodifizierenden Code an dieser Stelle und aendern gleich direkt
die zwei Byte hinter dem JMP. Beim 65816 gibt es aber nun auch folgende
Moeglichkeit: JMP($7000,X) ! Ist in X eine 2, wird zu der Adresse gesprungen,
die in $7002 und $7003 steht! Damit ist gleich klar, wofuer man diese neue
Adressierungsart benutzen kann: Sprungtabellen! Doch natuerlich muss man
aufpassen, denn das X-Register sollte man immer zweimal erhoehen, um nicht
eine falsche Adresse aus High-Byte eines Tabelleneintrages und Low-Byte des
naechsten zu bekommen. Uebrigens funktioniert diese Adressierungsart nicht
nur bei JMP, sondern es gibt sie auch bei JSR - z.B. JSR($7000,X). Listing 5.1
zeigt, wie's geht.

Weniger ist mehr

Im letzten Kursteil hatten wir ja besprochen, wie wir die Zeropage, die beim
65816 Direct Page genannt wird, in beliebige Speicherbereiche legen koennen.
Um dem Coder aber zusaetzlich noch einen (kleinen) Geschwindigkeitsgewinn zu
geben und eventuell noch ein Register freizuhalten, wurde fuer die Direct
Page (Zeropage) auch eine neue Adressierungsart eingefuehrt. Erfahrene
Programmierer koennen sich vielleicht schon denken, worum es geht: Will man
ueber einen Pointer, der in der Zeropage steht, auf einen Speicherbereich
zugreifen, geschieht dies ja wie bekannt z.B. ueber LDA($FD),Y. Oft ist es
jedoch so, dass man aus verschiedenen Gruenden nach jedem gelesenen Byte den
Zeiger weitersetzt (also $FD und gegebenenfalls $FE erhoeht) - womit das
Y-Register immer 0 bleibt und auch bleiben muss, damit auf die richtige
Adresse zugegriffen wird. Der andere Fall ist, dass man nur auf das eine Byte
(oder beim 65816 auch auf zwei Byte) zugreifen will, auf das der Pointer in
der Zeropage zeigt. Auch hier ist es laestig, jedesmal das Y-Register mit 0
laden zu muessen und es eventuell vorher noch irgendwohin zu retten. Darum
gibt es ab jetzt die Adressierungsmoeglichkeit: LDA($FD) - ohne alles! In
Listing 5.2 sieht man, wie einfach das funktioniert.

Relative Spruenge

Bei Spruengen kennen wir zwei Moeglichkeiten: Entweder den absoluten oder den
relativen Sprung. Der relative ist immer ein Sprung "von hier aus" einige
Byte zurueck oder vorwaerts (127 Bytes Entfernung). Dieser Abstand wird mit
dem Befehl gespeichert, so dass wir nur zwei Bytes pro Branch-Befehl haben,
der Disassembler macht immer die richtige Adresse draus. Ein altes Leid ist
das Gefuehl des Unbehagens, wenn man mit JMP eine Sequenz von ein paar Byte
ueberspringen muss. Oft denkt man sich, ein BNE tut's doch auch - das
Zeroflag duerfte doch eigentlich nie gesetzt sein an dieser Stelle... das
klappt auch meistens - aber wenn nicht, ist die Suche nach dem Fehler extrem
gross. Deshalb gibt's beim 65816 jetzt endlich den BRA - BRanch Always. Er
springt auf jeden Fall, ist aber ansonsten wie jeder andere Branch relativ
zum Program-Counter. Doch damit nicht genug: Den JMP-Befehl kann man von nun
an getrost ganz vergessen! Sollte der BRA mit seiner maximalen Sprungweite
von 127 Byte naemlich einmal nicht reichen, nimmt man einfach den BRL -
BRanch always Long. Dies ist zwar wie der JMP wieder ein 3-Byte-Befehl,
jedoch wird auch hier das Sprungziel relativ zur aktuellen Befehlsadresse
abgelegt, was durchaus von Vorteil sein kann! 

Bitte ein Bit

Will man einzelne Bits in einem Byte, oftmals beispielsweise ein
VIC-Register, setzen oder loechen, wurde dies bisher ueber die Befehle LDA -
ORA (oder AND) - STA erledigt. Drei Befehle, nur um ein einziges Bit zu
aendern! Das hat nun ein Ende: Die SuperCPU bietet hier zwei neue Befehle.
Einer davon ist TSB - Test and Set Bits against accumulator. Was heisst das
im Klartext? Ganz einfach: Man holt sich mit LDA ein Byte in den Akku, in dem
alle zu setzenden Bits auf 1 sind, alle anderen sind 0. Dann kommt ein TSB
Adresse, wodurch automatisch eine OR-Verknuepfung ausgefuehrt wird: Alle
Bits, die im Akku gesetzt sind, werden nun auch im Speicher gesetzt, alle
anderen bleiben unberuehrt. Zusaetzlich wird noch eine andere Operation
ausgefuehrt: Der Akku wird mit der Speicherstelle verANDet - das Ergebnis
wird jedoch nicht gespeichert (genau wie beim BIT-Befehl), lediglich das
Zero-Flag wird beim Ergebnis 0 gesetzt.

Das Gegenstueck ist der TRB-Befehl (Test and Reset Bits against accumulator).
Auch hier muss der Akku mit einem Wert geladen werden. Diesmal sollten alle
die Bits im Akku gesetzt sein, die in der Adresse hinter dem TRB geloescht
werden sollen. Achtung: Dies ist genau umgekehrt wie bei dem AND-Befehl -
dort muessen ja die zu loeschenden Bits auf 0 sein, die nicht zu loeschenden
auf 1. Beim TRB-Befehl jedoch wird es genau andersherum gehandhabt. Man muss
sich fuer beide Befehle nur merken, dass die Bits, die man setzen bzw.
loeschen will, im Akku auf 1 stehen muessen. Beim TRB wird ebenfalls noch die
oben bereits erwaehnte zweite Operation ausgefuehrt (ein wirkliches AND, was
jedoch nur das Zero-Flag beeinflusst, nicht den Speicher). In Listing 5.3 wird
die Funktionsweise dieser Befehle noch einmal veranschaulicht.

Du bist eine Null!

Im Gegensatz zu Entwicklern anderer Prozessoren, die zahlreiche so gut wie
nie brauchbare Befehle in ihre CPU's einbauten und sie zehn Jahre spaeter als
zukunftsweisende Technologie an den Mann bringen, haben sich die Designer des
65816 schon ein paar Gedanken gemacht. Sie stellten fest, dass einer der am
allerhaeufigsten in den Speicher geschriebenen Werte die Null ist. Wer seine
Sourcecodes durchsieht, wird wahrscheinlich feststellen, dass dies durchaus
stimmt. Deshalb gibt es im 65816 einen speziellen Befehl, der nichts
weiter tut, als eine Null zu speichern: STZ. Damit kann man, ohne erst ein
LDA #$00 (oder LDA #$0000) schreiben zu muessen und damit den Akku-Inhalt zu
verlieren, mal eben schnell eine oder mehrere Speicherstellen auf Null
setzen. Doch Achtung: Der STZ arbeitet nicht mit allen Adressierungsarten.
Zugelassen sind lediglich STZ addr, STZ dp, STZ addr,X und STZ dp,X (dp steht
hier fuer Direct Page). Also nicht wundern, wenn der Assembler bei einem STZ
addr,Y nicht mitspielen will.

Das war erst der Anfang

Im naechsten Kursteil gehen wir dann wieder richtig zur Sache: Es gibt da
naemlich auch noch Adressierungsarten, die sich mit dem Stack befassen.
Dieser hat beim 65816 sozusagen eine Dimension mehr - es lassen sich
interessante Dinge damit realisieren...





(w) Malte Mundt
©1999 Go64 Redax! & Count Zero/SCS*TRC for all HTML Stuff

[ Zum 4. Teil ][ Zum Index ][ Zum 6. Teil ]