Forum: Mikrocontroller und Digitale Elektronik Multiplikation 16Bit (signiert) mit 8Bit (unsigniert) Assembler ATmega8 ATmega1284P


von Bernhard S. (bernhard)


Lesenswert?

Geschätztes Forum,

es sollen 2 Zahlen miteinander multipliziert werden, die 16-Bit Zahl ist 
vorzeichenbehaftet, die 8-Bit zahl ist nicht vorzeichenbehaftet.


Momentan hab ich es durch eine Schleife realisiert:

        ldi R18,LOW (-12) ; TESTZAHL 1.Faktor
        ldi R19,High(-12)
        ldi R20, 5        ; Testzahl 2.Faktor
        clr XL
        clr XH
SCHLEIFE:
  add XL,18
  adc XH,19
  dec R20
  brne SCHLEIFE

Ich suche eine Lösung, die weniger Takte benötigt,

bitte helft mir.


Danke

Bernhard

von Dampfnilp (Gast)


Lesenswert?

Die Megas haben glaub einen Hardware Multiplizierer ..

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


Lesenswert?

Bernhard S. schrieb:
> Ich suche eine Lösung, die weniger Takte benötigt,
>
> bitte helft mir.

 Also 16bit * 8bit passt schon mal nicht in ein Registerpaar (16bit).

 Versuche es hiermit:
1
.def Mul1 = r2
2
.def Mul2 = r3
3
.def Mul3 = r4
4
5
        ldi   r18, Low (-12)  ; TESTZAHL 1.Faktor
6
        ldi   r19, High(-12)
7
        ldi   r20, 5          ; Testzahl 2.Faktor
8
9
;*** Das kannst du als Routine aufrufen, mit RET am ende
10
mpy8x16:
11
        mul   r18, r20        ; Low Byte
12
        movw  Mul1, r0        ; Ergebnis in r2/r3 übernehmen
13
        mul   r19, r20        ; High Byte
14
        add   Mul2, r0        ; Addiere Low Byte zu HighByte von vorher
15
        mov   Mul3, r1        ; Highest Byte einfach übernehmen
16
        brcc  PC+2            ; Falls bei der vorherigen Addition Übertrag
17
        inc   Mul3            ; Highest Byte um eins erhohen
18
;* Wenn als Routine aufgerufen
19
;       ret
 12 bzw. 13Cycles fur alles, ist das schnell genug ?

 Übrigens, du solltest einzelne register mit Kleinbuchstaben schreiben,
 Registerpaare aber mit Grossbuchstaben, um es etwas lesbarer zu machen
 z.B.
 ldi  r14, 5     ; klein
 ld   r14, X+   ; X gross, weil X in diesem Fall ein Registerpaar ist

: Bearbeitet durch User
von Bernhard S. (bernhard)


Lesenswert?

> 12 bzw. 13Cycles fur alles, ist das schnell genug ?


Toll, ich bin begeistert :-)


Was passiert eigentlich bei "brcc  PC+2" wie ist "PC+2" zu verstehen?


Jetzt muss ich ersteinmal über diese Routine nachdenken, was da genau 
passiert.

Danke

Bernhard

von BastiDerBastler (Gast)


Lesenswert?

Da er zum Ret springen soll, falls das Carry Bit nicht gesetzt ist, wird 
sich "brcc" vielleicht als "branch carry complement" übersetzen lassen. 
PC+2 soll dann bestimmt Program-Counter+2 heißen und insgesamt springt 
die Instruktion zwei Zeilen vor zum Ret, falls das Carry-Bit nicht 
gesetzt ist.

Aber ist nur eine Theorie, kenne mich nicht aus mit den Teilen...

von Bernhard S. (bernhard)


Lesenswert?

>Also 16bit * 8bit passt schon mal nicht in ein Registerpaar (16bit).

Korrekt, ich hätte noch dazu schreiben sollen, dass der Wertebereich des 
Ergebnisses die 16 Bit nicht überschreitet, sorry.

Bernhard

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


Lesenswert?

Bernhard S. schrieb:
> Was passiert eigentlich bei "brcc  PC+2" wie ist "PC+2" zu verstehen?


 PC ist Abkürzung für Program Counter.

 brcc ist "Branch Carry Clear", also wenn kein Übertrag vorhanden,
 überspringe den nächsten Befehl.

 Nächster Befehl ist 2 Byte breit, deswegen +2.

 Klarer ?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Bernhard S. schrieb:
>>Also 16bit * 8bit passt schon mal nicht in ein Registerpaar (16bit).
>
> Korrekt, ich hätte noch dazu schreiben sollen, dass der Wertebereich des
> Ergebnisses die 16 Bit nicht überschreitet, sorry.

In dem Falle kannst du die letzten 3 Befehle (mov/brcc/inc) weglassen. 
...die sind ohnehin nicht korrekt :-)

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


Lesenswert?

Johann L. schrieb:
> In dem Falle kannst du die letzten 3 Befehle (mov/brcc/inc) weglassen.
> ...die sind ohnehin nicht korrekt :-)

 Die sind schon korrekt, nur nicht für negative Zahlen, aber:

   a) So hat er das auch in seinem Beispiel gemacht.
   b) Und da in seinem Beispiel das Vorzeichen ausser Acht gelassen
      wurde, habe ich es auch so gemacht.

 AVR kennt auch MULSU.

: Bearbeitet durch User
von Bernhard S. (bernhard)


Lesenswert?

> Nächster Befehl ist 2 Byte breit, deswegen +2.

> Klarer ?


Ja, danke.

Möglich wäre natürlich auch:

      brcc mpy8x16_EXIT
      ...
      ...
      ...
mpy8x16_EXIT:
      ret

von c-hater (Gast)


Lesenswert?

Bernhard S. schrieb:

> Korrekt, ich hätte noch dazu schreiben sollen, dass der Wertebereich des
> Ergebnisses die 16 Bit nicht überschreitet, sorry.

Dann ist die schnellste Lösung für 16Bit signed*8Bit unsigned:


;->R16:R17: Faktor 1 (16Bit signed)
;  R18    : Faktor 2 (8Bit unsigned)
;<-R17:R16: Produkt
;R2 zerstört, R18 unverändert

  mul R16,R18    ;2
  mov R16,R0     ;1
  mov R2,R1      ;1
  mulsu R17,R18  ;2
  mov R17,R0     ;1
  add R17,R2     ;1
                 ;-
                 ;6

Für die vollen 24Bit sind auch nur zwei Takte mehr erforderlich, dazu 
wären folgende zwei Instruktionen noch an die Routine anzuhängen:

  clr R18        ;1
  adc R18,R1     ;1

Das 24Bit-Ergebnis steht dann in R18::R16.

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Last mich raten wenn, Faktor1 signed mit Faktor2 unsigned multipliziert 
wird, dann iat Signum des Produktes = dem Signum von Faktor1 --->

ergo (also)  Singnum von Faktor1  abtrennen  und im Ergebnsregister 
speichern, die absoluten Faktoren multiplizieren und anschließend zum 
Ergebnisregisteraddieren.

 Fertsch

von Maxx (Gast)


Lesenswert?

Winfried J. schrieb:
> ergo (also)  Singnum von Faktor1  abtrennen  und im Ergebnsregister
> speichern, die absoluten Faktoren multiplizieren und anschließend zum
> Ergebnisregisteraddieren.

In welchem System hast du ein Signum-Bit und kannst das so 
abtrennen/addieren und welches System meinst du nutzt der TO?

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

üblicherweise ist das höchstwertige bit das Signum

also

bei einer 16bit integer  das bit 15 diese kann man durch And 0x8000 
bestimmen
um es zwischenzuspeischern, dann Maskieren mit or ox7fff  sodann kann 
man die integer multiplikation mit unsigned ausführen und schließlich 
signum und produkt wieder zusammenfügen mittels  signum OR 
absolutprodukt   da er noch schreibt der werteberieich von 16bit signed 
wird nicht überschritten mußß er nur das highest bit aufbewahren.

von Eric B. (beric)


Lesenswert?

Winfried J. schrieb:
> üblicherweise ist das höchstwertige bit das Signum
>
> also
>
> bei einer 16bit integer  das bit 15 diese kann man durch And 0x8000
> bestimmen
> um es zwischenzuspeischern, dann Maskieren mit or ox7fff

Das wird aber nicht zum richtigen Ergebnis führen: 0x7FFF ist eben nicht 
0x0001 (0xFFFF == -1). Da fehlt also noch ein Schritt.

Oh, und maskieren macht man mit AND, nicht mit OR.

: Bearbeitet durch User
von Maxx (Gast)


Lesenswert?

Winfried J. schrieb:
> üblicherweise ist das höchstwertige bit das Signum

Üblicherweise eben nicht.
Es gibt zwar bei einigen Systemen z.B. IEEE-754 das Signum aber bei den 
hier üblich diskutierten uCs insbesondere einem AVR greift man bei den 
Registern auf das Zweierkomplement zurück, indem das Vorzeichen in die 
gesammte Bitfolge eingeht.

zwar gilt hier
  signum(z) = -1 genau dann, wenn MSB = 1
  signum(z) = 1 sonst

aber für abs(z) gilt

  abs(z) = z, für signum(z) = 1
  abs(z) = (~z) -1 für signum(z) == -1

(~z) -1 ist offensichtlich nicht z &~ MSB

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Es kommt darauf an was du wie maskieren willst. Das Signum mit filterst 
du mit and AND 0x8000, den absoltwert mit AND 0x7fff
Mit OR fügt man beides wieder zusammen. Sollte ich oben was anderes 
geschrieben haben so bitte ich um Verzeihung, bin krank und war in 
Eile...

Namaste

: Bearbeitet durch User
von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

Maxx schrieb:
> aber bei den
> hier üblich diskutierten uCs insbesondere einem AVR greift man bei den
> Registern auf das Zweierkomplement zurück, indem das Vorzeichen in die
> gesammte Bitfolge eingeht.
>
> zwar gilt hier
>   signum(z) = -1 genau dann, wenn MSB = 1
>   signum(z) = 1 sonst
>

holla,

Darüber habe ich noch nie nachgedacht weil mir die bewährte Methode seit 
30 Jahren geläufig ist. Und ich damit seither nicht mehr befassen 
musste. In C denke ich darüber nicht nach, das soll der Compiler machen 
und in ASM benutze ich halt das Format welches mir seit dem 8bit ATARI 
in Fleisch und Blut übergegangen ist. Blöd  wirds wenn man importiert 
oder exportiert und das Format nich beachtet.

Danke dafür, das muss ich mir dann noch mal näher anschauen.

Namaste

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Winfried J. schrieb:
> Last mich raten wenn, Faktor1 signed mit Faktor2 unsigned multipliziert
> wird, dann iat Signum des Produktes = dem Signum von Faktor1 --->
>
> ergo (also)  Singnum von Faktor1  abtrennen  und im Ergebnsregister
> speichern, die absoluten Faktoren multiplizieren und anschließend zum
> Ergebnisregisteraddieren.
>
>  Fertsch

Und warum so kompliziert???

1) Bei 16 * 8 = 16 ist das Vorzeichen der 16-Bit Zahl Wurscht.

2) AVR hat wie gesagt dedizierte Befehle für Multiplikation von
  -  Signed * Signed
  -  Signed * Unsigned
  -  Unsigned * Unsigned

--> Kein Bit-Gefrickel erforderlich.

Andererseits ist Bit-Gefrickel für das richtige 
Assembler-Look-and-Feel natürlich unentbehrlich!

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Allen danke ich für die sehr wertvollen Informationen.

Bei Atmel fand ich die AVR201 / AVR201.asm.


Was versteht man eigentlich unter "fractional multiply" ?



Bernhard

von Karl H. (kbuchegg)


Lesenswert?

Bernhard S. schrieb:
> Allen danke ich für die sehr wertvollen Informationen.
>
> Bei Atmel fand ich die AVR201 / AVR201.asm.
>
>
> Was versteht man eigentlich unter "fractional multiply" ?

Im Zusammenhang mit der AppNote?

Wenn du im Wirtshaus bist und 7 halbe Bier trinkst, und jede Halbe 3 
Euro kostet, dann hast du 21 Euro für 7 Halbe, bzw. 21 Euro für 3.5 
Liter Bier ausgegeben.

Du willst keine Kommazahlen, weil das kompliziert zu rechnen ist. Also 
nimmst du ein geeignetes Vielfaches. Im Beispiel arbeitest du also nicht 
in ganzen Litern, sondern in halben, weil das die kleinste Einheit ist, 
die du noch berücksichtigen können musst.

von Bernhard S. (bernhard)


Lesenswert?

Für die Division von zwei signierten / unsignierten 16-Bit Zahlen habe 
ich einen separaten Thread angelegt.

Beitrag "Division 16-BIT / 32-Bit (signiert) durch 16-Bit (signiert) Assembler ATmega8 ATmega1284P"

Bernhard

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Karl Heinz schrieb:
> Wenn du im Wirtshaus bist und 7 halbe Bier trinkst, und jede Halbe 3
> Euro kostet, dann hast du 21 Euro für 7 Halbe, bzw. 21 Euro für 3.5
> Liter Bier ausgegeben.

Karl Heinz schrieb:
> Du willst keine Kommazahlen, weil das kompliziert zu rechnen ist.

 Klar, nach 7 Halben.

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.