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.