Forum: Mikrocontroller und Digitale Elektronik Mehr als 8-Bit Subtraktion mit * (-1)


von anfänger0815 (Gast)


Lesenswert?

Hallo Forum, mal wieder eine Verständnisfrage. Ich möchte zwei z.B 32 
Bit zahlen von einander subtrahieren. Wenn ein Negatives Ergebnis 
berechnet wird soll dies den gleichen Zahlenwert im positiven haben, 
sprich aus -231983 soll 231983 werden. Bei eine 8-Bit-Subtraktion mache 
ich das mit dem Befehel NEG wenn ein Übertrag ins Carry stattgefunden 
hat. wie ist es bei einer 32-Bit-Zahl. Muß ich nach jeder 
Teilsubtraktion überprüfen ob ein Übertrag stattgefunden hat und dann 
den NEG-Befehl ausführen oder nur am Ende der vier Teilsubtraktionen bei 
einem Carryübertrag dann viermal den NEG-Befehl. Oder soll ich den 
COM-Befehl nehmen. ich weiß nicht warum, aber ich habe oft ein Ergebnis 
welches sich um 1 zu einem mit Dezimal und den gleichen Zahlen 
ausgeführten Rechnung unterscheidet.

Danke mal wieder für Eure Hilfe

von Stefan F. (Gast)


Lesenswert?

Ist der CPU Typ völlig irrelevant?

von K. S. (the_yrr)


Lesenswert?

Was bitte versuchst du da zu machen? Willst du den Absolutwert vom 
Ergebnis der Subtraktion haben? und soll das Assembler auf einem 8 Bit 
System sein? Rechnet das mit Einer- oder Zweierkomplement, je nachdem 
halt COM oder auch nicht.

anfänger0815 schrieb:
> aber ich habe oft ein Ergebnis
> welches sich um 1
mit was für Code?
eventuell ein Problem mit der Zweierkomplement Darstellung?

> oder nur am Ende der vier Teilsubtraktionen
nur am Ende, denn nur dann ist die Zahl negativ geworden. Aber da würde 
ich eher das Negativ Flag abfragen als das Carry flag, das kann nämlich 
auch überlaufen wenn du von einer positiven Zahl eine negative abziehst. 
Wäre halt interessant was für ein System du benutzt und was für Flags 
das hat.

von anfänger0815 (Gast)


Lesenswert?

Große Entschuldigung. Ich arbeite im Moment mit einem Attiny84. Ich 
verwende Assembler. Genau, ich möchte auf alle Fälle den Betrag einer 
Subtraktion. Also keine Negativen Werte.

Mein Testcode sieht im Moment so aus:

  ldi tmp10,40
  ldi tmp12,30
  sub tmp10,tmp12

  ldi tmp11,20
  ldi tmp12,30
  sbc tmp11,tmp12

  brcc hp10
  neg tmp10
  neg tmp11

hp10:

von c-hater (Gast)


Lesenswert?

anfänger0815 schrieb:

> Muß ich nach jeder
> Teilsubtraktion überprüfen ob ein Übertrag stattgefunden hat und dann
> den NEG-Befehl ausführen

Nein. NEG hilft dir nicht, wenn du es mit mehr als einem Byte zu tun 
hast.

> oder nur am Ende der vier Teilsubtraktionen bei
> einem Carryübertrag dann viermal den NEG-Befehl.

Nein. NEG hilft dir nicht, wenn du es mit mehr als einem Byte zu tun 
hast.

> Oder soll ich den
> COM-Befehl nehmen.

Das ist zielführender, reicht aber allein nicht.

> ich weiß nicht warum, aber ich habe oft ein Ergebnis
> welches sich um 1 zu einem mit Dezimal und den gleichen Zahlen
> ausgeführten Rechnung unterscheidet.

Nicht ganz. Wenn du COM verwendest, ist das Ergebnis immer um genau 1 
daneben(zu klein). Das musst du also einfach nur kompensieren. Beispiel 
für 16Bit:

 sub R16,R18
 sbc R17,R19
 brpl positiv
 com R16
 com R17
 subi R16,Low(-1)
 sbci R17,High(-1)
positiv:
 ...

von anfänger0815 (Gast)


Lesenswert?

Super Danke für die schnelle Antwort. Werde ich gleich versuchen 
nachzuvollziehen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

c-hater schrieb:
> Beispiel für 16Bit:
>
>  sub R16,R18
>  sbc R17,R19
>  brpl positiv

Es handelt sich wohl um die Subtraktion 2er unsigned Werte, zumindest 
deutet darauf hin, dass der TO auf Carry vergleicht.  Ergo:
1
BRSH positiv
2
;; oder
3
BRCC positiv

>  com R16
>  com R17
>  subi R16,Low(-1)
>  sbci R17,High(-1)

Geht kürzer:
1
neg  R17
2
neg  R16
3
sbci R17, 0 ; oder sbc R17, Rzero  wenn Rzero = 0.

Und wieder hat der c-hater was vom C-Compiler gelernt :-P

Negation für 32 Bits:
1
com  R19
2
com  R18
3
com  R17
4
neg  R16
5
sbci R17, -1
6
sbci R18, -1
7
sbci R19, -1

von Yalu X. (yalu) (Moderator)


Lesenswert?

Johann L. schrieb:
> Geht kürzer:
>
> neg  R17
> neg  R16
> sbci R17, 0 ; oder sbc R17, Rzero  wenn Rzero = 0.
>
> Und wieder hat der c-hater was vom C-Compiler gelernt :-P

Das ging mir auch schon oft so.

Wenn ich erfahren wollte, ob es für eine bestimmte Rechenoperation einen
coolen Assemblertrick gibt, fragte ich einfach den Compiler um Rat und
war von seinen Antworten meist positiv überrascht.

Irgendwann hat es mir aber gereicht, und ich habe den Compiler
angebrüllt: "Wenn du sowieso immer alles besser weißt, dann erledige
doch dieses Assemblergefrickel selber, und zwar bitte komplett!"

Er war sofort damit einverstanden, und seitdem gebe ich – in einer für
uns beide gut verständlichen Sprache – nur noch grob vor, was ich gerne
hätte, und der Compiler übernimmt für mich dann netterweise die lästige
Assemblerprogrammierung.

Und das mit einem Tempo, dass einem die Spucke wegbleibt: Zehntausende
Assemblerzeilen in Sekundenschnelle und dabei auch noch fehlerfrei, das
muss ihm erst einmal einer nachmachen.

Und er meckert nicht einmal, wenn ich von ihm verlange, fast dasselbe
Assemblerprogramm mit nur ein paar kleinen Änderungen noch einmal
komplett neu zu schreiben.

von Rainer V. (a_zip)


Lesenswert?

anfänger0815 schrieb:
> Muß ich nach jeder
> Teilsubtraktion überprüfen ob ein Übertrag stattgefunden hat und dann
> den NEG-Befehl ausführen oder nur am Ende der vier Teilsubtraktionen bei
> einem Carryübertrag dann viermal den NEG-Befehl

Nee, du mußt mal deinen Rechner "oben" einschalten...wenn du Zahlen 
subtrahierst (oder addierst) dann machst du das immer mit "Carry" 
(natürlich nicht bei der niedrigsten Stelle...) und dann kannst du das 
Ergebnis "verabsolutieren"...was immer dein Assembler dafür an Befehlen 
bereit stellt. Schau dir mal die vielen Assembler-Beispiele für 
fundamentale Rechenoperationen an, die es im Netz gibt. Oder schau dir 
halt an, was dein Compiler aus "abs(sign-32 minus sign-32)" macht.
Gruß Rainer

von Guest (Gast)


Lesenswert?

Yalu X. schrieb:
> Und das mit einem Tempo, dass einem die Spucke wegbleibt: Zehntausende
> Assemblerzeilen in Sekundenschnelle und dabei auch noch fehlerfrei, das
> muss ihm erst einmal einer nachmachen.

Und wenn mal wieder die Calling-Conventions nicht stimmen, und deshalb 
das Programm abstürzt ist der Compiler völlig hilflos und fragt dann 
doch ob sich mal bitte jemand den Assemblercode anschauen kann ;-)

von S. R. (svenska)


Lesenswert?

Guest schrieb:
> Und wenn mal wieder die Calling-Conventions nicht stimmen,

Das ist mir bisher eigentlich nur passiert, wenn ich selber 
Assemblercode in den Compiler-Output gefrickelt habe. Eigentlich alle 
Compiler, mit denen ich bisher zu tun hatte, konnten mit ihren eigenen 
Calling-Conventions zuverlässig umgehen.

von leo (Gast)


Lesenswert?

Yalu X. schrieb:
> "Wenn du sowieso immer alles besser weißt, dann erledige
> doch dieses Assemblergefrickel selber, und zwar bitte komplett!"

Zu genau dieser Meinung kam ich auch vor 15 Jahren (gcc 3.x / x86). Ich 
schaffte es nicht mehr, schnelleren Code "per Hand" zu erzeugen. Das mag 
bei µC noch funktionieren, auf x86 kaum.

leo

von Carl D. (jcw2)


Lesenswert?

Guest schrieb:
> Yalu X. schrieb:
>> Und das mit einem Tempo, dass einem die Spucke wegbleibt: Zehntausende
>> Assemblerzeilen in Sekundenschnelle und dabei auch noch fehlerfrei, das
>> muss ihm erst einmal einer nachmachen.
>
> Und wenn mal wieder die Calling-Conventions nicht stimmen, und deshalb
> das Programm abstürzt ist der Compiler völlig hilflos und fragt dann
> doch ob sich mal bitte jemand den Assemblercode anschauen kann ;-)

Wenn man keine Lust hat Assembler selber zu schreiben, muß das ja nicht 
bedeuten, daß man Assembler nicht mehr lesen kann.

von S. R. (svenska)


Lesenswert?

leo schrieb:
> Das mag bei µC noch funktionieren, auf x86 kaum.

Vor allem dann nicht, wenn sich bestimmte Implementationen in ihrem 
Verhalten deutlich voneinander unterscheiden. Befehlssequenzen, die auf 
einem x86 absolut optimal sind, sind auf einem anderen x86 überraschend 
langsam (z.B. "REP RET").

von Carl D. (jcw2)


Lesenswert?

leo schrieb:
> Yalu X. schrieb:
>> "Wenn du sowieso immer alles besser weißt, dann erledige
>> doch dieses Assemblergefrickel selber, und zwar bitte komplett!"
>
> Zu genau dieser Meinung kam ich auch vor 15 Jahren (gcc 3.x / x86). Ich
> schaffte es nicht mehr, schnelleren Code "per Hand" zu erzeugen. Das mag
> bei µC noch funktionieren, auf x86 kaum.
>
> leo

Vor allem kann man sich mit einem Compiler auf einem ganz anderen Niveau 
unterhalten.

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.