Hallo zusammen,
ich habe in r8 und r9 ein 16-Bit Wert stehen. Dort will ich jetzt den
Wert 8 hinzufügen. Meine Lösung:
ldi r24,8
clr r25
add r8,r24
adc r9,r25
Gibt es denn wirklich keinen Befehl, der nur das C Flag addiert?
ldi r24,8
add r8,r24
addcflag r9
Anscheinend gibt es auch kein addw, sondern nur ein addiw, was ja
bekanntlich bei reg<16 nicht geht...
> ist auch nichts gewonnen, finde ich
Kommt auf die Sichtweise an: beide Lösungen benötigen 4 Takte, die mit
adiw hat 1 Wort weniger, benutzt aber r25.
Eeben. Ich brauche 2 Register mehr, spare dafür 2 Byte. Das ist jetzt
nicht der Bringer....
Dachte, ich übersehe irgend einen einfachen Befehl... aber anscheinend
gehts wirklich nur so umständlich...
Servus,
kenne mich mit AVR-ASM nicht aus, bitte ggf. um Nachsicht, falls das
hier Blödsinn ist...
Also: Da es ja offenbar (aus mir unerfindlichen Gründen) keine "ADDI"
bzw. "ADCI" Befehle gibt, aber "Subtract Immediate" - geht vielleicht
sowas:
Christian S. schrieb:> Gibt es denn wirklich keinen Befehl, der nur das C Flag addiert?
Du siehst die Aufgabe falsch.
Normal muss das Ganze so aussehen (du arbeitest ja mit const integer):
1
.equAddZahl=8
2
3
ldir24,low(AddZahl)
4
ldir25,high(AddZahl)
5
addr8,r24
6
adcr9,r25
Und selbstverständlich geht das nicht kürzer - und sollte es auch
nicht sein, denn das nächste Mal willst du vielleicht 0x1234 addieren.
Und selbst wenn es ginge, hast du mit diesem einen Befehl nicht viel
gewonnen, aber ich wette dass du dann prompt irgendwo vergisst, die
Register entsprechend zu laden.
Ob du zwei Integer addierst oder Integer mit Byte ist eigentlich egal.
Du must eine Integer addition durchführen und ein Überlauf kann in
beiden Fällen entstehen.
Es wäre ganz schlechter Programmierstil, so etwas uberhaupt zu machen.
Nein, leider nicht. Die ganzen Immediate-Ops (auch andi, ori, cbr, sbr)
lassen sich nur auf die obere Hälfte des Registersatzes anwenden, also
R16 und höher.
Dort ist die Immediate-Subtraktion aber tatsächlich oft sehr nützlich
als Additionsersatz. Übrigens heißt die Variante mit Übertrag nicht
subic, sondern sbci.
@Christian:
Damit läßt sich auch im konkreten Fall wenigstens ein Takt einsparen:
movw R25:R24,R9:R8
subi R24,Low(-8)
sbci R25,High(-8)
matrixstorm schrieb:> zero_reg ist nicht vorhanden und gepflegt?
Doch, bei mir wird r4 auf 0x00 gesetzt und r5 auf 0xFF.
Zwei Befehle am Anfang, kann aber im weiteren Programmablauf manches
einfacher machen.
Christian S. schrieb:> ich habe in r8 und r9 ein 16-Bit Wert stehen. Dort will ich jetzt den> Wert 8 hinzufügen. Meine Lösung:>> ldi r24,8> clr r25> add r8,r24> adc r9,r25>> Gibt es denn wirklich keinen Befehl, der nur das C Flag addiert?
Nein.
Aber man kann ja das C-Flag explizit auswerten und nur bei gesetztem
Flag das High-Byte inkrementieren:
S. Landolt schrieb:> Marc Vesely schrieb:>> bei mir wird r4 auf 0x00 gesetzt und r5 auf 0xFF.>> Zwei Befehle am Anfang>> Wie schafft man das mit zwei Befehlen?
Das ist einfach, da nach Reset alle Register auf Null initialisiert
sind, schafft man das sogar mit einem Befehl, z.B.:
dec R5
oder auch
com R5
Aus beliebiger Ausgangssituation benötigt man allerdings wirklich
mindestens drei Takte.
S. Landolt schrieb:>> Zwei Befehle am Anfang>> Wie schafft man das mit zwei Befehlen?c-hater schrieb:> Das ist einfach, da nach Reset alle Register auf Null initialisiert> sind, schafft man das sogar mit einem Befehl, z.B.:
LOL.
Es sind tatsächlich 3 Befehle, da ich nicht voraussetze, dass Adresse
0x00 gleich RESET ist.
Zu meiner Entschuldigung :
Das Ganze befindet sich (zusammen mit noch ein paar Sachen) in einem
Macro, der wurde vor mehr als 5 Jahren das letzte mal bearbeitet.
Es schien dir ziemlich wichtig, so...
Wenn du Code etwas umstrukturierst (um hoehere Register statt r8++ zu
nutzen)
kannst du doch adiw benutzen.
Das macht die Addition mit einem Befehl in 2 Takten
A. K. schrieb:> c-hater schrieb:>> Das ist einfach, da nach Reset alle Register auf Null initialisiert>> sind>> Ist das irgendwo dokumentiert?
Nein, da es so nicht stimmt.
Die meisten machen keinen Unterschied zwischen I/O register und
general purpose register.
I/O register werden nach RESET auf initial values gesetzt, aber
general purpose register werden NICHT AUF NULL GESETZT , bleiben
also unverändert .
c-hater schrieb:
>S. Landolt schrieb:>> Marc Vesely schrieb:>>> bei mir wird r4 auf 0x00 gesetzt und r5 auf 0xFF.>>> Zwei Befehle am Anfang>>>> Wie schafft man das mit zwei Befehlen?>Das ist einfach, da nach Reset alle Register auf Null initialisiert>sind, schafft man das sogar mit einem Befehl, z.B.:>dec R5>oder auch>com R5>Aus beliebiger Ausgangssituation benötigt man allerdings wirklich>mindestens drei Takte.
Nur zur Info, aus beliebiger Ausgangssituation geht das auch mit zwei
Takten:
A. K. schrieb:> c-hater schrieb:>> Das ist einfach, da nach Reset alle Register auf Null initialisiert>> sind>> Ist das irgendwo dokumentiert?
Das würde mich auch interessieren, und seit wann. Bei meinen Neueren
scheint es so zu sein, bei den steinalten AT90S8515 und AT90S4433 ist es
nicht so.
Marc Vesely schrieb:> general purpose register werden *NICHT AUF NULL GESETZT*
Stimmt tatsächlich, ist auch bei einem ATmega1284P so.
Habe ich doch noch etwas gelernt, nämlich niemandem auf Anhieb zu
glauben (auch nicht mir selbst).
HI
>Bei meinen Neueren>scheint es so zu sein, bei den steinalten AT90S8515 und AT90S4433 ist es>nicht so.
Bei denen gab es gar keine GPIORs. Die sind mit ATmega164P/324P/644P
oder/und ATmega48/88/168 aufgetaucht.
MfG Spess
S. Landolt schrieb:> Es ging um die normalen Arbeitsregister r0..r31.
Jepp, und hier muß ich zu meiner peinlichen Schande gestehen, dass ich
da eindeutig absoluten Bullshit verbreitet habe. Sie werden definitiv
nicht auf Null initialisiert, sondern befinden sich wie der SRAM in
undefiniertem Zustand.
Das kommt davon, wenn man meistens mit dem Simulator entwickelt (der sie
tatsächlich auf Null initialisiert), aber doch gewohnheitsmäßig immer
den sicheren Weg wählt und alles benutzte Zeug explizit initialisiert.
Deswegen ist es mir echt wirklich niemals aufgefallen, dass der
Simulator auch in dieser Beziehung nicht das RL abbildet. Verdammt, wäre
auch nur einmal in irgendeinem Projekt der Codespace gerade so knapp
geworden, daß ich in die Versuchung gekommen wäre, ein paar Code-Worte
bei der Initialisierung zu sparen, dann hätte ich das wahrscheinlich
schon seit langem gewußt...
Axel Schwenke schrieb:> addiere8:>> ldi r24,8> add r8,r24> brcc weiter> inc r9>> weiter:
Dann viel Spaß bei der Fehlersuche!
inc ist etwas anderes als add oder adc, denn es rührt dass carry bit
nicht an.
> inc ist etwas anderes als add oder adc, denn es rührt dass carry> bit nicht an.
Daran besteht kein Zweifel, allein - welche Rolle spielt das bei der
ursprünglichen Fragestellung, der Addition eines konstanten Bytewertes
auf das Registerpaar r9:r8? Und ein eventueller Überlauf ließe sich per
Z-Flag abfragen.
Falls es lebensnotwendig ist, r8:r9 für diese Addition zu verwenden:
chris schrieb:> Wie ist denn deine komplette Aufagenbstellung???
Die Addition mit einer Konstanten ist vielleicht nur ein 'Trick', um den
Übertrag zu erreichen? -> Dann könnte man nur den Übertrag mit BRCC/
BRCS auswerten(.|?)
lrep schrieb:> Axel Schwenke schrieb:>> addiere8:>>>> ldi r24,8>> add r8,r24>> brcc weiter>> inc r9>>>> weiter:>> Dann viel Spaß bei der Fehlersuche!> inc ist etwas anderes als add oder adc, denn es rührt dass carry bit> nicht an.
Und?
Der obige Code tut genau das gewünschte: er addiert eine 8 zu einem
16-Bit unsigned Wert in R8:R9. Dabei kann R9 entweder um Eins erhöht
werden (wenn R8 überläuft) oder nicht. Ein Überlauf von R9 kann in
beiden Fällen auftreten und wird in beiden Fällen nicht abgefangen.
Muß er aber auch nicht. Bei unsigned Arithmetik ist ein Überlauf eine
ganz normale Sache.
c-hater schrieb:> Deswegen ist es mir echt wirklich niemals aufgefallen, dass der> Simulator auch in dieser Beziehung nicht das RL abbildet. Verdammt, wäre> auch nur einmal in irgendeinem Projekt der Codespace gerade so knapp> geworden, daß ich in die Versuchung gekommen wäre, ein paar Code-Worte> bei der Initialisierung zu sparen, dann hätte ich das wahrscheinlich> schon seit langem gewußt...
Als es noch keinen Tiny4313 gab, habe ich VASS-Interfaces mit 90S2313
gemacht. Da ging es um jeden Byte und deswegen bin ich prompt in die
Falle mit r0..r31 getappt.
Seitdem mache ich Init genauso wie du, also explizite Initialisierung
(mit einem Macro).
Und ich muss zu meiner Schande gestehen, dass ich mich erst nachdem ich
dieses Macro heute ansah, und nur weil das als Komentar darin stand,
daran erinnert habe.
P.S.
Am Ende waren genau 2046 Bytes im Flash.
Axel Schwenke schrieb:> Bei unsigned Arithmetik ist ein Überlauf eine> ganz normale Sache.
Stimmt.
Aber oft interessiert es ja doch, ob ein Überlauf aufgetreten ist, und
dazu fragt man i.d.R. hinter dem Label "weiter" den Cy ab.
Wenn aber jemand blauäugig den orthodoxen Code durch diese "Optimierung"
ersetzt hat, wird er (hoffentlich) etwas über Fehlerfortpflanzung
lernen.
...oder auch nicht, wenn er nur oberflächlich testet.
Vielleicht zerschellt dann ja nur mal wieder eine Sonde auf dem Mars.
Marc Vesely schrieb:> Am Ende waren genau 2046 Bytes im Flash.
Ein ähnliche Situation entsteht auch heutzutage noch, im
Bootloader-Bereich nämlich.
lrep schrieb:> Wenn aber jemand blauäugig den orthodoxen Code durch diese "Optimierung"> ersetzt hat, wird er (hoffentlich) etwas über Fehlerfortpflanzung> lernen.
Wo ist der Zusammenhang zwischen schlampiger Programmierung und
'Fehlerfortpflanzung'?
lrep schrieb:> ... oft interessiert es ja doch, ob ein Überlauf aufgetreten ist, und> dazu fragt man i.d.R. hinter dem Label "weiter" den Cy ab.
Davon war aber in der Aufgabenstellung nicht die Rede. Mal ganz davon
abgesehen, daß dem TE ja durchaus bekannt war, wie er das Carry über die
lange Addition bis zum Ende durchreichen kann.
> Wenn aber jemand blauäugig den orthodoxen Code durch diese "Optimierung"> ersetzt hat, wird er (hoffentlich) etwas über Fehlerfortpflanzung> lernen.
Vielleicht lernt er besser etwas über die Notwendigkeit einer exakten
Spezifikation. Wenn nicht spezifiziert ist, welchen Wert das Carry-Flag
nach der Operation haben soll, dann darf ich da jeden Wert zurückgeben.
Punkt.