Erst mal sorry für den komplizierten Betreff, aber mir fiel nix besseres
ein.
Ich erleichtere mir oft das Layout, indem ich die Port-Pins nach
gutdünken verteile und nachher in Software entsprechend darauf
zugreife. Das funktioniert sowohl in C als auch in Assembler bestens
(solange man natürlich nichts zeitkritisches vor hat).
Mir ist nun beim GCC aufgefallen, daß bei der Umsetzung unnötigerweise
einige Byte-Operationen als Word ausgeführt werden. Zum Beispiel:
void set_outputs(uint8_t data)
{
PORTC = (PORTC & 0xF7) | ((data & 0x01)<<3);
PORTD = (PORTD & 0x03) | ((data & 0x7E)<<1);
PORTB = (PORTB & 0xFE) | ((data & 0x80)>>7);
}
Hierbei wird der erste Befehl folgendermaßen umgesetzt:
10: PORTC = (PORTC & 0xF7) | ((data & 0x01)<<3);
IN R18,0x15 In from I/O location
ANDI R18,0xF7 Logical AND with immediate
MOV R20,R24 Copy register
CLR R21 Exclusive OR
MOVW R24,R20 Copy register pair
ANDI R24,0x01 Logical AND with immediate
ANDI R25,0x00 Logical AND with immediate
LDI R22,0x03 Load immediate
LSL R24 Add without carry
ROL R25 Add with carry
DEC R22 Decrement
BRNE -0x04 Branch if status flag cleared
OR R18,R24 Logical OR
OUT 0x15,R18 Out to I/O location
Warum werden denn hier die logischen Operationen mit 16 Bit ausgeführt
(R24/R25) wenn ich doch nur 8 Bit brauche? In diesem Code könnte man
ohne weiteres knapp 50% wegoptimieren.
Ich bin noch grün hinter den Ohren, was C betrifft - mache ich etwas
falsch oder ist das einfach so?
Prinzipiell könnte ich schon mit diesem Overhead leben - aber wenns
nicht unbedingt sein muß, verzichte ich auch gerne drauf ;)
Gruß
Thomas
Daß die logischen Operationen mit 16 Bits ausgeführt werden, wird daran
liegen, daß die von Dir verwendeten Konstanten vom Compiler als
16-Bit-Konstanten (genaugenommen: int) behandelt werden.
Du musst durch ein geeignetes Suffix mitteilen, daß die Konstante einen
anderen Datentyp haben soll.
Allerdings hab' ich keines gefunden, das auf 8-Bit-unsigned verweist.
Unsigned generell wird durch Anhängen eines U signalisiert:
wert = 1234U;
Long (32 Bit) wird durch Anhängen eines L signalisiert
wert = 1234L;
Alternativ könntest Du mal ausprobieren, was geschieht, wenn Du mit
char-Konstanten arbeitest:
void set_outputs(uint8_t data)
{
PORTC = (PORTC & '\xF7') | ((data & '\x01')<<3);
PORTD = (PORTD & '\x03') | ((data & '\x7E')<<1);
PORTB = (PORTB & '\xFE') | ((data & '\x80')>>7);
}
Typecast auf uint8_t sollte besser sein. In der Tat könnte der GCC hier besser optimieren (das darf er, solange dabei dasselbe rauskommt wie bei der type promotion auf 16 bits), hier zeigt sich, dass die meiste Arbeit im GCC eben auf 32- und 64-bit Architekturen gemacht wird, wo man sowas gar nicht erst bemerkt.
Hallo, danke für eure Tipps - jetzt weiß ich auch, was ein "typecast" ist ;) Mit der folgenden Änderung der Zeile: PORTC = (uint8_t)(PORTC & 0xF7) | (uint8_t)((data & 0x01)<<3); wird nun dieser Code produziert - das gefällt mir wesentlich besser. in r25, 0x15 ; 21 andi r25, 0xF7 ; 247 andi r24, 0x01 ; 1 add r24, r24 add r24, r24 add r24, r24 or r25, r24 out 0x15, r25 ; 21
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.