Hallo,
ich habe folgendes Problem: Ich will mehrere vorzeichenbehaftete
(Zweierkomplement) 16bit Zahlen zu einer vorzeichenbehafteten 24bit-Zahl
aussummieren:
1
.def Zahl_1_L = r16
2
.def Zahl_1_H = r17
3
.def Zahl_2_L = r18
4
.def Zahl_2_H = r19
5
.def erg_L = r20
6
.def erg_M = r21
7
.def erg_H = r22
8
.def temp = r23
9
10
main:
11
12
clr temp
13
14
add erg_L, Zahl_1_L
15
adc erg_M, Zahl_1_H
16
adc erg_H, temp
17
18
add erg_L, Zahl_2_L
19
add erg_H, Zahl_2_H
20
adc erg_H, temp
21
22
...
Der Code klappt sehr gut mit vorzeichenlosen, also
Einer-Komplement-Zahlen. Leider wird das dritte Byte bei
vorzeichenbehafteten negativen Zahlen nicht richtig gebildet. Ich bin
Anfänger im Rechnen mit Assembler und weiß nicht so recht, wie ich das
auf einfache Art und Weise ohne viele zusätzliche Register und
zusätzlichen Code realisieren kann (Programm ist laufzeitkritisch).
Die Möglichkeit, die mir einfällt ist, das höchste Bit des hohen Bytes
einer jeden Zahl zu prüfen und dann die 16bit zu ner 24bit-Zahl
erweitern:
wenn bit7 von Zahl_H =1 dann 3.byte=FF
wenn bit7 von Zahl_H =0 dann 3.byte=00
Das vorzeichenrichtige Aufsummieren sollte dann problemlos klappen.
Aber dazu brauche ich einige Sprungbefehle und neue Register, dann wird
der Code zu lang.
Ich denke, mal es gibt einen eleganteren Trick, nur komme ich auch nach
langem Nachdenken einfach nicht drauf.
Vielleicht könnt ihr mir ja helfen.
Danke für eure Antworten
Hi
Wie zeitkritisch ist die Berechnung? Controller und Taktfrequenz wären
hilfreich.
@Ralph: Der Compiler (und die meisten Anwender desselben) weiss nicht
wie es geht, sondern nur die Programmierer des Compilers. Hier geht es
um Assembler.
Wenn du einen konstruktiven Beitrag leisten kannst, wird sich Sven
freuen.
MfG Spess
Also mal ein bisschen Brainstorming:
Ein Überlauf in das höchstwertige Byte kann bei der Addition von
Zweierkomplement-Ausgangswerten nur dann auftreten, wenn beide
Ausgangswerte bereits negativ waren (MSB gesetzt), wodurch das Ergebnis
auf jeden Fall auch negativ ist. Also muss bei einem Überlauf in jedem
Fall das komplette H-Byte gesetzt werden (0xFF), damit man wieder auf
eine Zweierkomplement-Darstellung kommt.
In den Fällen, in denen das Carry-Flag nicht gesetzt wird, ist zu
überprüfen, ob der Wert in den beiden niederwertigen Bytes positiv oder
negativ ist. Das kann man sehr elegant mit dem N-Flag im SREG lösen. N
entspricht nach der Addition dem MSB des Ergebnisses, ist also gesetzt,
wenn das Ergebnis der adc-Operation negativ ist. Wenn das der Fall ist,
muss noch zusätzlich überprüft werden, ob es bei der Addition einen
Zweierkomplement-Überlauf gegeben hat. Dafür wiederum gibts das V-Flag,
das gesetzt ist, wenn es einen Überlauf in das MSB des Ergebnisses
gegeben hat. Falls also N und V gesetzt sind, heißt das, es hat einen
Überlauf auf das MSB gegeben, das scheinbar negative Ergebnis ist also
in Wirklichkeit positiv und dementsprechend muss das High-Byte des
Ergebnisses mit Nullen gefüllt werden. Andernfalls handelt es sich
tatsächlich um ein negatives Ergebnis und das High-Byte wird mit Einsen
gefüllt (also 0xFF).
Es müssen also im Prinzip drei sukzessive Abfragen durchgeführt werden:
1
Carry gesetzt?
2
Ja: Ergebnis ist auf jeden Fall negativ, High-Byte = 0xFF, weiter im Programm.
3
Nein:
4
N-Flag gesetzt?
5
Nein: Ergebnis ist auf jeden Fall positiv, High-Byte = 0x00, weiter im Programm.
6
Ja:
7
V-Flag gesetzt?
8
Ja: Ergebnis ist positiv, High-Byte = 0x00, weiter im Programm.
9
Nein: Ergebnis ist negativ, High-Byte = 0xFF, weiter im Programm.
Diese Abfrage ist mit den Branch-Befehlen relativ einfach (und schnell)
durchführbar und kostet keine zusätzlichen Register.
Viel Spaß beim Weitertüfteln...
Ralph wrote:
> Programmier in C und lass das den Compiler machen, der weiß wie es geht
Welcher Compiler kann denn bitteschön ressourcensparend (und das war
gefordert!) mit 24-Bit-Zahlen rechnen? Also, erst Gehirn hochfahren,
dann schreiben...
>Die Möglichkeit, die mir einfällt ist, das höchste Bit des hohen Bytes>einer jeden Zahl zu prüfen und dann die 16bit zu ner 24bit-Zahl>erweitern:>wenn bit7 von Zahl_H =1 dann 3.byte=FF
(und bit7 von Zahl_M = 1 lassen)
>wenn bit7 von Zahl_H =0 dann 3.byte=00
Ich denke, anders wird es nicht gehen.
Also, beide 16bit Zahlen auf 24Bit aufdrömeln, dann einfach addieren..
main:
Matthias L.:
sbis => Skip if Bit in I/o-register is Set
sbrs => Skip if Bit in Register is Set
> clr Zahl_1_HH> sb*r*s Zahl_1_H, 7> rjmp positiv1> ldi Zahl_1_HH, 0xFF> positiv1:
geht glaube ich einfacher:
clr Zahl_1_HH
sbrc Zahl_1_H, 7
ldi Zahl_1_HH, 0xFF