 Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Hallo zusammen,
ich habe einen Cortex M4 (STM32F446) und muß einen Haufen Berechnungen
der Form
int32_t a, b, c;
x(+)= a(*)b
und
x(-)= a(*)b
durchführen. Dabei soll sowohl die Addition als auch die Multiplikation
sättigendend sein (deswegen habe ich Multiplikations- und
Additionszeichen etwas abgewandelt).
Ich wühle mich gerade durch die arm_math.h, die jede Menge interessanter
Operationen bietet, aber eine so einfache häufig gebrauchte (zumindest
in der Computergrafik) Funktion nicht zu bieten scheint.
Der Cortex M3 bietet ja durchaus sättigende Operation im Instruction
Set. Wie kann ich diese Operation unter C sinnvoll nutzen?
*Muß es inline Assembler sein?
*Oder die Operation in C nachbauen und hoffen, daß der Compiler die
richtige Operation daraus macht?
*Oder gibt es einfach noch eine andere ARM-Mathe-Library, die ich
übersehen habe?
Viele Grüße
W.T.
Angehängte Dateien:
-
1.png
53,6 KB, 209 Downloads
-
2.png
18,3 KB, 360 Downloads
Du sprichst ein (meines Wissens nach) Alleinstellungsmerkmal des ARM
Compilers an. Es gibt dort eine gewisse Palette an Idiomen, die
garantiert direkt in die entsprechenden DSP Befehle umgewandlt werden.
Eine Tabelle dieser Idiome hab ich mal eben angehängt.
Persönlich hab ich die Erfahrung gemacht, dass GCC leider nicht alle
dieser Formulierungen so direkt schluckt. Nutzt du alles GCC (oder
Clang?), dann würde ich zur Nutzung der inline Varianten raten... Die
lassen sich ja gegebenenfalls in eigenen Funktionen nach belieben
schachteln.
Hallo Vincent,
danke erstmal für die schöne Tabelle. Ist sie aus dem Buch von Joseph
Yiu?
Erste Erkenntnis: Die sättigenden Multiplikationen beziehen sich nur auf
1x2 Vektoren mit beiden Werten verpackt in einem 32-Bit Wert. Zwar
sicher nett für so manche Anwendung, aber für mich nicht hilfreich.
Zweite Erkenntnis: Es gibt keine sättigende Multiplikation zweier
32-Bit-Werte mit Sättigung auf INT32_MAX/MIN. Aber ich kann zwei
31-Bit-Werte multiplizieren und anschließend auf 31 Bit sättigen. Auch
gut.
Ich habe es mal ausprobiert: 1 | int32_t ssat30(int32_t x)
| 2 | {
| 3 | const int32_t lim = (1L<<30);
| 4 | return (x < -lim ? -lim : (x > lim-1 ? lim-1 : x ) );
| 5 | }
| 6 |
| 7 | void main(void)
| 8 | {
| 9 | [...]
| 10 | int32_t i = INT32_MIN;
| 11 | while( 1 ) {
| 12 | int32_t j = ssat30(i);
| 13 | printf("i=%li, j=%li \n",i, j);
| 14 | i ++;
| 15 | }
| 16 | }
|
Wird mit dem ARM-GCC 5.4.1 zu: 1 | (102) while( 1 ) {
| 2 | (103) int32_t j = ssat30(i);
| 3 | (104) printf("i=%li, j=%li \n",i, j);
| 4 | 0800034A mvn.w r6, #3221225472 ; 0xc0000000
| 5 | 0800034E ldr r5, [pc, #52] ; (0x8000384 <main+212>)
| 6 | 08000350 mov r2, r4
| 7 | 08000352 cmp r4, r6
| 8 | 08000354 it ge
| 9 | 08000356 movge r2, r6
| 10 | 08000358 cmp.w r2, #3221225472 ; 0xc0000000
| 11 | 0800035C it lt
| 12 | 0800035E movlt.w r2, #3221225472 ; 0xc0000000
| 13 | 08000362 mov r1, r4
| 14 | 08000364 mov r0, r5
| 15 | 08000366 bl 0x8000df8 <printf>
| 16 | (105) i ++;
| 17 | 0800036A adds r4, #1
| 18 | 0800036C b.n 0x8000350 <main+160>
| 19 | 0800036E nop
| 20 | 08000370 movs r0, r0
| 21 | 08000372 movs r0, #0
| 22 | 08000374 udf #131 ; 0x83
| 23 | 08000376 orrs r3, r3
| 24 | 08000378 b.n 0x800039c <dda+20>
|
d.h. der Compiler kennt das Idiom nicht. Wahrscheinlich wird es doch mal
Zeit, Inline-Assembler zu lernen.
Nachtrag: Oben war natürlich ein Denkfehler drin. Richtig wäre:
1 | int32_t ssat30(int32_t x)
| 2 | {
| 3 | const int32_t lim = (1L<<30);
| 4 | return (x < -lim-1 ? -lim-1 : (x > lim ? lim : x ) );
| 5 | }
|
und das Ergebnis des Compilers ist: 1 | while( 1 ) {
| 2 | (106) int32_t j = ssat30(i);
| 3 | (107) printf("i=%li, j=%li \n",i, j);
| 4 | 08000352 mvn.w r6, #1073741824 ; 0x40000000
| 5 | 08000356 ldr r5, [pc, #60] ; (0x8000394 <main+228>)
| 6 | 08000358 mov r2, r4
| 7 | 0800035A cmp.w r4, #1073741824 ; 0x40000000
| 8 | 0800035E it ge
| 9 | 08000360 movge.w r2, #1073741824 ; 0x40000000
| 10 | 08000364 cmp r2, r6
| 11 | 08000366 it lt
| 12 | 08000368 movlt r2, r6
| 13 | 0800036A mov r1, r4
| 14 | 0800036C mov r0, r5
| 15 | 0800036E bl 0x8000e08 <printf>
|
Nachtrag: In der core_cmInstr.h hat schon jemand genau das für mich
gemacht. Sehr schön. Der Befehl lautet "__SSAT".
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
- [c]C-Code[/c]
- [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
|