Interrupt-Routine optimieren möglich?

Hallo,

ich habe mir mittels objdump den ASM-Code für eine Interruptroutine angeschaut:

ISR (TIMER0_COMPA_vect){
 ca0:	1f 92       	push	r1   //Wieso?
 ca2:	0f 92       	push	r0
 ca4:	0f b6       	in	r0, 0x3f	; 63
 ca6:	0f 92       	push	r0   //Warum?
 ca8:	11 24       	eor	r1, r1   //Weshalb der Blödsinn?
 caa:	2f 93       	push	r18
 cac:	8f 93       	push	r24
 cae:	9f 93       	push	r25
  byte p=PWM+=PWMAdd;
 cb0:	90 91 00 01 	lds	r25, 0x0100	; 0x800100 <__data_start>
 cb4:	9f 5b       	subi	r25, 0xBF	; 191
 cb6:	90 93 00 01 	sts	0x0100, r25	; 0x800100 <__data_start>
  byte a=PORTB&0x0F;
 cba:	85 b1       	in	r24, 0x05	; 5
 cbc:	8f 70       	andi	r24, 0x0F	; 15
  if(MotorOn){
 cbe:	20 91 05 01 	lds	r18, 0x0105	; 0x800105 <MotorOn>
 cc2:	22 23       	and	r18, r18
 cc4:	a1 f0       	breq	.+40     	; 0xcee <__vector_21+0x4e>
    if(p>PWMSoll1) a|=0x10;
 cc6:	20 91 04 01 	lds	r18, 0x0104	; 0x800104 <PWMSoll1>
 cca:	29 17       	cp	r18, r25
 ccc:	08 f4       	brcc	.+2      	; 0xcd0 <__vector_21+0x30>
 cce:	80 61       	ori	r24, 0x10	; 16
    if(p>PWMSoll2) a|=0x20;
 cd0:	20 91 03 01 	lds	r18, 0x0103	; 0x800103 <PWMSoll2>
 cd4:	29 17       	cp	r18, r25
 cd6:	08 f4       	brcc	.+2      	; 0xcda <__vector_21+0x3a>
 cd8:	80 62       	ori	r24, 0x20	; 32
    if(p>PWMSoll3) a|=0x40;
 cda:	20 91 02 01 	lds	r18, 0x0102	; 0x800102 <PWMSoll3>
 cde:	29 17       	cp	r18, r25
 ce0:	08 f4       	brcc	.+2      	; 0xce4 <__vector_21+0x44>
 ce2:	80 64       	ori	r24, 0x40	; 64
    if(p>PWMSoll4) a|=0x80;
 ce4:	20 91 01 01 	lds	r18, 0x0101	; 0x800101 <PWMSoll4>
 ce8:	29 17       	cp	r18, r25
 cea:	08 f4       	brcc	.+2      	; 0xcee <__vector_21+0x4e>
 cec:	80 68       	ori	r24, 0x80	; 128
  }
  PORTB=a;
 cee:	85 b9       	out	0x05, r24	; 5
}
 cf0:	9f 91       	pop	r25
 cf2:	8f 91       	pop	r24
 cf4:	2f 91       	pop	r18
 cf6:	0f 90       	pop	r0   //Weg damit
 cf8:	0f be       	out	0x3f, r0	; 63
 cfa:	0f 90       	pop	r0
 cfc:	1f 90       	pop	r1   //Und auch das, warum denn nur?
 cfe:	18 95       	reti

Der erzeugte Code für die Routine ist wirklich gut, besser kann man das glaube ich nicht selber machen.
Nur stören mich einige, meiner Meinung nach, unnütze pushs und pops für die Register r0 und r1.
Über r0 wird das SREG gesichert, muss sein. Aber da r0 im eigentlichen Programm nicht verwendet wird könnte man r0 doch nur 1 mal pushen und poppen. Und vorallem r1. Wird nicht verwendet aber einfach mal pushen und mit eor r1,r1 löschen. Was soll das?
Kann man in der Arduino-IDE diese bescheuerte “Vorlage” verändern oder das ganze ASM einfach rauskopieren, anpassen und in C++ einfügen mit einer Option das der Compiler da nix mehr hinzufügen soll?

MfG
Andi

EDIT: Ach ja, wieso wird denn überhaupt r0 und r1 hergenommen? Man kann doch sowieso nur mit den Registern r16 bis r31 Imediate-Befehle wie ori oder addi machen. Irgendwie scheint mir die Arduino-IDE nicht wirklich gut für die AVRs angepasst zu sein.

Soweit ich weiss ist im C-Kontext das Register 1 als 0 vorausgesetzt.

Das gilt aber nicht auf Assembler Ebene, da könnte sinnvoller Inhalt im Register sein.
Da ein Interrupt jederzeit (also auf Assembler Ebene) auftreten kann, ist es nötig auch R1 zu retten,
da aber wiederum C das Register als 0 erwartet, wird das durch den "Blödsinn" sichergestellt.

Aber in diesem Fall wird r1 ja nicht ein mal verwendet aber trotzdem gepusht und auf 0 gesetzt was ich als Unfug empfinde. Kostet mit dem pop nur Rechenzeit von 5 Takte.
Kann man da nix ändern?

MfG
Andi

Typischer Fall von ‘Optimieren’ an der völlig falschen Stelle, meiner Ansicht nach.
3/4 Zyklen pro Interrupt, würde mich nicht jucken.

Du glaubst der Interrupt Entry Kode sei ohne Sinn und Verstand geschrieben worden?
Ich tu das nicht.

Keine Ahnung wo man das ändern könnte, es mag tief im Kode-Generator verborgen sein,
ich kenne den Quelltext des gcc nicht.

Schreib deine Interruptroutinen in Assembler und benutze die Interrupt Definition, die keinen Entry/Exit Kode erzeugt.

Whandall:
... benutze die Interrupt Definition, die keinen Entry/Exit Kode erzeugt.

Und wie geht das?

MfG
Andi

Wenn du die Frage stellen musst, solltest du es nicht tun.

Denn dann hast du die Dokumentation noch nicht gelesen (und Google oder andere nicht gefragt).

ManualInterrupt.png

http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__interrupts.html

Gesagt und gemacht:

ISR (TIMER0_COMPA_vect, ISR_NAKED){
  asm("push r24 \n in r24,0x3F \n push r24 \n push r25 \n push r18");
 ca0:	8f 93       	push	r24
 ca2:	8f b7       	in	r24, 0x3f	; 63
 ca4:	8f 93       	push	r24
 ca6:	9f 93       	push	r25
 ca8:	2f 93       	push	r18
  byte p=PWM+=PWMAdd;
 caa:	90 91 00 01 	lds	r25, 0x0100	; 0x800100 <__data_start>
 cae:	9f 5b       	subi	r25, 0xBF	; 191
 cb0:	90 93 00 01 	sts	0x0100, r25	; 0x800100 <__data_start>
  byte a=PORTB&0x0F;
 cb4:	85 b1       	in	r24, 0x05	; 5
 cb6:	8f 70       	andi	r24, 0x0F	; 15
  if(p>PWMSoll1) a|=0x10;
 cb8:	20 91 04 01 	lds	r18, 0x0104	; 0x800104 <PWMSoll1>
 cbc:	29 17       	cp	r18, r25
 cbe:	08 f4       	brcc	.+2      	; 0xcc2 <__vector_21+0x22>
 cc0:	80 61       	ori	r24, 0x10	; 16
  if(p>PWMSoll2) a|=0x20;
 cc2:	20 91 03 01 	lds	r18, 0x0103	; 0x800103 <PWMSoll2>
 cc6:	29 17       	cp	r18, r25
 cc8:	08 f4       	brcc	.+2      	; 0xccc <__vector_21+0x2c>
 cca:	80 62       	ori	r24, 0x20	; 32
  if(p>PWMSoll3) a|=0x40;
 ccc:	20 91 02 01 	lds	r18, 0x0102	; 0x800102 <PWMSoll3>
 cd0:	29 17       	cp	r18, r25
 cd2:	08 f4       	brcc	.+2      	; 0xcd6 <__vector_21+0x36>
 cd4:	80 64       	ori	r24, 0x40	; 64
  if(p>PWMSoll4) a|=0x80;
 cd6:	20 91 01 01 	lds	r18, 0x0101	; 0x800101 <PWMSoll4>
 cda:	29 17       	cp	r18, r25
 cdc:	08 f4       	brcc	.+2      	; 0xce0 <__vector_21+0x40>
 cde:	80 68       	ori	r24, 0x80	; 128
  PORTB=a;
 ce0:	85 b9       	out	0x05, r24	; 5
  asm("pop r18 \n pop r25 \n pop r24 \n out 0x3F,r24 \n pop r24");
 ce2:	2f 91       	pop	r18
 ce4:	9f 91       	pop	r25
 ce6:	8f 91       	pop	r24
 ce8:	8f bf       	out	0x3f, r24	; 63
 cea:	8f 91       	pop	r24
  reti();
 cec:	18 95       	reti

Das sieht ja schon mal viel besser aus.
Ich habe mit AVR-ASM schon vor 15 Jahren programmiert. Nach dieser 15-jährigen Pause habe ich mit C++ (Arduino) dieses Jahr erst begonnen. ASM ist kein Problem für mich aber diese hundert tausende C-Optionen kommen halt erst mit der Zeit rein.

Vielen Dank für deine Hilfe.

MfG
Andi

Gerne.

Lies mal die ganze Referenz, zumindestens diagonal.

Praktisch braucht man an der Stelle nur in Ausnahmefällen optimieren,
insofern ist so etwas eher akademisch (oder direkt projektbezogen).

Whandall:
insofern ist so etwas eher akademisch (oder direkt projektbezogen).

Na ja, da der AVR noch die Länge von einem Mehrkanal PPM-Signal per Pin-Change-IRQ mithilfe von Timer1 messen soll sollte diese Routine so kurz wie möglich sein.
Bin selber gespannt was daraus wird.

MfG
Andi