Gibt es in GCC auch den SWAP Befehl analog zu Assembler der das untere mit dem oberen Nibbel bei einem Byte vertauscht? Danke schonmal
Geht mit inline Assembler: http://www.roboternetz.de/wissen/index.php/Inline-Assembler_in_avr-gcc#swap_Nibbles
Wenns nicht DERMASSEN(!!) schnell gehen muss..... warum nicht einfach in C mit einer Hilfsvariablen: tmpbyte = swapbyte; swapbyte = <<=4; tmpbyte >>=4; swapbyte |= tmpbyte; Setzt der Compiler normal 1:1 um. Grüßle
hättest du gesucht, hättest du das gefunden
1 | uint8_t swapbyte |
2 | swapbyte = (swapbyte << 4) && (swapbyte >> 4); |
vorher ggf. nach unsigned casten
> Geht mit inline Assembler:
Der Code, den man dort sieht:
1 | static inline unsigned char swap (unsigned char x) |
2 | {
|
3 | asm volatile ("swap %0" : "=r" (x) : "0" (x)); |
4 | return x; |
5 | }
|
kann übrigens noch einen Tick verbessert werden. Inline-Assembler verhindert leider ein "constant folding", weshalb diese Berechnung auch in den Fällen zur Laufzeit durchgeführt wird, in denen es eigentlich nicht nötig wäre. Es gibt bei gcc einen Trick, um auch diese Optimierungen zu ermöglichen. Der geht so:
1 | static inline unsigned char swap (unsigned char x) |
2 | {
|
3 | if (__builtin_constant_p(x)) |
4 | x = (x << 4) | (x >> 4); |
5 | else
|
6 | asm volatile ("swap %0" : "=r" (x) : "0" (x)); |
7 | |
8 | return x; |
9 | }
|
__builtin_constant_p wird zur Compileeit ausgewertet, wodurch das if() auch zur Compilezeit aufgelöst wird. Wenn swap() inline expandiert wird, wird ein zur Compilezeit bekannter übergebener Wert als solche erkannt und die C-Implementation verwendet, die dann ebenfalls zur Compilezeit durchgeführt wird.
@Jörg "oups! natürlich: swapbyte = (swapbyte << 4) & (swapbyte >> 4); sorry" Sollte da nicht ein | anstatt des & stehen?!
Vielen Dankfür die schnelle Hilfe. Habe wieder was gelernt. Klasse Forum. Bis dann 73 & 55
Bei mir optimiert der Compiler leider a = (a<<4) | (a>>4); überhaupt nicht zu einem SWAP Befehl. Aus
1 | typedef uint8_t u08; |
2 | static void rs232_receiveconfig(void) { |
3 | u08 k; |
4 | u08 a, b; |
5 | u08 * addr = (u08 *)eep_config; |
6 | for (k = 0; k < sizeof(eep_config); k++) { |
7 | a = hextobyte(rs232_get_nextbyte()); |
8 | //swap the byte (the lower 4 bits will be zero afterwards)
|
9 | a = (a<<4) | (a>>4); |
10 | b = hextobyte(rs232_get_nextbyte()); |
11 | eeprom_write_byte(addr+k, a | b); |
12 | rs232_put_byte('A'); |
13 | }
|
14 | }
|
wird ein völlig umständliches
1 | rcall rs232_get_nextbyte |
2 | rcall hextobyte |
3 | mov r17,r24 |
4 | .stabn 68,0,64,.LM25-rs232_thread |
5 | .LM25: |
6 | clr r25 |
7 | ldi r18,4 |
8 | 1: lsl r24 |
9 | rol r25 |
10 | dec r18 |
11 | brne 1b |
12 | swap r17 |
13 | andi r17,0x0f |
14 | or r17,r24 |
15 | .stabn 68,0,65,.LM26-rs232_thread |
16 | .LM26: |
17 | rcall rs232_get_nextbyte |
18 | rcall hextobyte |
mit einem Typecast
1 | a = ((u08)(a<<4)) | ((u08)(a>>4)); |
sieht es nur geringfügig besser aus:
1 | rcall rs232_get_nextbyte |
2 | rcall hextobyte |
3 | mov r17,r24 |
4 | .stabn 68,0,64,.LM25-rs232_thread |
5 | .LM25: |
6 | swap r24 |
7 | andi r24,0xf0 |
8 | swap r17 |
9 | andi r17,0x0f |
10 | or r17,r24 |
11 | .stabn 68,0,65,.LM26-rs232_thread |
12 | .LM26: |
13 | rcall rs232_get_nextbyte |
14 | rcall hextobyte |
Der GCC Compiler ist: 3.4.3
Besser als das zweite wird's wohl im Moment nicht. Es müsste jemand, der hinreichend viel RTL versteht, sich mal hinsetzen und gucken, wie man es erreicht, dass er die überflüssigen 4 Befehle einfach weglässt.
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.