Ich habe hier eine C Zeile mit einem Code, und verstehe nicht, wieso da mulhi3 aufgerufen werden soll. Kann mir das bitte jemand erklären oder ist es ein bekannter BUG ? Danke für die Antworten. CC Arguments sind folgende: bin\avr-gcc %* -Wa,-almshd=a.lst -mcall-prologues -Os -mmcu=attiny24 -Wl,-Map -Wl,a.map for(EEAR = (unsigned int)&cfg_ee,flag=;EEARL<(sizeof(cfg)+(unsigned int)&cfg_ee);CAST(char*,cfg-(unsigned int)&cfg_ee)[EEARL++]=~EEDR) EECR|=(1<<EERE); // copy EEprom to data 6f4: 82 e0 ldi r24, 0x02 ; 2 6f6: 90 e0 ldi r25, 0x00 ; 0 6f8: 9f bb out 0x1f, r25 ; 31 6fa: 8e bb out 0x1e, r24 ; 30 6fc: 2e b3 in r18, 0x1e ; 30 6fe: 2e 5e subi r18, 0xEE ; 238 700: 23 bb out 0x13, r18 ; 19 702: 62 e1 ldi r22, 0x12 ; 18 704: 70 e0 ldi r23, 0x00 ; 0 706: 50 d0 rcall .+160 ; 0x7a8 <__mulhi3> 708: aa 27 eor r26, r26 70a: bb 27 eor r27, r27 70c: a8 1b sub r26, r24 70e: b9 0b sbc r27, r25 710: a7 53 subi r26, 0x37 ; 55 712: bf 4f sbci r27, 0xFF ; 255 714: 0c c0 rjmp .+24 ; 0x72e <main+0x82> 716: e0 9a sbi 0x1c, 0 ; 28 718: 9e b3 in r25, 0x1e ; 30 71a: 8d b3 in r24, 0x1d ; 29 71c: ed 91 ld r30, X+ 71e: fc 91 ld r31, X 720: 11 97 sbiw r26, 0x01 ; 1 722: e9 0f add r30, r25 724: f1 1d adc r31, r1 726: 80 95 com r24 728: 80 83 st Z, r24 72a: 9f 5f subi r25, 0xFF ; 255 72c: 9e bb out 0x1e, r25 ; 30 72e: 9e b3 in r25, 0x1e ; 30 730: 83 b3 in r24, 0x13 ; 19 732: 98 17 cp r25, r24 734: 80 f3 brcs .-32 ; 0x716 <main+0x6a> // cut // 000007a8 <__mulhi3>: 7a8: 55 27 eor r21, r21 7aa: 00 24 eor r0, r0 000007ac <__mulhi3_loop>: 7ac: 80 ff sbrs r24, 0 7ae: 02 c0 rjmp .+4 ; 0x7b4 <__mulhi3_skip1> 7b0: 06 0e add r0, r22 7b2: 57 1f adc r21, r23 000007b4 <__mulhi3_skip1>: 7b4: 66 0f add r22, r22 7b6: 77 1f adc r23, r23 7b8: 61 15 cp r22, r1 7ba: 71 05 cpc r23, r1 7bc: 21 f0 breq .+8 ; 0x7c6 <__mulhi3_exit> 7be: 96 95 lsr r25 7c0: 87 95 ror r24 7c2: 00 97 sbiw r24, 0x00 ; 0 7c4: 99 f7 brne .-26 ; 0x7ac <__mulhi3_loop> 000007c6 <__mulhi3_exit>: 7c6: 95 2f mov r25, r21 7c8: 80 2d mov r24, r0 7ca: 08 95 ret
Wie lange hast du denn gebraucht, um den Code so unlesbar hinzukriegen? Der ist zudem noch fehlerhaft.
1 | for ( |
2 | EEAR = (unsigned int) &cfg_ee, flag=; |
3 | EEARL < (sizeof(cfg) + (unsigned int) &cfg_ee); |
4 | CAST(char *, cfg - (unsigned int) &cfg_ee)[EEARL++] = ~EEDR |
5 | )
|
6 | EECR |= (1 << EERE); // copy EEprom to data |
Es gibt übrigens auch fertige Routinen in der avr-libc für sowas. Die sollte man auch tunlichst verwenden, wegen der Zeigerproblematik.
sorry, dies ist der korrekte Code. cfg_ee ist ein Strukt im EEprom, cfg ist dasselbe Strukt im Ram. CAST ist einfach ein Cast *(char*)(&cfg-(unsigned int)&cfg_ee) Der Grund wieso ich die vorgefertigten Funktionen nicht verwenden will ist die Codegröße. Trotzdem ist die Verwendung von mulhi3 für mich merkwürdig. for(EEAR = (unsigned int)&cfg_ee;EEARL<(char)(sizeof(cfg)+(unsigned int)&cfg_ee);CAST(char*,cfg-(unsigned int)&cfg_ee)[EEARL++]=~EEDR) EECR|=(1<<EERE); // copy EEprom to data 6f4: 22 e0 ldi r18, 0x02 ; 2 6f6: 30 e0 ldi r19, 0x00 ; 0 6f8: 3f bb out 0x1f, r19 ; 31 6fa: 2e bb out 0x1e, r18 ; 30 6fc: c9 01 movw r24, r18 6fe: 62 e1 ldi r22, 0x12 ; 18 700: 70 e0 ldi r23, 0x00 ; 0 702: 55 d0 rcall .+170 ; 0x7ae <__mulhi3> 704: aa 27 eor r26, r26 706: bb 27 eor r27, r27 708: a8 1b sub r26, r24 70a: b9 0b sbc r27, r25 70c: a7 53 subi r26, 0x37 ; 55 70e: bf 4f sbci r27, 0xFF ; 255 710: 2e 5e subi r18, 0xEE ; 238 712: 33 27 eor r19, r19 714: 27 fd sbrc r18, 7 716: 30 95 com r19 718: 0c c0 rjmp .+24 ; 0x732 <main+0x86> 71a: e0 9a sbi 0x1c, 0 ; 28 71c: 9e b3 in r25, 0x1e ; 30 71e: 8d b3 in r24, 0x1d ; 29 720: ed 91 ld r30, X+ 722: fc 91 ld r31, X 724: 11 97 sbiw r26, 0x01 ; 1 726: e9 0f add r30, r25 728: f1 1d adc r31, r1 72a: 80 95 com r24 72c: 80 83 st Z, r24 72e: 9f 5f subi r25, 0xFF ; 255 730: 9e bb out 0x1e, r25 ; 30 732: 8e b3 in r24, 0x1e ; 30 734: 90 e0 ldi r25, 0x00 ; 0 736: 82 17 cp r24, r18 738: 93 07 cpc r25, r19 73a: 7c f3 brlt .-34 ; 0x71a <main+0x6e>
pic user schrieb: > Trotzdem ist die Verwendung von mulhi3 für mich > merkwürdig. Das dürfte einfach das Resultat des verqueren Codes sein.
1 | *(char*)(&cfg-(unsigned int)&cfg_ee) |
Wenn du von einem Pointer auf ein Struct einen Integer-Wert abziehst, muss ja von der Adresse das Ergebnis von (Integer-Wert * sizeof(Struct)) abgezogen werden. Da ist deine Multiplikation. Für mich macht deine ganze Pointer-Arithmetik keinen Sinn. > cfg_ee ist ein Strukt im EEprom, cfg ist dasselbe Strukt im Ram. Und warum sollte dann überhaupt irgendein Bedarf bestehen, die Adressen der beiden irgendwie miteinander zu verrechnen? pic user schrieb: > Der Grund wieso ich die vorgefertigten Funktionen nicht verwenden will > ist die Codegröße. Und auch das klingt für mich ziemlich unsinnig.
> Das dürfte einfach das Resultat des verqueren Codes sein. schein so zu sein. > Wenn du von einem Pointer auf ein Struct einen Integer-Wert abziehst, > muss ja von der Adresse das Ergebnis von (Integer-Wert * sizeof(Struct)) > abgezogen werden. Da ist deine Multiplikation. Wobei, ich habe mulh3 nicht nachfollzogen scheint aber ein *3 zu sein. Aber das Strukt ist 18 bytes groß und es bekommt 18 als input. > Für mich macht deine ganze Pointer-Arithmetik keinen Sinn. >> cfg_ee ist ein Strukt im EEprom, cfg ist dasselbe Strukt im Ram. > Und warum sollte dann überhaupt irgendein Bedarf bestehen, die Adressen > der beiden irgendwie miteinander zu verrechnen? Weil mit dem Array im Ram gearbeitet wird welches vom EEprom initialisiert wird. Das Array sind eigentlich statische Werte, welche im Konfigurationsmodus geändert sowie dann als ganzes ins EEprom gespeichert werden. > > pic user schrieb: >> Der Grund wieso ich die vorgefertigten Funktionen nicht verwenden will >> ist die Codegröße. > > Und auch das klingt für mich ziemlich unsinnig. Code hat jemand anders geschrieben, ich wurde gebeten die Softwäre zu ändern, mehr Funktionalität reinzubringen, und von 1.5kbyte sind es derzeit 2150byte welche ich nocht auf die 2k Grenze runterbringen muss. Danke vielmals für deinen Support. Zum Scluss noch der Code: for(EEAR = (unsigned int)&cfg_ee;EEARL-(uchar)((uint)&cfg_ee+sizeof(cfg));CAST(char*,cfg)[EEA RL++-(uchar)(uint)&cfg_ee]=~EEDR) EECR|=(1<<EERE); // copy EEprom to data 6f4: 82 e0 ldi r24, 0x02 ; 2 6f6: 90 e0 ldi r25, 0x00 ; 0 6f8: 9f bb out 0x1f, r25 ; 31 6fa: 8e bb out 0x1e, r24 ; 30 6fc: 68 2f mov r22, r24 6fe: 6e 5e subi r22, 0xEE ; 238 700: 48 2f mov r20, r24 702: 50 e0 ldi r21, 0x00 ; 0 704: 11 c0 rjmp .+34 ; 0x728 <main+0x7c> 706: e0 9a sbi 0x1c, 0 ; 28 708: 3e b3 in r19, 0x1e ; 30 70a: 2d b3 in r18, 0x1d ; 29 70c: 83 2f mov r24, r19 70e: 90 e0 ldi r25, 0x00 ; 0 710: 84 1b sub r24, r20 712: 95 0b sbc r25, r21 714: e0 91 c9 00 lds r30, 0x00C9 718: f0 91 ca 00 lds r31, 0x00CA 71c: e8 0f add r30, r24 71e: f9 1f adc r31, r25 720: 20 95 com r18 722: 20 83 st Z, r18 724: 3f 5f subi r19, 0xFF ; 255 726: 3e bb out 0x1e, r19 ; 30 728: 8e b3 in r24, 0x1e ; 30 72a: 86 17 cp r24, r22 72c: 61 f7 brne .-40 ; 0x706 <main+0x5a>
Im Vergleich zur stdlib spart dieser unleserliche Code 62 bytes flash, getestet wie folgt: #if 1 #define EEREAD (1<<EERE) #define EEWRITE (1<<EEPE)|(1<<EEMPE) void ee(char x) { char i; EECR=0; for(i=sizeof(cfg)-1,EEAR = (unsigned int)&cfg_ee;EEDR=CAST(char*,cfg)[i++],i--;EECR = (1<<EEMPE),EECR=x,CAST(char*,cfg)[i]=EEDR,--EEARL) while(EECR & (1<<EEPE)); } #else #include <avr/eeprom.h> #if 1 void ee(char x) { if (x==EEREAD) // +62 bytes flash eeprom_read_block((void*)&cfg, (const void*)&cfg_ee, sizeof(cfg)); else eeprom_write_block((const void*)&cfg_ee,(void*)&cfg, sizeof(cfg)); } #else #define EEREAD 0 #define EEWRITE 1 void ee(char x) { char i; // +78 bytes flash for(i=sizeof(cfg);i--;CAST(char*,cfg)[i]=eeprom_read_byte(&cfg_ee+i)) if(x) eeprom_write_byte(&cfg_ee+i,CAST(char*,cfg)[i]); } #endif #endif und hier der ASM code. #if 1 #define EEREAD (1<<EERE) #define EEWRITE (1<<EEPE)|(1<<EEMPE) void ee(char x) { char i; EECR=0; 6ac: 28 2f mov r18, r24 6ae: 1c ba out 0x1c, r1 ; 28 for(i=sizeof(cfg)-1,EEAR = (unsigned int)&cfg_ee;EEDR=CAST(char*,cfg)[i++],i--;EECR = (1<<EEMPE),EECR=x,CAST(char*,cfg)[i]=EEDR,--EEARL) while(EECR & (1<<EEPE)); 6b0: 82 e0 ldi r24, 0x02 ; 2 6b2: 90 e0 ldi r25, 0x00 ; 0 6b4: 9f bb out 0x1f, r25 ; 31 6b6: 8e bb out 0x1e, r24 ; 30 6b8: 94 e0 ldi r25, 0x04 ; 4 6ba: 09 c0 rjmp .+18 ; 0x6ce <ee+0x22> 6bc: e1 99 sbic 0x1c, 1 ; 28 6be: fe cf rjmp .-4 ; 0x6bc <ee+0x10> 6c0: 9c bb out 0x1c, r25 ; 28 6c2: 2c bb out 0x1c, r18 ; 28 6c4: 8d b3 in r24, 0x1d ; 29 6c6: 81 8b std Z+17, r24 ; 0x11 6c8: 8e b3 in r24, 0x1e ; 30 6ca: 81 50 subi r24, 0x01 ; 1 6cc: 8e bb out 0x1e, r24 ; 30 6ce: e0 91 c9 00 lds r30, 0x00C9 6d2: f0 91 ca 00 lds r31, 0x00CA 6d6: 81 89 ldd r24, Z+17 ; 0x11 6d8: 8d bb out 0x1d, r24 ; 29 6da: f0 cf rjmp .-32 ; 0x6bc <ee+0x10>
Das großflächige Entfernen von Leerzeichen und Zeilenumbrüchen im Quellcode wird aber keinen Flash sparen. Das macht den Code nur noch unsleserlicher, als er eh schon ist. Und ich kann mir auch nicht so recht vorstellen, daß du mehr sparst, wenn du die gesamte Funktionalität in den Schleifenkopf steckst. Mir scheint da aber auch ein logischer Fehler drin zu sein. Bei jedem Schleifendurchlauf inkrementierst du i und dekrementierst es wieder. Da du es als Abbruchkriterium nutzt, müßte das eine Endlosschleife ergeben. Ich sehe im Assemblercode auch keine Stelle, an der er wieder aus der Schleife rauskommt.
@Rolf Magnus Danke, ich schlage mich mit dem Code schon zu lange rum, damit mir solche idiotische Fehler unterlaufen. Dies reduziert leider auch die Anzahl der gewonnen bytes, leider. Ich hoffe ich bin fertig geworden, das wird sich morgen zeigen. Mit folgendem Code sind es: #define CFG_GET (1<<EERE) #define CFG_SET (1<<EEPE)|(1<<EEMPE) static void inline config_update(char type) { char i,j; for(j=cfg.ee_limit,i=0,EECR=0,EEAR=(unsigned int)&cfg_ee;j--;EEARL++) { while(EECR & (1<<EEPE));EEDR=CAST(char*,cfg)[i]; EECR = (1<<EEMPE),EECR=type,CAST(char*,cfg)[i++]=EEDR;} } AVR Memory Usage ---------------- Device: attiny24 Program: 2048 bytes (100.0% Full) (.text + .data + .bootloader) Data: 96 bytes (75.0% Full) (.data + .bss + .noinit) EEPROM: 127 bytes (99.2% Full) (.eeprom) und mit diesem: #include <avr/eeprom.h> static void inline config_update(char type) { if (type==EEREAD) // +62 bytes flash eeprom_read_block((void*)&cfg, (const void*)&cfg_ee, cfg.ee_limit); else eeprom_write_block((const void*)&cfg_ee,(void*)&cfg, cfg.ee_limit); } AVR Memory Usage ---------------- Device: attiny24 Program: 2094 bytes (102.2% Full) (.text + .data + .bootloader) Data: 96 bytes (75.0% Full) (.data + .bss + .noinit) EEPROM: 127 bytes (99.2% Full) (.eeprom)
Sven P. schrieb: > Es gibt übrigens auch fertige Routinen in der avr-libc für sowas. Die > sollte man auch tunlichst verwenden, wegen der Zeigerproblematik. Irgendwann wurde die EEPROM-Lib auf indirekten Funktionscall umgestellt und hat riesig Flash verbraucht. Ich hab daher meine eigene Funktion geschrieben. Da Schreiben und Lesen viel gemeinsam hat, habe ich beides in eine Funktion gepackt. Das spart nochmals Code. Obendrein wird unnützes Schreiben vermieden. Man kann also immer die gesamte Struct sichern, auch wenn sich nur ein Element geändert hat.
1 | #include <util\atomic.h> |
2 | |
3 | #define EESTART 0x0001
|
4 | |
5 | #define EE_WRITE 1
|
6 | #define EE_READ 0
|
7 | |
8 | void eeprom( uint8_t *sram, uint16_t eep, uint16_t len, uint8_t write ) |
9 | {
|
10 | uint8_t edat; |
11 | |
12 | do{ |
13 | while( EECR & 1<<EEPE ); // wait until previous write done |
14 | EEAR = eep; |
15 | EECR |= 1<<EERE; // read pulse |
16 | edat = EEDR; |
17 | if( write ){ // if write flag |
18 | if( edat != *sram ){ // and not equal |
19 | EEDR = *sram; // write EEPROM |
20 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE){ |
21 | EECR |= 1<<EEMPE; |
22 | EECR |= 1<<EEPE; // write pulse |
23 | }
|
24 | }
|
25 | }else{ |
26 | *sram = edat; // read EEPROM |
27 | }
|
28 | sram++; |
29 | eep++; // next address |
30 | }while( --len ); |
31 | }
|
32 | |
33 | void save_eedata() |
34 | {
|
35 | eeprom( (void*)&eedata, EESTART, sizeof( eedata ), EE_WRITE ); |
36 | }
|
37 | |
38 | void read_eedata() |
39 | {
|
40 | eeprom( (void*)&eedata, EESTART, sizeof( eedata ), EE_READ ); |
41 | }
|
eedata ist die Struct im SRAM. Peter
pic user schrieb: > Dies reduziert leider auch die Anzahl > der gewonnen bytes, leider. Lass einfach die Hacks. Das ist Käse, nur um ein paar Bytes zu sparen! Verursachen diese paar Bytes mehr denn wirklick Probleme ? Oder ist's von der Sorte "Ich weis da was besser als der Compiler und will auf Biegen nd Brechen das Byte sparen"? Wenn dich die Multiplikation sooo nervt oder wirklich absolut inakzeptabel ist, dann verabschiede dich von deiner alten Toolchain! Und verwende stattdessen was zeitgemässes wie zB avr-gcc 4.7.1. Der macht die Multiplikation nicht mehr per libgcc-Aufruf, zumindest falls der µC über MUL verfügt.
@Peter Dannegger Danke, ein wirklich netter code, und er zeigt mir auch wie man das mit den ATOMIC_BLOCK machen sollte. Nach ein paar defines konnte ich es mit -std=c99 compilieren. Beides werde ich in Zukunft nutzen. Gegenüber der AVR Lib erspart er 20 byte code (version 4.3.3 von GCC) Inzwischen ist der Code auch mit der realen HW getestet und läuft soweit. @ Johann L. (gjlayde) Der Unterschied ist, ob das Programm in den Prozessor reinpasst oder nicht.
pic user schrieb: > @ Johann L. (gjlayde) > Der Unterschied ist, ob das Programm in den Prozessor reinpasst oder > nicht. Lohnt sich denn -mcall-prologues? Das bringt idR nur was bei extrem teuren Funktionen wie float-Berechnungen. Andsonsten hat man eher billige Prologe, und mit -mcall-prologues wird der Code gerne mal größer. Neben -Os gibt's noch weitere Optionen die man antesten kann wie -fno-split-wide-types, -fno-inline-small-functions, -morder1 bzw. -morder2 und natürlich generell intelligentere Unsetzung. Gibt es denn ein nicht verhuntzes, übersetzbares Beispiel für den Code von oben?
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.