Adressierungsarten
Operanden von Assemblerbefehlen können unterschiedlich adressiert sein. Manche Befehle erlauben nur eine bestimmte Untermenge dieser Adressierungen
und in einigen Fällen wird durch Wechsel der Adressierungsart auch ein anderer Speicher angesprochen. Doch bevor wird hierauf
auf den folgenden Seiten näher eingehen,
betrachten wir zuerst die einzelnen Adressierungsmöglichkeiten des 8051 Assemblers.
Immediate Adressierung
Konstanten werden in Assembler durch eine vorangestellte Raute (#) gekennzeichnet. Die Angabe #40 ist also der Wert 40. Die Konstanten können
wie alle Werte in Assembler dezimal, hexadezimal oder binär angegeben werden. Bei hexadezimalen Zahlen wird der Zahl ein h und bei binären ein
b hinten angehängt. So sind #40, #28h und #101000b dieselben Werte.
Konstanten sind immediate adressiert. Das englische Wort „immediate“ bedeutet umgehend. Bei einem konstanten Operanden folgt dem
Befehlsbyte im ROM sofort der Wert des Operanden - der Wert muss also nicht in einem anderen Speicher „nachgeschlagen“ werden.
Direkte Adressierung
Bei der direkten Adressierung wird die Adresse einer Speicherzelle angegeben. Hier wird die Adresse angegeben ohne jegliches vorangestelltes Zeichen.
So ist 40h
die Speicherzelle, diese habe den Wert 10h
.
Mit mov A, 40h
wird der Wert dieser Speicherzelle (also 10h) in den Akkumulator kopiert, während
mov A, #40h
den Wert 40h
in den Akkumulator schreibt.
Direkt adressierbar ist das komplette SFR (80h bis FFh) und der untere Teil des internen RAMs (00h bis 7Fh).
Register Adressierung
Wird eins der Register R0 bis R7 als Parameter verwendet, so spricht man von Register Adressierung. Die Register liegen standardmäßig
an der Adresse 0 bis 7 im RAM und können auch durch direkte Adressierung ausgelesen oder verändert werden.
Worin liegt also der Unterschied zwischen Register Adressierung und direkter Adressierug?
Der Speicherort der Register kann verändert werden. Mit den Bits RS1 und RS0 (Bit 4 und 3 im PSW) wird festgelegt, wo die Register im RAM liegen.
RS1 | RS0 | Adresse von R0-R7 |
0 | 0 | 00h-07h |
0 | 1 | 08h-0Fh |
1 | 0 | 10h-17h |
1 | 1 | 18h-1Fh |
Somit speichert
mov R0, #3
den Wert 3 in Register 0. Dies kann an der Adresse
0h, 8h, 10h
oder
18h
sein.
Indirekte Adressierung
Bei der Register-Indirekten-Adressierung wird der Inhalt der Register R0 oder R1 als Adresse aufgefasst. Dies wird durch ein vorangestelltes
@ gekennzeichnet. Wird mov A, @R0
angegeben, so wird der Inhalt von R0
zur Adresse und der Inhalt derselben wird
in A kopiert.
Es wird hier also die Adresse indirekten angegeben, da man sie zuerst aus R0
auslesen muss, um den gewünschten
Speicherort zu ermitteln.
Beispiel 1:
mov | 20h, | #3 | ; Wert 3 in die Speicherzelle 20h schreiben |
mov | R0, | #20h | ; Den Wert 20h in R0 schreiben |
mov | A, | @R0 | ; In R0 steht 20h, deshalb wird der Wert aus 20h in A kopiert - also 3 |
Register indirekt lässt sich der komplette interne RAM adressieren und der Erweiterungsspeicher (von 00h bis FFh) adressieren.
Der große Vorteil der indirekten Adressierung ist, dass man mit dem gleichen Code einen ganzen Speicherbereich beschreiben kann.
Beispiel 2:
| mov | R0, | #20h | ; Den Wert 20h in R0 schreiben |
schleife: | mov | @R0, | #0FFh | ; den Wert 0FFh an @R0 schreiben |
| inc | R0 | | ; R0 um 1 erhöhen |
| cjne | R0, | #40h, schleife | ; So lange in R0 nicht 40h steht: weiter bei schleife |
Dieses Code-Fragment beschreibt den internen RAM von 20h bis 3Fh mit dem Wert 0FFh. Hierzu wird zuerst 20h in R0 geschrieben und dann
mittels indirekter Adressierung die Speicherzelle 20h beschrieben.
Danach wird R0 um 1 erhöht, somit wird beim nächsten Durchlauf der Schleife mit mov @R0, #0FFh
in die Speicherzelle 21h geschrieben.
Beim darauf folgenden Schleifendurchlauf in 22h,
Beim darauf folgenden Schleifendurchlauf in 23h,
...
Indirekte Adressierung über den DPTR
Wird auf den Erweiterungsspeicher zugegriffen, so reichen R0/R1 nicht aus, da der Erweiterungsspeicher 64kB groß sein kann. Es wird ein
16-Bit Register benötigt. Bei dem Befehl movx
kann deshalb auch über den Datapointer (DPTR
) indirekt adressiert werden
(z.B. movx A, @DPTR
). Näheres hierzu finden Sie bei den Erklärungen zum Befehlssatz.
Indirekte indizierte Adressierung
Hier setzt sich die Adresse aus der Summe zweier Werte zusammen. Bei @A+DPTR ergibt die Summe
aus DPTR und A die Adresse des Operanden. Bei @A+PC
wird der Programm-Counter
und der Akkumulator addiert. Dieser Wert wird als Adresse verwendet.
Beispiel: Im DPTR steht der Wert 202h und im Akku steht 04h so liest movc A, @A+DPTR
den Wert an der Stelle 202h+04h=206h
im ROM aus und schreibt in den Akkumulator.
Bitadressierung
Der 8051 bietet die Möglichkeit, einzelne Bits zu adressieren. Durch diese Eigenschaft sind viele Probleme einfacher und komfortabler zu lösen als
dies z.B. beim Z80 der Fall war (hier mussten einzelne Bits anhand von Masken mit and, or, xor, shift herausgeschnitzt werden).
Bitadressen kann man durch Byte-Adresse.Bit-Nummer (z.B. 80h.3) angeben. Da dies allerdings in eine 8-Bit Zahl umgewandelt (80h.3=83h)
wird, sind nicht alle Bytes im RAM bzw. SFR bit-adressierbar. Einzelne Bits lassen sich im RAM von den Bytes 20h bis 2Fh (Bitadressen 00h bis 7Fh)
und im SFR alle Speicherzellen, welche hexadezimal auf 0 oder 8 enden (80h, 88h, 90h, 98h, A0h, ...) mit den Bitadressen 80h bis FFh.