Forum: Compiler & IDEs Optimierungsproblem


von Steffen Graap (Gast)


Lesenswert?

Hallo

Für einen Bootloader benutze ich die folgenden Zeilen
1
volatile register UINT8_t R0 asm("r0");
2
volatile register UINT8_t R1 asm("r1");
3
volatile register UINT8_t R30 asm("r30");
4
volatile register UINT8_t R31 asm("r31");
5
volatile UINT16_t u16Buffercount;
6
7
for (u16Buffercount = 0 ; u16Buffercount < PAGE_BYTE ; u16Buffercount += 2)
8
  {              //solange ausführen, bis alle Bytes der Page beschriebn wurden
9
  R0 = u8Com_RX_Buffer[u16Buffercount];
10
  R1 = u8Com_RX_Buffer[u16Buffercount + 1]; //Daten aus Puffer in R0 & R1 laden
11
  R30 = (UINT8) u16Buffercount; //Wordadresse in Z-Pointer laden
12
  while (SPMCSR & 1);      //warten, das letzte spm beendet
13
  SPMCSR = 1;          //Pagepuffer schreiben vorbereiten
14
  asm volatile ("spm");    //Pagepuffer schreiben ausführen
15
  }
Da Register R30 für den Compiler anscheinend in der Schleife nicht 
benutzt wird, wird erst nach Beendigung der Schleife in R30 ein Wert 
gelanden.
Was mache ich falsch, oder was muss ich machen???

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


Lesenswert?

Steffen Graap wrote:

[Ist offenbar AVR]

>
1
> volatile register UINT8_t R0 asm("r0");
2
> volatile register UINT8_t R1 asm("r1");
3
> volatile register UINT8_t R30 asm("r30");
4
> volatile register UINT8_t R31 asm("r31");
5
>

Don't do it.  All diese Register sind tabu für dich.

Du darfst r2 bis r7 (glaub' ich) relativ gefahrlos benutzen,
die Register ab r8 noch zusätzlich, falls du keine Funktionen
mit großen Argumentlisten benutzt.

r0, r1 und der Z-Zeiger ,,gehören'' dem Compiler.

von Steffen Graap (Gast)


Lesenswert?

genau ist AVR (GCC über eclipse)

die Register brauch man für den "spm"-Aufruf. in R0 & R1 steht das 
Datenword das in den FLASH-Page-Puffer geschrieben werden soll. In R30 
steht die Wordadresse innerhalb des FLASH-Page-Puffer. Das ist ja gerade 
mein Problem das man unbedingt diese Regiter benutzen muss.

Für R30 & R31 hat mich der Compiler mit folgender Warnmeldung auf die 
Nutzung der Register aufmerksamm gemacht. (call-clobbered register used 
for global register variable)

von Andreas K. (a-k)


Lesenswert?

Schon mal einen Blick in <avr/boot.h> riskiert?

von Steffen Graap (Gast)


Lesenswert?

Das ist ja zu einfach, könnte aber funktionieren. Ich werd mich mal 
daran versuchen. Bin halt von meinem letzten Compiler (CodeVision) von 
den mitgelieferten Funktionen nicht so beeindruckt, das ich das meiste 
selbst geschrieben habe. Ich muss mich jetz bei eclips/GCC erst mal 
daran gewöhnen, das es für fast alles fertige Funktionen gibt.

Auch wenn das Problem gelöst ist, aber die Frage bleibt weiter, wie 
bekomme ich den Compiler überzeugt, die Codezeile innerhalb der Schleife 
nicht rauszuoptimiern. (theorethisch, versteht sich)

Danke Steffen

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


Lesenswert?

Steffen Graap wrote:

> Auch wenn das Problem gelöst ist, aber die Frage bleibt weiter, wie
> bekomme ich den Compiler überzeugt, die Codezeile innerhalb der Schleife
> nicht rauszuoptimiern. (theorethisch, versteht sich)

Du kannst mit einer fehlerhaften Eingabe nicht erwarten, dass der
Compiler anschließend das tut, was du dir vorstellst.

Die korrekte Lösung für dieses Problem ist halt ein Stückchen
inline-Assembler-Code, und genau das hast du ja in <avr/boot.h>
bereits vorgefertigt drin.

von Steffen Graap (Gast)


Lesenswert?

Die Lösung für dieses Problem ist natürlich die Verwendung der boot.h. 
Ist ja auch der einfachste Weg.

ABER:
Lass uns an diesem Beispiel das Problem trotzdem lösen.
Wenn ich eine fehlerhafte Eingabe gemacht habe, was meines Wissens nicht 
so ist, wo ist dann der Fehler, schließlich soll man ja aus seinen 
Fehlern lernen.
Prinzipiell funktioniert der oben stehende Code ja auch. Wenn ich den 
Code wie unten stehend abändern würde, würde der Compiler die Verwendung 
von R30 erkennen und in jedem Schleifendurchlauf R30 laden. Allerdings 
füge ich nicht gerne Code ein, der eigentlich nicht benutz wird
1
#define EXT_RAM  (* (UINT8 volatile *) 0x2000)
2
for (u16Buffercount = 0 ; u16Buffercount < PAGE_BYTE ; u16Buffercount += 2)
3
  {              //solange ausführen, bis alle Bytes der Page beschriebn wurden
4
  R0 = u8Com_RX_Buffer[u16Buffercount];
5
  R1 = u8Com_RX_Buffer[u16Buffercount + 1]; //Daten aus Puffer in R0 & R1 laden
6
  R30 = (UINT8) u16Buffercount; //Wordadresse in Z-Pointer laden
7
  EXT_RAM = R30;           //R30 zum schein in den ext. Ram schreiebn
8
  while (SPMCSR & 1);      //warten, das letzte spm beendet
9
  SPMCSR = 1;          //Pagepuffer schreiben vorbereiten
10
  asm volatile ("spm");    //Pagepuffer schreiben ausführen
11
  }
Es muss doch eine bessere Lösung geben, um den Compiler von der 
Benutzung des Registers zu überzeugen.

Gruß Steffen

von Andreas K. (a-k)


Lesenswert?

Aliases für vom Compiler implizit verwendete Register sind nun einmal 
ein Tabu. Jede neue Version des Compilers kann dir diesen schön zurecht 
getrimmten Code über den Haufen schmeissen.

Wenn sowas gemacht werden muss, dann mit asm() Statements. Die sind 
sauber definiert und da darf man diese Register verwenden, wenn man 
bestimmte Regeln einhält. Genau so und nicht anders ist deshalb 
avr/boot.h implementiert.

von Steffen Graap (Gast)


Lesenswert?

Dann ist also der Fehler die Benutzung der Aliasse.

Den Tip mit den Aliassen habe ich von hier:
http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_regbind

Eine Frage zu der boot.h
In den Funktionen boot_page_erase() & boot_page_fill() wird eine 16bit 
Adresse benutzt. Beim ATMEGA256 benötige ich aber insgesammt eine 18bit 
Adresse. Wie nutze ich nun diese 16 bit Adresse?
bei boot_page_erase() entsprechen die 16 Bit nur der Pageadresse?
bei boot_page_fill() entsprechen die 16 Bit der Wordadress im 
Pagebuffer?

Gruß Steffen

von Andreas K. (a-k)


Lesenswert?

Steffen Graap wrote:

> Dann ist also der Fehler die Benutzung der Aliasse.

Ja. Nämlich derjeniger, die man nicht verwenden darf.

> Den Tip mit den Aliassen habe ich von hier:

Da steht aber auch: "Typically, it should be save to use r2 through r7 
that way.". Und das ist zwar orthografisch falsch, inhaltlich sollte man 
sich daran aber halten. Weil es umgekehrt bedeutet, dass die Verwendung 
der anderen Register höchst unsicher ist.

> In den Funktionen boot_page_erase() & boot_page_fill() wird eine 16bit
> Adresse benutzt. Beim ATMEGA256 benötige ich aber insgesammt eine 18bit
> Adresse. Wie nutze ich nun diese 16 bit Adresse?

Ich habe das Include-File grad nicht zu Hand, aber von der Doku her den 
Eindruck, dass die Breite der Adresse abhängig vom Prozessortyp ist. 
Steht nicht ausdrücklich in der Doku drin, aber schau mal ins File rein.

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


Lesenswert?

Andreas Kaiser wrote:

> Da steht aber auch: "Typically, it should be save to use r2 through r7
> that way.". Und das ist zwar orthografisch falsch, inhaltlich sollte man
> sich daran aber halten.

Was ist daran ortografisch falsch?

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


Lesenswert?

Jörg Wunsch wrote:

> Was ist daran ortografisch falsch?

OK, gesehen. ;-)

...und repariert.  Danke.

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.