Zahl In RR[4:7] in 2er Kompl. wandeln.
Geht es einfacher?
clr A
com RR4 :setzt carry
com RR5
com RR6
com RR7 ; C=1 wird gleich als +1 verwendet
adc RR4,A
adc RR5,A
adc RR6,A
adc RR7,A ; carry wird verworfen
Hi
>Geht es einfacher?
Einem Befehl kann man sparen:
[avrasm}
com r16
com r17
com r18
com r19
subi r16,Low(-1)
sbci r17,byte2(-1)
sbci r18,byte3(-1)
sbci r19,byte4(-1)
[/avrasm}
MfG Spess
Ich brauche doch etwas Nachhilfe
In der AVR-Hilfe unter expressions findet sich z.B.
byte2(expression) was ident ist mit high(expression), dass dies das
2.Byte eines Ausdruckes liefert. Gut!
Aber der t2313 hat ja nur 1 Byte Weite. Also was liefert dann
byte2 oder byte3 oder byte4(-1) zurück?
Wenn es 0 ist, so verstehe ich die Antwort von spess53.
In meiner nicht so großen Erfahrung würde ich aber dann schreiben, wenn
es richtig ist:
[avrasm}
com r16
com r17
com r18
com r19
subi r16,(-1) ; ident mit add 1
sbci r17,0 ; wenn Übertrag, dann nur carry addieren
sbci r18,0
sbci r19,0
[/avrasm}
Aber ist das richtig?
Bitte um Nachhilfe
Hi
>Aber der t2313 hat ja nur 1 Byte Weite. Also was liefert dann>byte2 oder byte3 oder byte4(-1) zurück?
Assembler Hilfe:
BYTE2(expression) is the same function as HIGH
BYTE3(expression) returns the third byte of an expression
BYTE4(expression) returns the fourth byte of an expression
In diesem Fall ist expression = -1 oder $FFFFFFFF
>Wenn es 0 ist, so verstehe ich die Antwort von spess53.
Der Befehl com ist das Einerkomplement (oder Negation) und mit
Rd ← $FF - Rd definiert. Das Zweierkomlement (neg) mit Rd ← $00 - Rd.
Also ist neg(Wert) = com(Wert)+1. Da es keine ADDI/ADCI-Befehle gibt,
werden die in dem Fall durch subi/sbci -1 ersetzt.
Funktioniert bei mir seit Jahren. Teste es einfach im Simulator.
MfG Spess
Rudi D. schrieb:> Aber der t2313 hat ja nur 1 Byte Weite. Also was liefert dann> byte2 oder byte3 oder byte4(-1) zurück?
Das bezieht sich auf Konstanten oder konstante berechnete Ausdrücke im
Assembler, nicht auf Werte in Registern. Solche Ausdrücke werden vom
Assembler in 32 Bits gerechnet.
A. K. schrieb:> Rudi D. schrieb:>> Aber der t2313 hat ja nur 1 Byte Weite. Also was liefert dann>> byte2 oder byte3 oder byte4(-1) zurück?>> Das bezieht sich auf Konstanten oder konstante berechnete Ausdrücke im> Assembler, nicht auf Werte in Registern. Solche Ausdrücke werden vom> Assembler in 32 Bits gerechnet.
Das hat mir gefehlt. Wo steht das im AVR Studio, habs nie gefunden.
spess53 schrieb:> Der Befehl com ist das Einerkomplement (oder Negation) und mit> Rd ← $FF - Rd definiert. Das Zweierkomlement (neg) mit Rd ← $00 - Rd.> Also ist neg(Wert) = com(Wert)+1. Da es keine ADDI/ADCI-Befehle gibt,> werden die in dem Fall durch subi/sbci -1 ersetzt.
Das hab ich ja schon geschriebn, ist ja klar.
Aber sollte es nicht heißen:
subi r16,Low(-1)
sbci r17,byte2(0)
sbci r18,byte3(0)
sbci r19,byte4(0)
Es soll ja nur das ev. Carry addiert werden und nicht
r18 = r18 - ffh -C
Wo steh ich auf der Leitung?
Rudi D. schrieb:> Wo steh ich auf der Leitung?
-1 = 0xFFFFFFFF
Bei dir: 0x000000FF.
Negation: B = Invertiere(A) + 1
Oder: B = Invertiere(A) - -1
Und zwar in 32 Bits Breite.
aber wenn dir das zu kompliziert ist:
clr r20
clr r21
movw r22, r20
sub r20, r16
sbc r21, r17
sbc r22, r18
sbc r23, r19
Ergebnis in R20-23
Hi
>Es soll ja nur das ev. Carry addiert werden und nicht>r18 = r18 - ffh -C
Als 32-Bit-Zahl ist aber -1 = $FFFFFFFF und nicht nur $000000FF-
MfG Spess
spess53 schrieb:> [avrasm}> com r16> com r17> com r18> com r19> subi r16,Low(-1)> sbci r17,byte2(-1)> sbci r18,byte3(-1)> sbci r19,byte4(-1)> [/avrasm}
spess, das kann IMHO nicht richtig sein.
Um vom 1er Komplement, zum 2er Komplement zu kommen, ist ein einziges
Mal 1 zu addieren und nicht 4 x
Kann aber auch sein, dass ich diese Schreibweise nicht verstehe.
Rudi D. schrieb:> spess53 schrieb:>> [avrasm}>> com r16>> com r17>> com r18>> com r19>> subi r16,Low(-1)>> sbci r17,byte2(-1)>> sbci r18,byte3(-1)>> sbci r19,byte4(-1)>> [/avrasm}>> spess, das kann IMHO nicht richtig sein.>> Um vom 1er Komplement, zum 2er Komplement zu kommen, ist ein einziges> Mal 1 zu addieren und nicht 4 x
Du addierst aber nicht +1, sondern du subtrahierst -1
Arithmetisch kommt das aufs gleiche raus.
Nur: Wenn du -1 subtrahierst, dann musst du auch wirklich -1
subtrahieren. Und das in allen 4 Bytes der 32 Bit Zahl! Denn es kann ja
einen Übertrag von einem Byte ins nächste geben.
Dezimal: 99 + 1 ist ja auch 100 und du hast einen Übertrag von der 2.ten
zur 3.ten Stelle. 999999 + 1. Hier wimmelt es nur so von Überträgen von
einer Stelle zur nächsten. Es reicht nicht, einfach nur in der
Einerstelle die 1 zu addieren. 999999 + 1 ergibt eben nicht 999990
sondern der Übertrag wandert die Ziffern nach vorne.
Darum hab ich ja in meiner 9 Lines Lösung 1addiert und 3x mögliche
carries berücksichtigt.
GCC braucht nur 7 Befehle.
Danke auch peda, jetzt hab ich's.
Lg
>> Ich habe eine Frage: hat sich das der Programmierer von GCC einfallen> lassen oder wer kann sonst so eine optimale Lösung erfinden?
Der GCC optimiert halt sehr gut. Darum muss ich auch immer schmunzeln
wenn irgendwelche ASM-Gurus ankommen und was von Performance und
Codegröße schwadronieren, wenn es mal wieder gegen C geht. Meist
verliert sogar der fortgeschrittene ASM Programmierer locker gegen den
GCC Optimierer.
>> Ich habe eine Frage: hat sich das der Programmierer von GCC einfallen> lassen oder wer kann sonst so eine optimale Lösung erfinden?
In diesem Falls: Ja. Es ist eine "fest" vorgegebene Sequenz, die
ausgegeben wird, wenn: Ein 32-Bit int zu negieren ist und Ein- und
Ausgaberegister übereinstimmen und es sich dabei um obere Register
handelt.
Falls es keine oberen Register sind, so wird 1 Instruktion mehr
ausgegeben:
1
com r17
2
com r16
3
com r15
4
com r14
5
adc r14,__zero_reg__
6
adc r15,__zero_reg__
7
adc r16,__zero_reg__
8
adc r17,__zero_reg__
Negation eines 16-Bit int ist übrigens immer mit 3 Instruktionen
machbar, auch in den unteren Registern:
Johann L. schrieb:> Falls es keine oberen Register sind, so wird 1 Instruktion mehr> ausgegeben:> com r17> com r16> com r15> com r14> adc r14,__zero_reg__> adc r15,__zero_reg__> adc r16,__zero_reg__> adc r17,__zero_reg__
Das ist ja fast ident mit der Frage im 1. Beitrag von mir.
Aber wie wird "__zero_reg__" dann übersetzt, da es für die unteren
Register ja kein immediate gibt. Darum hab ich ja "clr A" dazugenommen.
Bin ja nur gelegentlich als Hobby in Assembler unterwegs. DDS und so
Projekte auf elektronik-labor.de zu lesen.
Rudi D. schrieb:> hat sich das der Programmierer von GCC einfallen> lassen oder wer kann sonst so eine optimale Lösung erfinden?
Es gibt nicht "den" GCC-Entwickler.
Einen Compiler baut nie jemand allein in seinem stillen Kämmerlein,
sondern daran können 10.000 und mehr Leute beteiligt sein.
Das Wissen vieler ist nunmal größer, als das eines einzelnen.
Ich war auch schwer enttäuscht, als ich meine 16Bit-Mul/Div für den 8051
entwickelt hatte und dann mal den Keil C51 reassembliert habe. Dessen
Code war halb so groß, dafür doppelt so schnell. Auch hatte ich
haufenweise Push/Pop-Orgien in meinen Assemblerprogrammen, der C51 hat
das mit Registern für Argumente und Overlay für Variablen viel
effektiver gelöst. Von Assembler nach C umgeschriebene Programmer wurden
daher kleiner und schneller.
Und der Herr Keil wird auch nicht alles allein gemacht haben.
Rudi D. schrieb:> Aber wie wird "__zero_reg__" dann übersetzt, da es für die unteren> Register ja kein immediate gibt. Darum hab ich ja "clr A" dazugenommen.
Nachtrag:
Dieses Register, s.o. bezieht sich auf den GCC Inline Assembler und ist
R1 lt. GCCdoc. Es wird immer auf NULL gehalten. Näheres
https://gcc.gnu.org/wiki/avr-gcc?action=fullsearch&context=180&value=__zero_&fullsearch=Text
Es gilt nicht für den Assembler von AVRStudio4. o.k.