Hier ein C-Code für die Multiplikation von 16Bit Zahlen und als Ergebnis erhält man eine 32Bit Zahl: uint32_t mul16(uint16_t, uint16_t) ersetzt folgenden Ausdruck: 32Bit = 16Bit * 16Bit Mit Optimierung -0s dauert die Multiplikation 37 Taktzyklen (inklusive pop und push der Register). Der Quellcode enthält Inline-Assembler Anteile, was die Multiplikatin beschleunigt. Damit ist es mögliche alle Arten von Zahlen (Ganzzahl und Fließkommahzahlen bis 255) zu rechnen die 16Bit brauchen. Um Fließkommazahlen zu multiplieren müssen diese natürlich erst ins Binäre umgerechnet werden. Dies wird so durchgeführt: Den Ganzzahlligen Dezimalwert in die oberen 8Bit hineinschreiben und den Dezimalen Kommawert mit 2^8 multiplizieren und diesen Wert in die unteren 8Bit hinein schreiben. Anschließend steht im 32Bit Ergebnis in den oberen 16Bit die Ganzzahl und in den unteren 16Bit die Kommazahl. Der Kommawert ist aber nicht Dezimal. Dieser wird Dezimal dadurch dargestellt, dass der Kommawert mit 1/(2^16) multipliziert wird. Als Beispiel: Die Zahl 1,1 gibt in Hex: 0x0119 = 1 im oberen Byte und 25 im niederen Byte. Dadurch hat man zwar eine Auflösung von nur 0,0039 in Dezimal, aber für viele Regelungstechnische Aufgaben oder Filter reicht es aus. Da hier die Geschwindigkeit im vordergrund steht. Verbesserungen und Optimierungen sind erwünscht. Gruß Alex.
Hi, das ist so nicht korrekt, weil Register verändert werden, von denen der Compiler nix mitbekommt. Ausserdem übergibst Du besser die Werte wie sie sind ohne sie von Hand zu zerbröseln, also
1 | [erg] "+r" (res.wert32) // Zugriff mit %A[erg], %B[erg], ... |
ist zudem besser lesbar als Operanden-Nummern.
...und noch ein Fehler: R1 muss am Ende auf 0 gesetzt werden!
Ich denke es muss heissen adc %C0,R1 anstatt add %C0,R1
Danke für den Hinweis. Hier ist die korrigierte Version.
Ok, nur noch ein Schönheitsfehler: result ist uninitialisierte Eingabe von asm, eigentlich sollte gcc das anwarnen. Die korrekte Out-Constraint ist hier "=&r" und nicht "+r".
Danke für den Tip. Im Anhang ist die neue multi16.c Dadurch ist nur ein schreiben der Register möglich. Während "+r" für Ein- und Ausgabe dient. Gruß Alex
Oder gleich in avr-gcc einbauen :-)
1 | (define_insn "umulhisi3" |
2 | [(set (match_operand:SI 0 "register_operand" "=&r") |
3 | (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r")) |
4 | (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))] |
5 | "AVR_HAVE_MUL && !(optimize_size)" |
6 | "mul %B1,%B2 |
7 | movw %C0,r0 |
8 | mul %A1,%A2 |
9 | movw %A0,r0 |
10 | mul %B1,%A2 |
11 | add %B0,r0 |
12 | adc %C0,r1 |
13 | clr __zero_reg__ |
14 | adc %D0,__zero_reg__ |
15 | mul %A1,%B2 |
16 | add %B0,r0 |
17 | adc %C0,r1 |
18 | clr __zero_reg__ |
19 | adc %D0,__zero_reg__" |
20 | [(set_attr "length" "14") |
21 | (set_attr "cc" "clobber")]) |
Wobei bei solch langen Pattern irgendwann die Schmerzgrenze erreicht ist...
Die Aufnahme in die AVR Bibliothek wäre sehr gut. Von den Pattern habe ich leider keine Ahnung, wie die funktionieren und wie diese Aufgebaut sind. Gruß Alex.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.