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...
nutze die Pointeregister "r24:r25", XH:L,YH:L, ZH:L bei r24:r25 bin ich mir nicht mehr ganz sicher addiw ?H:L,$08 ;da wird C automatisch addiert
Man kann die Verwendung von r25 vermeiden, aber mehr fällt mir nicht ein:
1 | ldi r24,8 |
2 | add r8,r24 |
3 | ldi r24,0 |
4 | adc r9,r24 |
Naja die Werte stehen halt leider in r8 drin. Wenn ich vor- und nachher mit movw arbeite, ist auch nichts gewonnen, finde ich.
> 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...
Oft reserviere ich mir für das gesamte Programm ein Register 'null', manchmal auch 'effeff', zur ständigen Verwendung:
1 | .def null = r2 |
2 | .def effeff = r3 |
3 | |
4 | clr null |
5 | clr effeff |
6 | dec effeff |
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:
1 | subi r8,-8 |
2 | subic r9,-1 |
???
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 | .equ AddZahl = 8 |
2 | |
3 | ldi r24, low(AddZahl) |
4 | ldi r25, high(AddZahl) |
5 | add r8, r24 |
6 | adc r9, 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.
Thomas Elger schrieb: > "Subtract Immediate" - geht vielleicht > sowas: > >
1 | > subi r8,-8 |
2 | > subic r9,-1 |
3 | > |
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:
1 | addiere8: |
2 | |
3 | ldi r24,8 |
4 | add r8,r24 |
5 | brcc weiter |
6 | inc r9 |
7 | |
8 | weiter: |
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?
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.
> da nach Reset alle Register auf Null initialisiert sind
Danke, wieder was gelernt.
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
c-hater schrieb: > Das ist einfach, da nach Reset alle Register auf Null initialisiert > sind Ist das irgendwo dokumentiert?
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 .
:
Bearbeitet durch User
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:
1 | clr r4 |
2 | ser r5 |
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(.|?)
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.