Forum: Mikrocontroller und Digitale Elektronik [ASM] Addition (Immediate)


von Christian (dragony)


Lesenswert?

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...

von chris (Gast)


Lesenswert?

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

von S. Landolt (Gast)


Lesenswert?

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

von Christian (dragony)


Lesenswert?

Naja die Werte stehen halt leider in r8 drin. Wenn ich vor- und nachher 
mit movw arbeite, ist auch nichts gewonnen, finde ich.

von chris (Gast)


Lesenswert?

Wie ist denn deine komplette Aufagenbstellung???

von S. Landolt (Gast)


Lesenswert?

> 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.

von Christian (dragony)


Lesenswert?

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...

von S. Landolt (Gast)


Lesenswert?

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

von Thomas E. (picalic)


Lesenswert?

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

???

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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)

von matrixstorm (Gast)


Lesenswert?

_zero_reg_ ist nicht vorhanden und gepflegt?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von Axel S. (a-za-z0-9)


Lesenswert?

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:

von S. Landolt (Gast)


Lesenswert?

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?

von c-hater (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

> da nach Reset alle Register auf Null initialisiert sind

Danke, wieder was gelernt.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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...

von matrixstorm (Gast)


Lesenswert?

sbiw kann da nicht weiterhelfen?

von matrixstorm (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

c-hater schrieb:
> Das ist einfach, da nach Reset alle Register auf Null initialisiert
> sind

Ist das irgendwo dokumentiert?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von Joe Ampere (Gast)


Lesenswert?

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

von Joe Ampere (Gast)


Lesenswert?

Kommando zurück!

"ser" geht nur für die oberen 16 Register.

von S. Landolt (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

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).

von spess53 (Gast)


Lesenswert?

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

von S. Landolt (Gast)


Lesenswert?

Es ging um die normalen Arbeitsregister r0..r31.

von c-hater (Gast)


Lesenswert?

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...

von lrep (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

> 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.

von Ralf G. (ralg)


Lesenswert?

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
von Axel S. (a-za-z0-9)


Lesenswert?

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
von lrep (Gast)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

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'?

von Axel S. (a-za-z0-9)


Lesenswert?

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
Noch kein Account? Hier anmelden.