WinAVR - Sprung zu absoluter Adresse

Gast #547289
Lesenswert?

Hallo allerseits,

ich stehe bei WinAVR momentan vor folgendem Problem: Ich möchte aus 
meiner Applikation heraus meinen Bootloader aufrufen. Da die Applikation 
die Adresse des Bootloaders nicht kennt, habe ich am Ende des Flashs 
einen Sprungbefehl definiert, der zum Bootloader führt. Die Applikation 
muss also nur einen Sprung zur letzten Flashadresse machen und wird dann 
entsprechend weitergeleitet.

Nur - wie macht man so einen Sprung zur letzten Adresse in WinAVR? Alle 
Sprungbefehle scheinen relativ sein. Gibt es einen Befehl wie "goto" für 
absolute Adressen? Auch mit inline Assembler komme ich nicht so recht 
weiter. Wenn ich "rjmp FLASHEND" schreibe, macht er nach dem Compilieren 
daraus etwas wie "rjmp PC+0x0123" - was aufaddiert jedoch nicht FLASHEND 
ergibt.

Was kann ich tun? Ich habs erstmal behelfsmäßig über einen IJMP-Befehl 
gelöst, bei dem ich die FLASHEND-Adresse ins Z-Register schreibe. Da 
muss es aber doch noch einen "ordentlichen" Weg für geben, an eine 
absolute Adresse zu springen?!

Weiß jemand Rat?

Viele Grüße,
Steffen
Gast #547303
Lesenswert?

Definier dir einen Funktionszeiger setzt den Wert des Funktionszeigers 
auf die feste Adresse und rufe dann die Funktion auf. Oder du schreibst 
einfach einen Assemblerbefehl. (mit dem asm statement)
Gast #547312
Lesenswert?

Hallo Bri,

keine Ahnung, wie Funktionszeiger funktionieren, aber das werde ich dann 
mal ausprobieren. An anderer Stelle hätte ich sowas schonmal gebrauchen 
können, dann ist es jetzt wohl Zeit sich soetwas anzuschauen.

Per Assembler geht es leider nicht (bzw. nur per IJMP, siehe oben), weil 
auch dort beim Tiny45 mit dem "rjmp"-Befehl nur relative Sprünge 
unterstützt werden. Und das haut irgendwie nicht hin. Die Adresse, die 
mir vom Linker generiert wird, ist nicht die, die ich angegeben habe.

Danke für Deine Antwort!
Steffen
Gast #547317
Lesenswert?

Also rein als Schuß ins blaue würde ich sagen, es könnte es so gehen:

void (* boot_loader) (); // Definition Variable als Funktionszeiger

boot_loader = 0xF000; // hier richtige Adress eintragen

boot_loader(); // und aufrufen


Gast #548446
Lesenswert?

Hallo Bri,

das war nicht nur ins Blaue, es war ins Schwarze! Nur in der hinteren 
Klammer der Definition muss noch ein "void" stehen - das ist alles.

Übrigens wird aus dem Gebilde am Ende wieder ein "ICALL" mit der 
Sprungadresse im Z-Register. Kein "rjmp", obwohl der ja auch 4K 
adressieren kann (reicht beim Tiny45 aus) und durch das nicht notwendige 
Laden des Z-Registers zwei Befehle weniger benötigen würde.

Vielen Dank für Deine Hilfe!
Steffen
Gast #548475
Lesenswert?

Naja, ein Aufruf über einen Funktionszeiger wird zwangsweise zu einem 
icall. Der Compiler weiß ja nicht, daß er das in diesem speziellen Fall 
nicht braucht.
Es gibt bei gcc auch noch eine Erweiterung, die alternativ gehen könnte. 
Ich kann grad nicht ausprobieren, welcher Code rauskommt, aber du kannst 
es mal versuchen mit:
1
goto *0xf000;

  
#548489
Lesenswert?

Ja, da ist ein schon sehr lange bekannter Bug bis AVR-GCC 3.4.6.

Ein RCALL wird fehlerhaft compiliert und bezieht sich auf die 
Startadresse des aktuellen Objektes, die logischer Weise ja nie 0x0000 
ist.

Damit ist jeder RCALL mit konstanter Adresse zum Scheitern verurteilt.


Beim AVR-GCC 4.1.1. hat man deshalb einen Work-Around gebastelt, indem 
auch konstante Calls mit einem ICALL gemacht werden.

Den RCALL wie bei Funktionsaufrufen vom Linker auflösen zu lassen, war 
wohl zu kompliziert.


Peter
Gast #548537
Lesenswert?

Ich komme etwas spät in diesen Thread...
In meinem Bootloader habe ich mehrere Methoden ausprobiert:
- Von der Applikation komme ich zurück in den Bootloader, indem ich 
einfach den Watchdog "kommen lasse", dafür reicht ein for(;;).
- Vom Bootloader in die Applikation geht am kompaktesten mit zwei "push 
r1" vor dem Funktionsende. Das ergibt eine "gefälschte" 
Rücksprungadresse von 0x0000, denn das Register r1 ist konstant Null.
- Mit Funktionszeiger geht auch, das ist aber etwas mehr Code. Bin sehr 
knapp dran...

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