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.
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".
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.