www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik 2 16bit zu einer 24bit Zahl addieren (Assembler)


Autor: Sven (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe folgendes Problem: Ich will mehrere vorzeichenbehaftete 
(Zweierkomplement) 16bit Zahlen zu einer vorzeichenbehafteten 24bit-Zahl 
aussummieren:
.def Zahl_1_L = r16
.def Zahl_1_H = r17
.def Zahl_2_L = r18
.def Zahl_2_H = r19
.def erg_L    = r20
.def erg_M    = r21
.def erg_H    = r22
.def temp     = r23

main:

clr temp

add erg_L, Zahl_1_L
adc erg_M, Zahl_1_H
adc erg_H, temp

add erg_L, Zahl_2_L
add erg_H, Zahl_2_H
adc erg_H, temp

...


Der Code klappt sehr gut mit vorzeichenlosen, also 
Einer-Komplement-Zahlen. Leider wird das dritte Byte bei 
vorzeichenbehafteten negativen Zahlen nicht richtig gebildet. Ich bin 
Anfänger im Rechnen mit Assembler und weiß nicht so recht, wie ich das 
auf einfache Art und Weise ohne viele zusätzliche Register und 
zusätzlichen Code realisieren kann (Programm ist laufzeitkritisch).
Die Möglichkeit, die mir einfällt ist, das höchste Bit des hohen Bytes 
einer jeden Zahl zu prüfen und dann die 16bit zu ner 24bit-Zahl 
erweitern:

wenn bit7 von Zahl_H =1 dann 3.byte=FF
wenn bit7 von Zahl_H =0 dann 3.byte=00

Das vorzeichenrichtige Aufsummieren sollte dann problemlos klappen.

Aber dazu brauche ich einige Sprungbefehle und neue Register, dann wird 
der Code zu lang.
Ich denke, mal es gibt einen eleganteren Trick, nur komme ich auch nach 
langem Nachdenken einfach nicht drauf.
Vielleicht könnt ihr mir ja helfen.

Danke für eure Antworten

Autor: Ralph (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Programmier in C und lass das den Compiler machen, der weiß wie es geht

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Wie zeitkritisch ist die Berechnung? Controller und Taktfrequenz wären 
hilfreich.

@Ralph: Der Compiler (und die meisten Anwender desselben) weiss nicht 
wie es geht, sondern nur die Programmierer des Compilers. Hier geht es 
um Assembler.
Wenn du einen konstruktiven Beitrag leisten kannst, wird sich Sven 
freuen.

MfG Spess

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also mal ein bisschen Brainstorming:
Ein Überlauf in das höchstwertige Byte kann bei der Addition von 
Zweierkomplement-Ausgangswerten nur dann auftreten, wenn beide 
Ausgangswerte bereits negativ waren (MSB gesetzt), wodurch das Ergebnis 
auf jeden Fall auch negativ ist. Also muss bei einem Überlauf in jedem 
Fall das komplette H-Byte gesetzt werden (0xFF), damit man wieder auf 
eine Zweierkomplement-Darstellung kommt.

In den Fällen, in denen das Carry-Flag nicht gesetzt wird, ist zu 
überprüfen, ob der Wert in den beiden niederwertigen Bytes positiv oder 
negativ ist. Das kann man sehr elegant mit dem N-Flag im SREG lösen. N 
entspricht nach der Addition dem MSB des Ergebnisses, ist also gesetzt, 
wenn das Ergebnis der adc-Operation negativ ist. Wenn das der Fall ist, 
muss noch zusätzlich überprüft werden, ob es bei der Addition einen 
Zweierkomplement-Überlauf gegeben hat. Dafür wiederum gibts das V-Flag, 
das gesetzt ist, wenn es einen Überlauf in das MSB des Ergebnisses 
gegeben hat. Falls also N und V gesetzt sind, heißt das, es hat einen 
Überlauf auf das MSB gegeben, das scheinbar negative Ergebnis ist also 
in Wirklichkeit positiv und dementsprechend muss das High-Byte des 
Ergebnisses mit Nullen gefüllt werden. Andernfalls handelt es sich 
tatsächlich um ein negatives Ergebnis und das High-Byte wird mit Einsen 
gefüllt (also 0xFF).

Es müssen also im Prinzip drei sukzessive Abfragen durchgeführt werden:
Carry gesetzt?
    Ja: Ergebnis ist auf jeden Fall negativ, High-Byte = 0xFF, weiter im Programm.
    Nein: 
    N-Flag gesetzt?
        Nein: Ergebnis ist auf jeden Fall positiv, High-Byte = 0x00, weiter im Programm.
        Ja: 
        V-Flag gesetzt?
            Ja: Ergebnis ist positiv, High-Byte = 0x00, weiter im Programm.
            Nein: Ergebnis ist negativ, High-Byte = 0xFF, weiter im Programm.
Diese Abfrage ist mit den Branch-Befehlen relativ einfach (und schnell) 
durchführbar und kostet keine zusätzlichen Register.

Viel Spaß beim Weitertüfteln...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ralph wrote:
> Programmier in C und lass das den Compiler machen, der weiß wie es geht
Welcher Compiler kann denn bitteschön ressourcensparend (und das war 
gefordert!) mit 24-Bit-Zahlen rechnen? Also, erst Gehirn hochfahren, 
dann schreiben...

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Die Möglichkeit, die mir einfällt ist, das höchste Bit des hohen Bytes
>einer jeden Zahl zu prüfen und dann die 16bit zu ner 24bit-Zahl
>erweitern:

>wenn bit7 von Zahl_H =1 dann 3.byte=FF
(und bit7 von Zahl_M = 1 lassen)

>wenn bit7 von Zahl_H =0 dann 3.byte=00

Ich denke, anders wird es nicht gehen.
Also, beide 16bit Zahlen auf 24Bit aufdrömeln, dann einfach addieren..

main:
clr temp

clr Zahl_1_HH         // Zahl1: HH:H:L
sbis Zahl_1_H, 7
rjmp positiv1
ldi Zahl_1_HH, 0xFF
positiv1:

clr Zahl_2_HH         // Zahl2: HH:H:L
sbis Zahl_2_H, 7
rjmp positiv2
ldi Zahl_2_HH, 0xFF
positiv2:

add erg_L, Zahl_1_L
adc erg_M, Zahl_1_H
adc erg_H, Zahl_1_HH

add erg_L, Zahl_2_L
adc erg_H, Zahl_2_H
adc erg_H, Zahl_2_HH

Vielleicht so? Bin aber net ganz sicher..

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Matthias L.:

sbis => Skip if Bit in I/o-register is Set
sbrs => Skip if Bit in Register is Set


> clr Zahl_1_HH
> sb*r*s Zahl_1_H, 7
> rjmp positiv1
> ldi Zahl_1_HH, 0xFF
> positiv1:

geht glaube ich einfacher:
clr Zahl_1_HH
sbrc Zahl_1_H, 7
ldi Zahl_1_HH, 0xFF

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
oh ja, das sbis und sbrs verwechselt..

Ja, hast recht, das spart einen BEfehl..

Autor: ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kenn mich mit AVR-Assembler nicht aus aber vieleicht geht es so?

add erg_L, Zahl_1_L
adc erg_M, Zahl_1_H
adc erg_H, 0
sbrc Zahl_1_H, 7
dec erg_H

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.