Hallo, ich habe mir mal das Assembler Progamm angeschaut, welches der GCC erstellt hat. Nun wundert es mich, warum soviele Register auf dem Stack gerettet werden, obwohl sie in der Routine gar nicht verändert werden. Erstmal das C und Assemblerprogramm vom Interruptaufruf: #C SIGNAL (SIG_OVERFLOW0) { systimer_int(); } # ASM SIGNAL (SIG_OVERFLOW0) { 3ca: 1f 92 push r1 3cc: 0f 92 push r0 3ce: 0f b6 in r0, 0x3f ; 63 3d0: 0f 92 push r0 3d2: 11 24 eor r1, r1 3d4: 2f 93 push r18 3d6: 3f 93 push r19 3d8: 4f 93 push r20 3da: 5f 93 push r21 3dc: 6f 93 push r22 3de: 7f 93 push r23 3e0: 8f 93 push r24 3e2: 9f 93 push r25 3e4: af 93 push r26 3e6: bf 93 push r27 3e8: ef 93 push r30 3ea: ff 93 push r31 systimer_int(); 3ec: 3f de rcall .-898 ; 0x6c } 3ee: ff 91 pop r31 3f0: ef 91 pop r30 3f2: bf 91 pop r27 3f4: af 91 pop r26 3f6: 9f 91 pop r25 3f8: 8f 91 pop r24 3fa: 7f 91 pop r23 3fc: 6f 91 pop r22 3fe: 5f 91 pop r21 400: 4f 91 pop r20 402: 3f 91 pop r19 404: 2f 91 pop r18 406: 0f 90 pop r0 408: 0f be out 0x3f, r0 ; 63 40a: 0f 90 pop r0 40c: 1f 90 pop r1 40e: 18 95 reti und nun das Interruptprogramm: #C void systimer_int(void) { extern volatile unsigned short restzeit; static char systimer_time = 0; outp (5, TCNT0); systimer_time++; restzeit--; } # ASM 0000006c <systimer_int>: void systimer_int(void) { extern volatile unsigned short restzeit; static char systimer_time = 0; outp (5, TCNT0); 6c: 85 e0 ldi r24, 0x05 ; 5 6e: 82 bf out 0x32, r24 ; 50 systimer_time++; 70: 80 91 65 00 lds r24, 0x0065 74: 8f 5f subi r24, 0xFF ; 255 76: 80 93 65 00 sts 0x0065, r24 restzeit--; 7a: 80 91 61 00 lds r24, 0x0061 7e: 90 91 62 00 lds r25, 0x0062 82: 01 97 sbiw r24, 0x01 ; 1 84: 90 93 62 00 sts 0x0062, r25 88: 80 93 61 00 sts 0x0061, r24 } 8c: 08 95 ret Warum ist das so und kann man das irgendwie abstellen ? Jogibär
Hi weil der GCC nicht weiß welche Register in systimer_int() verändert werden pusht er alle Arbeitsregister auf den Steck. Schreibe den Code aus systimer_int() direkt in die ISR und die push's werden verschwinden. Matthias
Hallo, das hatte ich schon ausprobiert, und dann wird der Kode auch kleiner. Ich dachte immer, der GCC versucht soetwas zu optimieren. Allerdings sieht ja der GCC im Assemblerprogramm welche Register er wirklich benutzt, und müßte dann die unbenutzten Register vom poppen ausnehmen. Ich denke, ich werde alle Interrupteinsprünge in eine extra Datei aufnehmen, dann herrscht auch dort Ordnung. Danke Michael
Hi, also bei mir werden nicht soviele Register gesichert. Mit welchen Optionen kompilierst Du. Bei mir ist -Os aktiv. Ergebnis: 00000056 <__vector_6>: 56: 1f 92 push r1 58: 0f 92 push r0 5a: 0f b6 in r0, 0x3f ; 63 5c: 0f 92 push r0 5e: 11 24 eor r1, r1 60: 8f 93 push r24 62: 9f 93 push r25 64: af 93 push r26 66: bf 93 push r27 68: 80 91 63 00 lds r24, 0x0063 6c: 90 91 64 00 lds r25, 0x0064 70: a0 91 65 00 lds r26, 0x0065 74: b0 91 66 00 lds r27, 0x0066 78: 01 96 adiw r24, 0x01 ; 1 7a: a1 1d adc r26, r1 7c: b1 1d adc r27, r1 7e: 80 93 63 00 sts 0x0063, r24 82: 90 93 64 00 sts 0x0064, r25 86: a0 93 65 00 sts 0x0065, r26 8a: b0 93 66 00 sts 0x0066, r27 8e: bf 91 pop r27 90: af 91 pop r26 92: 9f 91 pop r25 94: 8f 91 pop r24 96: 0f 90 pop r0 98: 0f be out 0x3f, r0 ; 63 9a: 0f 90 pop r0 9c: 1f 90 pop r1 9e: 18 95 reti aus SIGNAL(SIG_OVERFLOW0) { timer0++; } Oryx
Hallo, mein Makefile ist oben. Ich habe es jetzt in einer extra Datei und per include eingebunden. Damit sind die wahnsinnig vielen pop und push verschwunden. Dies scheint aber grundsätzlich nur aufzutreten, wenn man von Interrupt- einsprungadressen nochmal in eine Funktion überleitet. Bei mir war das bei allen 3 Interupt's so. Michael
Und woher weisst Du, welche Register der Compiler jetzt benötigt? Das musst Du ja jetzt selbst kontrollieren! Und die Fehler, die auftreten, weil im IR ein Reg zuwenig gesichert wird, die will ich nicht finden müssen ... Am Besten ist es, Du verwendest im IR keine Unterprogramme. Dann kann der Compiler auch optimieren. Vorrausschauend die Registerbelegung eines Unterprogramms zu erfassen dürfte für jeden Compiler nahezu unmöglich sein, spätestens dann, wenn die Routine in einem anderen File steht. Stefan
Hallo, generell sollte man in Interrupt Routinen immer möglichst kurz und klein halten. Um sie möglichst kurz zu halen empfiehlt es sich keine Funktionsaufrufe zu verwenden, da man hier zumindest den Sprung zur Funktion und den Rücksprung einsparen kann. Gruß MarkusS
"Vorrausschauend die Registerbelegung eines Unterprogramms zu erfassen dürfte für jeden Compiler nahezu unmöglich sein, spätestens dann, wenn die Routine in einem anderen File steht." Doch, der Keil C51 kann das. Er legt für jede Funktion einen Eintrag der Registerverwendung an. Wird eine Unterfunktion aufgerufen, dann schaut er in der Liste nach, ob dazu ein Eintrag existiert. Wird die Funktion aber erst später compiliert, existiert kein Eintrag und er geht von der maximalen Registerverwendung aus. Stellt er später fest, daß er zu pessimistisch war, compiliert er nochmal und dann weiß er aber schon die Registerverwendung aller Funktionen. Je nach Aufruftiefe können aber noch weitere Durchläufe folgen. Daher ist es besser, man macht ihm die Arbeit einfacher und schreibt die Unterfunktionen möglichst vor den Aufrufer. Peter
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.