Pfad: Home =>
AVR-Überblick =>
Programmiertechniken => Rechnen
Programmiertechnik für Anfänger in AVR Assemblersprache
Rechnen in Assemblersprache
Hier gibt es alles wichtige zum Rechnen in Assembler. Dazu gehören die
gebräuchlichen Zahlensysteme, das Setzen und
Rücksetzen von Bits, das Schieben und Rotieren, das
Addieren/Subtrahieren/Vergleichen und die
Umwandlung von Zahlen.
An Darstellungsarten für Zahlen in Assembler kommen infrage:
Die kleinste handhabbare positive Ganzzahl in Assembler ist das Byte zu je acht Bits.
Damit sind Zahlen zwischen 0 und 255 darstellbar. Sie passen genau in ein Register des
Prozessors. Alle größeren Ganzzahlen müssen auf dieser Einheit aufbauen
und sich aus mehreren solcher Einheiten zusammensetzen. So bilden zwei Bytes ein Wort
(Bereich 0 .. 65.535), drei Bytes ein längeres Wort (Bereich 0 .. 16.777.215) und
vier Bytes ein Doppelwort (Bereich 0 .. 4.294.967.295).
Die einzelnen Bytes eines Wortes oder Doppelwortes können über Register
verstreut liegen, da zur Manipulation ohnehin jedes einzelnes Register in seiner Lage
angegeben sein muss. Damit wir den Überblick nicht verlieren, könnte z.B. ein
Doppelwort so angeordnet sein:
.DEF dw0 = r16
.DEF dw1 = r17
.DEF dw2 = r18
.DEF dw3 = r19
dw0 bis dw3 liegen jetzt in einer Registerreihe. Soll dieses Doppelwort z.B. zu
Programmbeginn auf einen festen Wert (hier: 4.000.000) gesetzt werden, dann sieht das
in Assembler so aus:
.EQU dwi = 4000000 ; Definieren der Konstanten
LDI dw0,LOW(dwi) ; Die untersten 8 Bits in R16
LDI dw1,BYTE2(dwi) ; Bits 8 .. 15 in R17
LDI dw2,BYTE3(dwi) ; Bits 16 .. 23 in R18
LDI dw3,BYTE4(dwi) ; Bits 24 .. 31 in R19
Damit ist die Zahl in verdauliche Brocken auf die Register aufgeteilt und es darf mit
dieser Zahl gerechnet werden.
Zum Seitenanfang
Manchmal, aber sehr selten, braucht man auch negative Zahlen zum Rechnen. Die kriegt
man definiert, indem das höchstwertigste Bit eines Bytes als Vorzeichen
interpretiert wird. Ist es Eins, dann ist die Zahl negativ. Aus hier noch nicht ganz
einfach zu erklärenden Gründen stellt man in diesem Fall alle Zahlenbits
mit ihrem invertierten Wert dar. Invertiert heißt, dass -1 zu
binär 1111.1111 wird, die 1 also als von binär 1.0000.0000 abgezogen
dargestellt wird. Das vorderste Bit ist dabei aber das Vorzeichen, das signalisiert,
dass die Zahl negativ ist und die folgenden Bits die Zahl invertiert darstellen.
Einstweilen genügt es zu verstehen, dass beim binären Addieren von +1
(0000.0001) und -1 (1111.1111) ziemlich exakt Null herauskommt, wenn man von dem
gesetzten Übertragsbit Carry mal absieht.
In einem Byte sind mit dieser Methode die Ganzzahlen von +127 (binär: 0111.1111)
bis -128 (binär: 1000.000) darstellbar. In Hochsprachen spricht man von
Short-Integer. Benötigt man größere Zahlenbereiche, dann kann man weitere
Bytes hinzufügen. Dabei enthält nur das jeweils höchstwertigste Byte das
Vorzeichenbit für die gesamte Zahl. Mit zwei Bytes ist damit der Wertebereich von
+32767 bis -32768 (Hochsprachen: Integer), mit vier Bytes der Wertebereich von
+2.147.483.647 bis -2.147.483.648 darstellbar (Hochsprachen: LongInt).
Zum Seitenanfang
Die beiden vorgenannten Zahlenarten nutzen die Bits der Register optimal aus, indem sie
die Zahlen in binärer Form behandeln. Man kann Zahlen aber auch so darstellen, dass
auf ein Byte nur jeweils eine dezimale Ziffer kommt. Eine dezimale Ziffer wird dazu in
binärer Form gespeichert. Da die Ziffern von 0 bis 9 mit vier Bits darstellbar
sind und selbst in den vier Bits noch Luft ist (vier Bits = 0 .. 15), bleibt dabei
ziemlich viel Raum leer. Für das Speichern der Zahl 250 werden schon drei Register
gebraucht, also z.B. so:
| Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
| R16, Ziffer 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| R17, Ziffer 2 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
| R18, Ziffer 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Befehle zum Setzen:
LDI R16,2
LDI R17,5
LDI R18,0
Auch mit solchen Zahlenformaten läßt sich rechnen, nur ist es aufwendiger als
bei den binären Formen. Der Vorteil ist, dass solche Zahlen mit fast beliebiger
Größe (soweit das SRAM reicht ...) gehandhabt werden können und dass sie
leicht in Zeichenketten umwandelbar sind.
Zum Seitenanfang
Nicht ganz so verschwenderisch geht gepacktes BCD mit den Ziffern um. Hier wird jede
binär kodierte Ziffer in jeweils vier Bits eines Bytes gepackt, so dass ein Byte zwei
Ziffern aufnehmen kann. Die beiden Teile des Bytes werden oberes und unteres Nibble
genannt. Packt man die höherwertige Ziffer in die oberen vier Bits des Bytes (Bit
4 bis 7), dann hat das beim Rechnen Vorteile (es gibt spezielle Einrichtungen im AVR zum
Rechnen mit gepackten BCD-Ziffern). Die schon erwähnte Zahl 250 würde im
gepackten BCD-Format folgendermaäßen aussehen:
| Byte | Ziffern | Wert | 8 | 4 | 2 | 1 | 8 | 4 | 2 | 1 |
| 2 | 4,3 | 02 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 1 | 2,1 | 50 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
Befehle zum Setzen:
LDI R17,0x02 ; Oberes Byte
LDI R16,0x50 ; Unteres Byte
Zum Setzen ist nun die binäre (0b...) oder die headezimale (0x...) Schreibweise
erforderlich, damit die Bits an die richtigen Stellen im oberen Nibble kommen.
Das Rechnen mit gepackten BCD ist etwas umständlicher im Vergleich zum
Binär-Format, die Zahlenumwandlung in darstellbare Zeichenketten aber fast so
einfach wie im ungepackten BCD-Format. Auch hier lassen sich fast beliebig lange
Zahlen handhaben.
Zum Seitenanfang
Sehr eng verwandt mit dem ungepackten BCD-Format ist die Speicherung von Zahlen im
ASCII-Format. Dabei werden die Ziffern 0 bis 9 mit ihrer ASCII-Kodierung gespeichert
(ASCII = American Standard Code for Information Interchange). Das ist ein uraltes, aus
Zeiten des mechanischen Fernschreibers stammendes, sehr umständliches,
äußerst beschränktes und von höchst innovativen
Betriebssystem-Herstellern in das Computer-Zeitalter herübergerettetes
siebenbittiges Format, mit dem zusätzlich zu irgendwelchen Befehlen der
Übertragungssteuerung beim Fernschreiber (z.B. EOT = End Of Transmission) auch
Buchstaben und Zahlen darstellbar sind. Es wird in seiner Altertümlichkeit nur
noch durch den (ähnlichen) fünfbittigen Baudot-Code für deutsche
Fernschreiber und durch den Morse-Code für ergraute Marinefunker übertroffen.
In diesem Code-System wird die 0 durch die dezimale Ziffer 48 (hexadezimal: 30,
binär: 0011.0000), die 9 durch die dezimale Ziffer 57 (hexadezimal: 39, binär:
0011.1001) repräsentiert. Auf die Idee, diese Ziffern ganz vorne im ASCII
hinzulegen, hätte man schon kommen können, aber da waren schon die wichtigen
Verkehrs-Steuerzeichen für den Fernschreiber. So müssen wir uns noch immer
damit herumschlagen, 48 zu einer BCD-kodierten Ziffer hinzuzuzählen oder die
Bits 4 und 5 auf eins zu setzen, wenn wir deren ASCII-Code über die serielle
Schnittstelle senden wollen. Zur Platzverschwendung gilt das schon zu BCD geschriebene.
Zum Laden der Zahl 250 kommt diesmal der folgende Quelltext zum Tragen:
LDI R18,'2'
LDI R17,'5'
LDI R16,'0'
Das speichert direkt die ASCII-Kodierung in das jeweilige Register.
Zum Seitenanfang
Um eine BCD-kodierte Ziffer in ihr ASCII-Pendant zu verwandeln,
müssen die Bits 4 und 5 der Zahl auf Eins gesetzt werden. Das verlangt nach einer
binären Oder-Verknüpfung und ist eine leichte Aufgabe. Die geht so:
ORI R1,0x30
Steht ein Register zur Verfügung, in dem bereits 0x30 steht, hier R2,
dann kann man das Oder auch mit diesem Register durchführen:
OR R1,R2
Zurück ist es schon schwieriger, weil der naheliegende umgekehrt
wirkende Befehl,
ANDI R1,0x0F
der die oberen vier Bits des Registers auf Null setzt und die unteren vier Bits
beibehält, nur für Register oberhalb R15 möglich ist. Eventuell also in einem
solchen Register durchführen!
Hat man die 0x0F schon in Register R2, kann man mit diesem Register
Und-verknüpfen:
AND R1,R2
Auch die beiden anderen Befehle zur Bitmanipulation, CBR und SBR,
lassen sich nur in Registern oberhalb von R15 durchführen. Sie würden
entsprechend korrekt lauten:
SBR R16,0b00110000 ; Bits 4 und 5 setzen
CBR R16,0b00110000 ; Bits 4 und 5 löschen
Sollen eins oder mehrere Bits einer Zahl umgekehrt werden, bedient man
sich gerne des Exklusiv-Oder-Verfahrens, das nur für Register, nicht für
Konstanten, zulässig ist:
LDI R16,0b10101010 ; Umdrehen aller geraden Bits
EOR R1,R16 ; in Register R1 und speichern in R1
Sollen alle Bits eines Bytes umgedreht werden, kommt das
Einerkomplement ins Spiel. Mit
COM R1
wird der Inhalt eines Registers bitweise invertiert, aus Einsen werden Nullen und
umgekehrt. So wird aus 1 die Zahl 254, aus 2 wird 253, usw. Anders ist die Erzeugung
einer negativen Zahl aus einer Positiven. Hierbei wird das Vorzeichenbit (Bit 7)
umgedreht bzw. der Inhalt von Null subtrahiert. Dieses erledigt der Befehl
NEG R1
So wird aus +1 (dezimal: 1) -1 (binär 1111.1111), aus +2 wird -2 (binär
1111.1110), usw.
Neben der Manipulation gleich mehrerer Bits in einem Register gibt es das
Kopieren eines einzelnen Bits aus dem eigens für diesen Zweck eingerichteten T-Bit
des Status-Registers. Mit
BLD R1,0
wird das T-Bit in das Bit 0 des Registers R1 kopiert und das dortige Bit
überschrieben. Das T-Bit kann vorher auf Null oder Eins
gesetzt oder aus einem beliebigen anderen Bit-Lagerplatz in einem Register geladen
werden:
CLT ; T-Bit auf Null setzen, oder
SET ; T-Bit auf Eins setzen, oder
BST R2,2 ; T-Bit aus Register R2, Bit 2, laden
Zum Seitenanfang
Das Schieben von binären Zahlen entspricht dem Multiplizieren und Dividieren mit
2. Beim Schieben gibt es unterschiedliche Mechanismen.
Die Multiplikation einer Zahl mit 2 geht einfach so vor sich, dass alle
Bits einer binären Zahl um eine Stelle nach links geschoben werden. In das freie
Bit 0 kommt eine Null. Das überzählige ehmalige Bit 7 wird dabei in das
Carry-Bit im Status-Register abgeschoben. Der Vorgang wird logisches Links-Schieben
genannt.
LSL R1
Das umgekehrte Dividieren durch 2 heißt Dividieren oder logisches
Rechts-Schieben.
LSR R1
Dabei wird das frei werdende Bit 7 mit einer 0 gefüllt, während das Bit 0
in das Carry geschoben wird. Dieses Carry kann zum Runden der Zahl verwendet werden.
Als Beispiel wird eine Zahl durch vier dividiert und dabei gerundet.
LSR R1 ; Division durch 2
BRCC Div2 ; Springe wenn kein Runden
INC R1 ; Aufrunden
Div2:
LSR R1 ; Noch mal durch 2
BRCC DivE ; Springe wenn kein Runden
INC R1 ; Aufrunden
DivE:
Teilen ist also eine einfache Angelegenheit bei Binärzahlen (aber nicht durch 3)!
Bei vorzeichenbehafteten Zahlen würde das Rechtsschieben das
Vorzeichen in Bit 7 übel verändern. Das darf nicht sein. Desdewegen gibt es
neben dem logischen Rechtsschieben auch das arithetische Rechtsschieben. Dabei bleibt
das Vorzeichenbit 7 erhalten und die Null wird in Bit 6 eingeschoben.
ASR R1
Wie beim logischen Schieben landet das Bit 0 im Carry.
Wie nun, wenn wir 16-Bit-Zahlen mit 2 multiplizieren wollen? Dann muss
das links aus dem untersten Byte herausgeschobene Bit von rechts in das oberste
Byte hineingeschoben werden. Das erledigt man durch Rollen. Dabei landet keine Null
im Bit 0 des verschobenen Registers, sondern der Inhalt des Carry-Bits.
LSL R1 ; Logische Schieben unteres Byte
ROL R2 ; Linksrollen des oberen Bytes
Beim ersten Befehl gelangt Bit 7 des unteren Bytes in das Carry-Bit, beim zweiten
Befehl dann im Bit 0 des oberen Bytes. Nach dem zweiten Befehl hängt Bit 7 des
oberen Bytes im Carry-Bit herum und wir könnten es ins dritte Byte schieben, usw.
Natürlich gibt es das Rollen auch nach rechts, zum Dividieren von
16-Bit-Zahlen gut geeignet. Hier nun alles Rückwärts:
LSR R2 ; Oberes Byte durch 2, Bit 0 ins Carry
ROR R1 ; Carry in unteres Byte und dabei rollen
So einfach ist das mit dem Dividieren bei großen Zahlen. Man sieht sofort, dass
Assembler-Dividieren viel schwieriger zu erlernen ist als Hochsprachen-Dividieren,
oder?
Gleich vier mal Spezial-schieben kommt jetzt. Es geht um die Nibble
gepackter BCD-Zahlen. Wenn man nun mal das obere Nibble anstelle des unteren Nibble
braucht, dann kommt amn um vier mal Rollen
ROR R1
ROR R1
ROR R1
ROR R1
mit einem einzigen
SWAP R1
herum. Das vertauscht mal eben die oberen vier mit den unteren vier Bits.
Zum Seitenanfang
Ungeheuer schwierig in Assembler ist Addieren, Dividieren und Vergleichen.
Zart-besaitete Anfänger sollten sich an dieses Kapitel nicht herantrauen. Wer es
trotzdem liest, ist übermütig und jedenfalls selbst schuld.
Um es gleich ganz schwierig zu machen, addieren wir die 16-Bit-Zahlen
zu den Registern R1:R2 die Inhalte von R3:R4 (Das : heißt nicht Division! Das
erste Register gibt das High-Byte, das zweite nach dem : das Low-Byte an).
ADD R2,R4 ; zuerst die beiden Low-Bytes
ADC R1,R3 ; dann die beiden High-Bytes
Anstelle von ADD wird beim zweiten Addieren ADC verwendet. Das addiert
auch noch das Carry-Bit dazu, falls beim ersten Addieren ein Übertrag stattgefunden
hat. Sind sie schon dem Herzkasper nahe?
Wenn nicht, dann kommt jetzt das Subtrahieren. Also alles wieder
rückwärts und R3:R4 von R1:R2 subtrahiert.
SUB R2,R4 ; Zuerst das Low-Byte
SBC R1,R3 ; dann das High-Byte
Wieder derselbe Trick: Anstelle des SUB das SBC, das zusätzlich zum
Register R3 auch gleich noch das Carry-Bit von R1 abzieht. Kriegen Sie noch Luft? Wenn
ja, dann leisten sie sich das folgende: Abziehen ohne Ernst!
Jetzt kommt es knüppeldick: Ist die Zahl in R1:R2 nun
größer als die in R3:R4 oder nicht? Also nicht SUB, sondern CP,
und nicht SBC, sondern CPC:
CP R2,R4 ; Vergleiche untere Bytes
CPC R1,R3 ; Vergleiche obere Bytes
Wenn jetzt das Carry-Flag gesetzt ist, kann das nur heißen, dass R3:R4
größer ist als R1:R2. Wenn nicht, dann eben nicht.
Jetzt setzen wir noch einen drauf! Wir vergleichen Register R1 und eine
Konstante miteinander: Ist in Register R16 ein binäres Wechselbad gespeichert?
CPI R16,0xAA
Wenn jetzt das Z-Bit gesetzt ist, dann ist das aber so was von gleich!
Und jetzt kommt der Sockenauszieher-Hammer-Befehl! Wir vergleichen, ob
das Register R1 kleiner oder gleich Null ist.
TST R1
Wenn jetzt das Z-Flag gesetzt ist, ist das Register ziemlich leer und wir können
mit BREQ, BRNE, BRMI, BRPL, BRLO, BRSH, BRGE, BRLT, BRVC oder auch BRVS ziemlich
lustig springen.
Sie sind ja immer noch dabei! Assembler ist schwer, gelle? Na dann, kriegen sie noch ein
wenig gepacktes BCD-Rechnen draufgepackt. Beim Addieren von gepackten BCD's kann
sowohl die unterste der beiden Ziffern als auch die oberste überlaufen. Addieren
wir im Geiste die BCD-Zahlen 49 (=hex 49) und 99 (=hex 99). Beim Addieren in hex kommt
hex E2 heraus und es kommt kein Byte-Überlauf zustande. Die untersten beiden
Ziffern sind beim Addieren übergelaufen (9+9=18 = hex 12). Folglich ist die
oberste Ziffer korrekt um eins erhöht worden, aber die unterste stimmt nicht,
sie müsste 8 statt 2 lauten. Also könnten wir 6 addieren, dann stimmt es
wieder. Die oberste Ziffer stimmt überhaupt nicht, weil hex E keine zulässige
BCD-Ziffer ist. Sie müsste richtigerweise 4 lauten (4+9+1=14) und ein Überlauf
sollte auftreten. Also, wenn zu E noch 6 addiert werden, kommt dezimal 20 bzw. hex 14
heraus. Alles ganz easy: Einfach zum Ergebnis noch hex 66 addieren und schon stimmt
alles. Aber gemach! Das wäre nur korrekt, wenn bei der hintersten Ziffer, wie in
unserem Fall, entweder schon beim ersten Addieren oder später beim Addieren der 6
tatsächlich ein Überlauf in die nächste Ziffer auftrat. Wenn das nicht
so ist, dann darf die 6 nicht addiert werden. Woran ist zu merken, ob dabei ein
Übertrag auftrat? Am Halbübertrags-Bit im Status-Register. Dieses H-Bit
zeigt für einige Befehle an, ob ein solcher Übertrag aus dem unteren in das
obere Nibble auftrat. Dasselbe gilt analog für das obere Nibble, nur zeigt hier
das Carry-Bit den Überlauf an. Die folgenden Tabellen zeigen die verschiedenen
Möglichkeiten an.
ADD R1,R2 (Half)Carry-Bit | ADD Nibble,6 (Half)Carry-Bit | Korrektur |
| 0 | 0 | 6 wieder abziehen |
| 1 | 0 | keine |
| 0 | 1 | keine |
| 1 | 1 | (geht gar nicht) |
Nehmen wir an, die beiden gepackten BCD-Zahlen seien in R2 und R3 gespeichert, R1 soll
den Überlauf aufnehmen und R16 und R17 stehen zur freien Verfügung. R16 soll
zur Addition von 0x66 dienen (das Register R2 kann keine Konstanten addieren), R17
zur Subtraktion der Korrekturen am Ergebnis. Dann geht das Addieren von R2 und R3 so:
LDI R16,0x66
LDI R17,0x66
ADD R2,R3
BRCC NoCy1
INC R1
ANDI R17,0x0F
NoCy1:
BRHC NoHc1
ANDI R17,0xF0
NoHc1:
ADD R2,R16
BRCC NoCy2
INC R1
ANDI R17,0x0F
NoCy2:
BRHC NoHc2
ANDI R17,0x0F
NoHc2:
SUB R2,R17
Die einzelnen Schritte: Im ersten Schritt werden die beiden Zahlen addiert. Tritt
dabei schon ein Carry auf, dann wird das Eregebnisregister R1 erhöht und eine
Korrektur des oberen Nibbles ist nicht nötig (die obere 6 im Korrekturspeicher
wird gelöscht). INC und ANDI beeinflussen das H-Bit nicht. War
nach der ersten Addition das H-Bit schon gesetzt, dann kann auch die Korrektur des
unteren Nibble entfallen (das untere Nibble wird Null gesetzt). Dann wird 0x66
addiert. Tritt dabei nun ein Carry auf, dann wird wie oben verfahren. Trat dabei
ein Half-Carry auf, dann wird ebenfalls wie oben verfahren. Schließlich
wird das Korrektur-Register vom Ergebnis abgezogen und die Berechnung ist fertig.
Kürzer geht es so.
LDI R16,0x66
ADD R2,R16
ADD R2,R3
BRCC NoCy
INC R1
ANDI R16,0x0F
NoCy:
BRHC NoHc
ANDI R16,0xF0
NoCy:
SUB R2,R16
Ich überlasse es dem Leser zu ergründen, warum das so geht.
Zum Seitenanfang
Alle Zahlenformate sind natürlich umwandelbar. Die Umwandlung von BCD in ASCII
und zurück war oben schon besprochen (Bitmanipulationen).
Die Umwandlung von gepackten BCD's ist auch nicht schwer. Zuerst ist die gepackte BCD
mit einem SWAP umzuwandeln, so dass das erste Digit ganz rechts liegt. Mit
einem ANDI kann dann das obere (ehemals untere) Nibble gelöscht werden, so
dass das obere Digit als reine BCD blank liegt. Das zweite Digit ist direkt
zugänglich, es ist nur das obere Nibble zu löschen. Von einer BCD zu einer
gepackten BCD kommt man, indem man die höherwertige BCD mit SWAP in das
obere Nibble verfrachtet und anschließend die niederwertige BCD damit verODERt.
Etwas schwieriger ist die Umwandlung von BCD-Zahlen in eine Binärzahl. Dazu macht
man zuerst die benötigten Bits im Ergebnisspeicher frei. Man beginnt mit der
höchstwertigen BCD-Ziffer. Bevor man diese zum Ergebnis addiert, wird das Ergebnis
erstmal mit 10 multipliziert. Dazu speichert man das Ergebnis irgendwo zwischen,
multipliziert es mit 4 (zweimal links schieben/rotieren), addiert das alte Ergebnis
(mal 5) und schiebt noch einmal nach links (mal 10). Jetzt erst wird die BCD-Ziffer
addiert. Tritt bei irgendeinem Schieben des obersten Bytes ein Carry auf, dann passt
die BCD-Zahl nicht in die verfügbaren binären Bytes.
Die Verwandlung einer Binärzahl in BCD-Ziffern ist noch etwas schwieriger. Handelt
es sich um 16-Bit-Zahlen, kann man solange 10.000 subtrahieren, bis ein Überlauf
auftritt, das ergibt die erste BCD-Ziffer. Anschließend subtrahiert man 1.000
bis zum Überlauf und erhält die zweite Ziffer, usw. bis 10. Der Rest ist die
letzte Ziffer.Die Ziffern 10.000 bis 10 kann man im Programmspeicher in
einer wortweise organisierten Tabelle verewigen, z.B. so
DezTab:
.DW 10000, 1000, 100, 10
und wortweise mit dem LPM-Befehl aus der Tabelle herauslesen in zwei Register.
Eine Alternative ist eine Tabelle mit der Wertigkeit jedes einzelnen Bits
einer 16-Bit-Zahl, also z.B.
.DB 0,3,2,7,6,8
.DB 0,1,6,3,8,4
.DB 0,0,8,1,9,2
.DB 0,0,4,0,9,6
.DB 0,0,2,0,4,8 ; und so weiter bis
.DB 0,0,0,0,0,1
Dann wären die einzelnen Bits der 16-Bit-Zahl nach links herauszuschieben und,
wenn es sich um eine 1 handelt, der entsprechende Tabellenwert per LPM zu lesen und
zu den Ergebnisbytes zu addieren. Ein vergleichsweise aufwendigeres und langsameres
Verfahren.
Eine dritte Möglichkeit wäre es, die fünf zu addierenden BCD-Ziffern
beginnend mit 00001 durch Multiplikation mit 2 bei jedem Durchlauf zu erzeugen und
mit dem Schieben der umzuwandelnden Zahl beim untersten Bit zu beginnen.
Es gibt viele Wege nach Rom, und manche sind mühsamer.
Zum Seitenanfang
©2002 by http://www.avr-asm-tutorial.net