Forum: Compiler & IDEs avr-gcc 4.3.3: ISR und Inhalt von R1 bei Eintritt in ISR


von Werner B. (werner-b)


Angehängte Dateien:

Lesenswert?

Beim Durchsehen des erzeugten Listing aus dem Beispielcode für den 
AtXmega128A1
(Appnote AVR1300) bin ich auf die folgende Codesequenz gestossen.
1
ISR(ADCA_CH3_vect)
2
{
3
 244:  1f 92         push  r1
4
 246:  0f 92         push  r0
5
 248:  0f b6         in  r0, 0x3f  ; 63
6
 24a:  0f 92         push  r0
7
 24c:  08 b6         in  r0, 0x38  ; 56
8
 24e:  0f 92         push  r0
9
 250:  18 be         out  0x38, r1  ; 56
10
 252:  09 b6         in  r0, 0x39  ; 57
11
 254:  0f 92         push  r0
12
 256:  19 be         out  0x39, r1  ; 57
13
 258:  0b b6         in  r0, 0x3b  ; 59
14
 25a:  0f 92         push  r0
15
 25c:  1b be         out  0x3b, r1  ; 59
16
 25e:  11 24         eor  r1, r1
17
 260:  0f 93         push  r16
18
  ...

R1 kann vom Vordergrundprogramm jeden beliebigen, zufälligen Wert 
erhalten, Was landet dann in den IO Register 0x38, 0x39 und 0x3B ?

Das verwendete Makefile als Anhang.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

r1 wird möglicherweise beim Xmega genauso behandelt wie bei den 
normalen AVRs

"Falls das Register r1 verändert wird – was z.B. geschieht, wenn man 
Multiplikationsbefehle verwendet – dann muss am Ende des Templates das 
Register wieder auf 0 gesetzt werden, denn bei avr-gcc enthält dieses 
Register immer den Wert 0. Das Register in die Clobber-Liste aufzunehen 
bleibt wirkungslos. Hat man es zerstört, dann schreibt man ans Ende des 
Templates ein clr _zero_reg_ und stellt es dadurch wieder her."
http://www.rn-wissen.de/index.php/Inline-Assembler_in_avr-gcc

Das würde in deinem Listing allerdings bedeuten, dass man eigenen 
Inline-Assembler mit Nutzung von r1 atomar machen muss, d.h. nicht durch 
Interrupts unterbrechbar.

von Peter D. (peda)


Lesenswert?

Werner B. schrieb:
> R1 kann vom Vordergrundprogramm jeden beliebigen, zufälligen Wert
> erhalten, Was landet dann in den IO Register 0x38, 0x39 und 0x3B ?

Mumpitz, sieht also nach nem Compilerbug aus.
Welche GCC-Version its das denn?

R1 ist zwar fast immer 0, aber wenn der Interrupt nach ner 
Multiplikation mit 16Bit Ergebnis zuschlägt, krachts.


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ich glaube, das ist ein Bug.  Hier mal der Code, wie er vom
Codegenerator selbst kommt:
1
.global __vector_74
2
        .type   __vector_74, @function
3
__vector_74:
4
        push __zero_reg__
5
        push r0
6
        in r0,__SREG__
7
        push r0
8
        in r0,56-0
9
        push r0
10
        out 56-0,__zero_reg__
11
        clr __zero_reg__
12
/* prologue: Signal */
13
/* frame size = 0 */
14
/* epilogue start */
15
        pop r0
16
        out 56-0,r0
17
        pop r0
18
        out __SREG__,r0
19
        pop r0
20
        pop __zero_reg__
21
        reti

Die ISR kann sich nicht darauf verlassen, dass _zero_reg_ in der
Tat eine 0 enthält, insofern löscht sie das Register ordentlich,
bevor der eigentliche Code der ISR kommen würde -- aber zuvor
benutzt sie es bereits, um RAMPD zu löschen. :-/

Bitte schreib einen GCC-Bugreport dafür.

(Nicht-Xmegas sind davon nicht betroffen, da sie kein RAMPD-Register
besitzen.)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:

> Bitte schreib einen GCC-Bugreport dafür.

Bitte setz eric.weddington -at- atmel.com gleich mit auf die Cc-Liste
des Bugreports.

von Peter D. (peda)


Lesenswert?

Wäre eigentlich ein schöner Zeitpunkt, endlich mal die Spezialregister 
R0,R1 von ihrer Doppelfunktion zu entbinden und R2,R3 als SREG-Kopie und 
Zero zu nehmen.
Würde pro Interrupt 7 Befehle und 13 Zyklen sparen.


Peter

von (prx) A. K. (prx)


Lesenswert?

Änderungen am ABI sind eine Höllenmaschine. Jeder Assembler-Code muss 
dann mindestens kontrolliert und ggf. umgeschrieben werden, egal ob 
innerhalb GCC oder separater Code.

Ein Register wie R2 global als Platz für die SREG-Kopie von 
Interrupt-Handlern zu reservieren würde in sehr subtiler und schwer 
identifizierbarer Form jene bestehenden Programme abschiessen, die 
verschachtelte Interrupts verwenden. Was bei AVRs zwar nicht die Regel 
ist, aber zulässig.

von Dback (Gast)


Lesenswert?

Ein klarer Fall von, "Das hab ich schon immer so gemacht, so bleibt es 
auch ? - Was neues kommt nicht in Frage" :-))

Tja...muss man halt durch..
Gibts eigentlich das A20-Gate noch ?

von (prx) A. K. (prx)


Lesenswert?

Dback schrieb:

> Ein klarer Fall von, "Das hab ich schon immer so gemacht, so bleibt es
> auch ? - Was neues kommt nicht in Frage" :-))

Solche Registerkonventionen sind eine Grundsatzentscheidung, die in der 
Anfangsphase einer GCC Portierung getroffen wird. Sie im voll 
entwickelten produktiven Produkt zu renovieren braucht mehr Anlass als 
ein paar gewonnene Takte im Interrupt-Handler.

von Dback (Gast)


Lesenswert?

Ist ja auch ok so :-) Die Komptibilität wiegt schwerer.
Das A20-Gate ist übrigens gestern 28 Jahre alt geworden :-)

von Peter D. (peda)


Lesenswert?

A. K. schrieb:
> Änderungen am ABI sind eine Höllenmaschine.

Mit dem R1 gabs ja schon öfters Ärger und es wird auch nicht das letzte 
mal sein.
Man könnte das Zero-Register auch ganz weglassen, der Nutzen ist nur 
sehr gering.


> Ein Register wie R2 global als Platz für die SREG-Kopie von
> Interrupt-Handlern zu reservieren würde in sehr subtiler und schwer
> identifizierbarer Form jene bestehenden Programme abschiessen

Dafür gibts doch ISR_BLOCK, ISR_NOBLOCK, damit könnte man dann das 
zusätzliche Push/Pop steuern.


Peter

von Werner B. (werner-b)


Lesenswert?

Das Problem besteht offenbar nur beim U*nix Compiler von 
Bingo600@avrfreaks.
Ich habe das noch einmal mit WinAVR 20100110 Übersetzt. Da tritt der 
Fehler nicht auf.
1
 244:  1f 92         push  r1
2
 246:  0f 92         push  r0
3
 248:  0f b6         in  r0, 0x3f  ; 63
4
 24a:  0f 92         push  r0
5
 24c:  08 b6         in  r0, 0x38  ; 56
6
 24e:  0f 92         push  r0
7
 250:  09 b6         in  r0, 0x39  ; 57
8
 252:  0f 92         push  r0
9
 254:  0b b6         in  r0, 0x3b  ; 59
10
 256:  0f 92         push  r0
11
 258:  11 24         eor  r1, r1
12
 25a:  18 be         out  0x38, r1  ; 56
13
 25c:  19 be         out  0x39, r1  ; 57
14
 25e:  1b be         out  0x3b, r1  ; 59
15
...

Ich werde den Bug-Report also nur an Bingo600 schicken ;-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Werner B. schrieb:
> Das Problem besteht offenbar nur beim U*nix Compiler von
> Bingo600@avrfreaks.

Das würde bedeuten, dass mir wohl ein Patch fehlt.  Schade auch,
leider hat Eric seine WinAVR-Patches noch nicht ins CVS bei
sourceforge.net gestellt.  Damit kann ich nicht vergleichen, was
da fehlt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Das würde bedeuten, dass mir wohl ein Patch fehlt.

Ich habe die Patches jetzt da.  Werde ich mir demnächst mal angucken,
was mir da durch die Lappen gegangen ist.

von Werner B. (werner-b)


Lesenswert?

Ich hab's gefunden (nicht den Patch, aber was der tun muss).

In gcc/config/avr/avr.c die Zeilen 810-816 ...
1
      /* Clear zero reg.  */
2
      insn = emit_move_insn (zero_reg_rtx, const0_rtx);
3
      RTX_FRAME_RELATED_P (insn) = 1;
4
5
      /* Prevent any attempt to delete the setting of ZERO_REG!  */
6
      emit_insn (gen_rtx_USE (VOIDmode, zero_reg_rtx));

.. nach Zeile 741 (vor /* Push RAMPD, RAMPX, RAMPY. */) verschieben.

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
Noch kein Account? Hier anmelden.