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.