[ASM] Addition (Immediate)

OP #4135570
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...
Gast #4135610
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
(Firma: Vescomp) #4135744
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.
Gast #4135765
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)
#4136586
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:
Gast #4136747
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.
(Firma: Vescomp) #4137363
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...
(Firma: Vescomp) #4137491
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 .
Gast #4137554
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
Gast #4137969
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...
Gast #4138049
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.
#4138143
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.
(Firma: Vescomp) #4138181
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.
Gast #4138265
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.
Gast #4138337
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'?
#4138380
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren