AVR.
Ich benutze gerne einzelne Bits als Status-Flags für alle möglichen
Zustände im Programm (Ersatz für bool). Damit es schneller geht, bringe
ich die Bits in Registern unter. Zum ersten mal beobachte ich einen
Optimierungsfehler:
1 | volatile register struct {
|
2 | unsigned nibble:4;
|
3 | unsigned bit4:1;
|
4 | unsigned bit5:1;
|
5 | unsigned bit6:1;
|
6 | unsigned bit7:1;
|
7 | } status asm("r2");
|
8 |
|
9 | int main(void) {
|
10 | while(status.bit4);
|
11 | }
|
aus der while-Schleife macht der GCC folgendes:
1 | 11: int main(void) {
|
2 | +0000001C: 2D82 MOV R24,R2 Copy register
|
3 | +0000001D: 7180 ANDI R24,0x10 Logical AND with immediate
|
4 | +0000001E: 2388 TST R24 Test for Zero or Minus
|
5 | +0000001F: F7F1 BRNE PC-0x01 Branch if not equal
|
6 | 13: }
|
d.h. er holt R2 nur einmal in den R24, aber danach überprüft er R24
immer wieder auf Null, ohne Ihn vorher zu beschreiben.
Wenn ich die Flags nicht im Register ablege:
1 | volatile struct {
|
2 | unsigned nibble:4;
|
3 | unsigned bit4:1;
|
4 | unsigned bit5:1;
|
5 | unsigned bit6:1;
|
6 | unsigned bit7:1;
|
7 | } status;
|
8 |
|
9 | int main(void) {
|
10 | while(status.bit4);
|
11 | }
|
funktioniert alles wie es soll:
1 | 11: int main(void) {
|
2 | +00000024: 91800060 LDS R24,0x0060 Load direct from data space
|
3 | +00000026: FD84 SBRC R24,4 Skip if bit in register cleared
|
4 | +00000027: CFFC RJMP PC-0x0003 Relative jump
|
5 | 13: }
|
Bei diesem kleinen Beispiel nicht sichtbar, aber mein volles Programm
wird um 300 Byte dicker, wenn ich die zweite Variante benutze. Und
wahrscheinlich auch langsamer.
Ist das ein Bug, der gemeldet werden soll, oder ein Feature, das ich
nicht verstehe?
Wie kann ich das Programm sonst noch veranlassen solange zu warten oder
etwas zu tun, bis eine ISR ein flag setzt?
Danke.