Forum: Compiler & IDEs Fehler im Compiler oder bei mir ?


von Top S. (topsoft)


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

von ATU Fan (Gast)


Lesenswert?

kannst du niocht schlafen oder was

von Top S. (topsoft)


Lesenswert?

Vieleich, vieleicht auch nicht. Aber was hat das mit meiner Frage zu 
tun?

Gruß Rene

von Klaus (Gast)


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?_

von Top S. (topsoft)


Lesenswert?

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

Nein tut er nicht.

"Möglicherweise steht in R0 ja genau der Wert der an
der Stelle benötigt wird."

kann eigentlich nicht sein Variable ist ja volatile.

Gruß Rene

von Stefan E. (sternst)


Lesenswert?

Der Output sieht nach dem Disassembler-Fenster vom AVR-Studio aus. Ich 
meine, ich hätte ähnliches auch schon gehabt, was aber ein Fehler vom 
AVR-Studio war. Schau also besser erstmal im HEX-File nach, was 
tatsächlich dort steht.
Oder schau in das LSS-File, auch dem würde ich eher trauen, als dem 
AVR-Studio.

von Detlev T. (detlevt)


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.

von Top S. (topsoft)


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

von bingo (Gast)


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

von Top S. (topsoft)


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

von Stefan E. (sternst)


Lesenswert?

> Hier der Ausschnitt aus der main.sym .

Das war jetzt aber die falsche Stelle zum nachschauen, denn was sagt das 
aus über den erzeugen Assembler-Code?

von Top S. (topsoft)


Lesenswert?

"du springst in die else und frägst dann was mit if ab
und was machste wenn die if nicht war ist"

ja nix, wo liegt das Problem?

Gruß Rene

von Top S. (topsoft)


Lesenswert?

"Das war jetzt aber die falsche Stelle zum nachschauen, denn was sagt 
das
aus über den erzeugen Assembler-Code?"

nichts, aber über die Lage der Variablen im Ram.

Gruß Rene

von Stefan E. (sternst)


Lesenswert?

bingo wrote:

> du springst in die else und frägst dann was mit if ab
> und was machste wenn die if nicht war ist

Na nichts. Was soll daran problematisch sein?

von Stefan E. (sternst)


Lesenswert?

Top Soft wrote:

> nichts, aber über die Lage der Variablen im Ram.

Die stand doch schon im ersten Post fest.
Du weißt aber immer noch nicht, ob da nun tatsächlich "LDS R24,0x0000" 
im Code steht, oder nicht.

von Detlev T. (detlevt)


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.

von Top S. (topsoft)


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

von Top S. (topsoft)


Lesenswert?

"Sehr witzig! Ich meinte selbstverständlich "LDI R24,0x0063" im 
Vergleich
zu "LDI R24,0x0000"."

Schon klar, aber es drängte aus mir. ;-))

Nacht Rene

von Stefan E. (sternst)


Lesenswert?

@ Detlev T.:

Wenn der Compiler hier tatsächlich vor hätte r0 zu verwenden (und ich 
bin nicht deiner Meinung, dass er es hier dürfte), dann würde er das 
ganz sicher nicht mit einem LDS auf Adresse 0 machen.

von Oliver (Gast)


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

von Andreas K. (a-k)


Lesenswert?

Das Studio kompiliert nix, aber es disassembliert sehr wohl. Und um den 
Output vom integrierten Disassembler geht es ja offenbar. Wie oben schon 
erwähnt zeigt das LSS-File den korrekten Code, WinAVR kommt also nicht 
als Schuldiger in Frage.

von Oliver (Gast)


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

von Top S. (topsoft)


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

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.