Fehler im Compiler oder bei mir ?

#931298
Lesenswert?

Hallo,

ich glaube einen Fehler im Compiler entdeckt zu haben. Vieleicht? 8)
1
+0000003B:   91200062    LDS     R18,0x0062       Load direct from data space
2
44:           if (Status_Relais == 0){                // wenn das Relais aus ist
3
+0000003D:   2322        TST     R18              Test for Zero or Minus
4
+0000003E:   F4C1        BRNE    PC+0x19          Branch if not equal
Das sagt mir ja das der Compiler die Variable 'volatile uint8_t 
Status_Relais' im Ram an die Adresse 0x0062 gelegt hat.
1
46:               if (Anzahlpulse > 50){                  // mindestanzahl von Pulsen erreicht?
2
+00000046:   91800065    LDS     R24,0x0065       Load direct from data space
3
+00000048:   91900066    LDS     R25,0x0066       Load direct from data space
4
+0000004A:   97C3        SBIW    R24,0x33         Subtract immediate from word
5
+0000004B:   F010        BRCS    PC+0x03          Branch if carry set
Und hier liegt 'volatile uint16_t Anzahlpulse' an Adresse 0x0065 & 66 im 
Ram.
1
45:             if (Zeit > 257){                    // längere Zeit keine Pulse mehr gekommen
2
+0000003F:   91800000    LDS     R24,0x0000       Load direct from data space
3
+00000041:   91900064    LDS     R25,0x0064       Load direct from data space
4
+00000043:   5082        SUBI    R24,0x02         Subtract immediate
5
+00000044:   4091        SBCI    R25,0x01         Subtract immediate with carry
6
+00000045:   F3C8        BRCS    PC-0x06          Branch if carry set
Hier aber passt es nicht mehr, jetzt müsste die Variable 'volatile 
uint16_t Zeit' ja an Adresse 0x0000 & 0x0064 liegen. Das kann aber aus 
zwei Gründen nicht sein. Die Adresse 0x0000 sollte das Register R0 sein, 
ist also nicht im Ram. Und folgender Code wiederspricht dem:
1
83:         Zeit = 0;                          // Zeitzähler löschen
2
+000000AE:   92100064    STS     0x0064,R1        Store direct to data space
3
+000000B0:   92100063    STS     0x0063,R1        Store direct to data space
Diesem Code nach liegt sie aber an 0x0063 & 64, was ja auch passen 
würde.

Übersehe ich hier was oder ist das ein Fehler vom Compiler?

Gruß Rene
Gast #931308
Lesenswert?

Wenn die Optimierung eingeschaltet ist, kann der Compiler eine ganze 
Menge machen, was für den Menschen nicht auf den ersten Blick 
verständlich ist. Möglicherweise steht in R0 ja genau der Wert der an 
der Stelle benötigt wird. Ist aus den Codeschnipseln nicht zu erkennen.

Die einzig wichtige Frage hier lautet: _Tut der Code das was er soll?_
#931320
Lesenswert?

Top Soft wrote:
> kann eigentlich nicht sein Variable ist ja volatile.

Das heißt aber nicht, dass der Compiler in jeder Mikrosekunde damit 
rechnet, dass dieser Wert geändert wird. Das ginge schon deshalb nicht, 
weil zum Beispiel 16-Bit-Variablen in einem 8-Bit-AVR nicht atomar 
gelesen oder geschrieben werden können.

Es geht, so wie ich das verstanden habe, eher darum, dem Compiler 
mitzuteilen, dass eine Variable außerhalb des aktuellen Blocks (oder 
Funktion?) geändert werden kann, um bestimmte Optimierungen zu 
verhindern. Wie zum Beispiel so etwas:
1
volatile uint8_t timer_count = 0;
2

3
while(1)
4
  {
5
    /* Tue irgendwas ohne timer_count zu ändern */
6
    if(timer_count > 50) / * Tue was anderes */;
7
   }
Ohne volatile könnte er hier die if-Abfrage wegoptimieren.

Um auf dein Beispiel zurück zu kommen. Ich vermute, dass zu diesem 
Zeitpunkt der Wert aus Adresse 0x0063 aus einer vorherigen Berechnung 
noch in dem temporären Register R0 ist. Das läßt sich aus den 
Schnipseln, die du präsentiert hast, natürlich nicht ablesen. Dann wäre 
der Code weder falsch noch langsamer als wenn man aus Adresse 0x0063 
lesen würde.
#931321
Lesenswert?

Hi,

scheint wohl wirklich am AVR-Studio zu liegen. Hier der Ausschnitt aus 
der main.sym .
1
00800060 b ct1.1354
2
00800061 b ct0.1353
3
00800062 b Status.1328
4
00800063 B Zeit
5
00800065 B Anzahlpulse
6
00800067 B key_press
7
00800068 B key_state

Wenn ich das sei() und cli() aus dem folgenden Code entferne habe ich 
den Fehler sonnst nicht. Schon komisch.
1
  while(1){
2
    if (Status.Relais == 0){                // wenn das Relais aus ist
3
      cli();                          // Interrupts aus wegen 2 Byte Variablen
4
      if (Zeit > 500){                    // längere Zeit (ca 5 sec) keine Pulse mehr gekommen
5
        if (Anzahlpulse > 50){                  // mindestanzahl von Pulsen erreicht?
6
          PORTB |= (1<<PB0);                    // Relais an PB0 ein
7
          Status.Relais = 1;                    // neuen Relaisstatus setzen
8
        }
9
        else{                          // mindestzahl von Pulse nicht ereicht!
10
          Anzahlpulse = 0;                    // Pulsezähler löschen
11
          Zeit = 0;                        // Zeitzähler löschen
12
        }
13
      }
14
      sei();                          // Interrupts wieder an
15
    }
16
    else{                          // wenn das Relais an ist
17
      if( get_key_press( 1<<KEY0 )){              // ist Taste gedrückt?
18
        PORTB &= ~(1<<PB0);                  // Relais an PB0 aus
19
        Status.Relais = 0;                    // neuen Relaisstatus setzen
20
      }
21
    }
22
  }

Gruß Rene
Gast #931323
Lesenswert?

schon alleine wenn ich das hier sehr wird mir schlecht


else{                          // wenn das Relais an ist
      if( get_key_press( 1<<KEY0 )){              // ist Taste gedrückt?
        PORTB &= ~(1<<PB0);                  // Relais an PB0 aus
        Status.Relais = 0;


du springst in die else und frägst dann was mit if ab
und was machste wenn die if nicht war ist
#931325
Lesenswert?

"Ich vermute, dass zu diesem Zeitpunkt der Wert aus Adresse 0x0063 aus 
einer vorherigen Berechnung noch in dem temporären Register R0 ist. Das 
läßt sich aus den Schnipseln, die du präsentiert hast, natürlich nicht 
ablesen. Dann wäre der Code weder falsch noch langsamer als wenn man aus 
Adresse 0x0063 lesen würde."

Nicht langsamer? LDI braucht 3 Takte, wenns schon im Register ist braut 
es keinen!

Gruß Rene
#931343
Lesenswert?

Top Soft wrote:
> Nicht langsamer? LDI braucht 3 Takte, wenns schon im Register ist braut
> es keinen!

Sehr witzig! Ich meinte selbstverständlich "LDI R24,0x0063" im Vergleich 
zu "LDI R24,0x0000". Natürlich könnte man hier die Subtraktion gleich 
auf R0 ausführen und noch ein paar Byte und Taktzyklen sparen. Es wird 
immer wieder Fälle geben, wo der vom Compiler erzeugte Code etwas 
schlechter ist als ein von Hand optimierter.

Nachtrag: Welche Optimierungs"stufe" hast du überhaupt aktiviert. 
Vielleicht kann das der Compiler sogar noch verbessern.
#931344
Lesenswert?

Ja ok liegt definitiv am AVR Studio. Hier das main.lss:
1
if (Zeit > 500){                    // längere Zeit (ca 5 sec) keine Pulse mehr gekommen
2
  7a:  80 91 63 00   lds  r24, 0x0063
3
  7e:  90 91 64 00   lds  r25, 0x0064
4
  82:  85 5f         subi  r24, 0xF5  ; 245
5
  84:  91 40         sbci  r25, 0x01  ; 1
6
  86:  a8 f3         brcs  .-22       ; 0x72 <main+0x20>

Gruß Rene
Gast #931432
Lesenswert?

>Ja ok liegt definitiv am AVR Studio.

Das gute Studio macht zwar ab und zu mal Ärger, aber C-Code compiliert 
es niemals falsch. Garantiert.

Das Studio compiliert nämlich überhaupt keinen C-Code nichts, das macht 
der avr-gcc aus dem WinAVR-Paket. Und da wäre die erste Frage:
Welche WinAVR-Version ist installiert?

Und:
Kannst du mal einen vollständigen, kompilierbaren Code anhängen, und 
nicht nur Ausschnitte? Dazu das Studio-Projekt-File.

Oliver
Gast #931453
Lesenswert?

Nun ja, die beiden gezeigten Disassembler-Beispiele stammen nicht vom 
selben Source-Code:

oben:
>45:             if (Zeit > 257){                    // längere Zeit keine >Pulse 
mehr gekommen

weiter unten (aus main.lss)
>if (Zeit > 500){                    // längere Zeit (ca 5 sec) keine Pulse >mehr 
gekommen

und im oberen Beispiel ist die Disassemblierung auch richtig:
>+0000003F:   91800000    LDS     R24,0x0000

Wenn überhaupt, dann ist der Hexcode schon falsch, oder wird falsch 
gelesen.

Wo und warum da das Problem auftritt, ist wohl noch nicht so ganz klar.

Oliver
#931499
Lesenswert?

"die beiden gezeigten Disassembler-Beispiele stammen nicht vom
selben Source-Code:"

doch ich habe nur zwischenzeitlich am Code weitergearbeitet und den 
vorher willkürlich gewählten Zahlenwert durch denn korrekten ersetzt.

"Wenn überhaupt, dann ist der Hexcode schon falsch, oder wird falsch
gelesen."

der Hexcode ist korrekt, er wird falsch gelesen.

Gruß Rene

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren