asm volatile Problem

OP #839513
Lesenswert?
• ▲
▼
Ich probier schon ewig und es klappt nicht.
Ich will für meinen Bootloader nen API-Call aus C aufrufen:
1
asm volatile ("call 2 * 0x1FFE" ::);
funktioniert, aber eben nur für nen 16kB AVR.

Ich müßte also irgendwie statt 0x1FFE FLASHEND schreiben, bloß wie?


Peter
Persönliche Seite #839552
Lesenswert?
• ▲
▼
Dann habe ich mich foppen lassen vom Disassembler-View im AVR Studio.

Ich dachte, wenn man links in der Ansicht den PC sieht (in +1 Schritten) 
und rechts daneben 2 Instruktionsbytes, dann heisst das PC+1 geht 2 
Bytes im ROM weiter. Dazu habe ich mir aus dem Instruction Set 
zurechtgereimt, wieso dort die Einschränkung (call k mit 0 <= k < 64K) 
steht.

Sorry.
Gast #839640
Lesenswert?
• ▲
▼
> asm volatile ("call 2 * 0x1FFE" ::);
>
>
> funktioniert, aber eben nur für nen 16kB AVR.

Ja. Bei den kleineren gibt's kein call.

Man könnt's aber auch in C machen:

((void(*)(void))(FLASHEND/2))();

Hier muß man's dann lustigerweise durch 2 teilen, da FLASHEND eine 
Byteadresse ist, der Aufruf aber eine Word-Adresse will.
Funktioniert aber auch nur bis 128kB korrekt und benutzt aus irgendeinem 
Grund immer icall.
OP #839803
Lesenswert?
• ▲
▼
Rolf Magnus wrote:
> Funktioniert aber auch nur bis 128kB korrekt und benutzt aus irgendeinem
> Grund immer icall.

Ja, mein ATmega2561 guckt dann blöd aus der Wäsche.

Ich machs jetzt so, dann sind Mega8..2561 zufrieden und Z wird nicht 
zerstört.
1
void apicall( void )
2
{
3
  asm volatile("ldi r16, %0" :: "M" ((FLASHEND>>1)&0xFF));      // lo
4
  asm volatile("push r16");
5
  asm volatile("ldi r16, %0" :: "M" ((FLASHEND>>9)&0xFF));      // hi
6
  asm volatile("push r16");
7
#if( FLASHEND > 0x1FFFF )
8
  asm volatile("ldi r16, %0" :: "M" ((FLASHEND>>17)&0xFF));     // xhi
9
  asm volatile("push r16");
10
#endif
11
}


Peter
OP #840113
Lesenswert?
• ▲
▼
Karl heinz Buchegger wrote:
> Ich denke er löst den eigentlichen jump dadurch aus,
> dass er den Returnstack manipuliert.
> -> Funktionsreturn macht den Jump

Jau, so isses.

Die Funktion darf also nicht inlined werden.
Zur Sicherheit noch das hier drüber schreiben:
1
void apicall( void ) __attribute__ ((noinline));
Aufm Mega168 hab ichs getestet, läuft wie dumm.
Ich kann jetzt meine 8kB Daten nichtflüchtig speichern.
EEPROM war gestern.


Peter
Gast #840275
Lesenswert?
• ▲
▼
>> Da fehlt noch ein ret, oder?
>>
> Ich denke er löst den eigentlichen jump dadurch aus,
> dass er den Returnstack manipuliert.

Ja, eben, und dann muß das entsprechende ret dazu aber auch da sein.

> -> Funktionsreturn macht den Jump

Aber deren Rücksprungadresse liegt doch auch noch auf dem Stack. So 
verliert er doch zwei bzw. drei Bytes Stack bei jedem apicall()-Aufruf.
Gast #840290
Lesenswert?
• ▲
▼
Nein, denn die funktion apicall ist doch 'nur' ein jumppad/wrapper und 
die API function soll doch zu dem aufrufer von apicall zurück...

Also der return von apicall nimmt die gerade auf den stack gelegen werte 
und die 'system-funktion' dann die return addresse die der call von 
apicall auf den stack gelegt hatte.

in der ursprünglichen variante, währen das auch 'zwei' returns die 
system-function returned zu apicall und apicall zum aufrufer.

mfg.
olaf
Gast #840497
Lesenswert?
• ▲
▼
@Peter:
Du soltest das register r16 vor und nachher noch sichern, das ist ja 
callee-save definiert.
1
void apicall(void) {
2
  asm volatile (
3
    "mov r0, r16\n"
4
    "ldi r16, lo8(%0)\n"
5
    "push r16\n"
6
    "ldi r16, hi8(%0)\n"
7
    "push r16\n"
8
#if (FLASHEND>0x1FFFF)
9
    "ldi r16, hlo8(%0)\n"
10
    "push r16\n"
11
#endif
12
    "mov r16, r0\n"
13
    : : "i"(FLASHEND/2)
14
  );
15
}

mfg.
olaf
Gast #841034
Lesenswert?
• ▲
▼
nochmal ich...

Habe nochmal alle constrains der gcc asm anweisung angesehen und 
folgende lösung gefunden:
1
void apicall(void) {
2
#if (FLASHEND>0x2000)
3
  asm volatile("jmp %0" :: "p"(FLASHEND&~1));
4
#else
5
  asm volatile("rjmp %0" :: "p"(FLASHEND&~1));
6
#endif
7
}

Vorteil zu obiger lösung, es wird kein weiteres register benötigt und 
solange kein AVR mit 4MB flash in sicht ist, brauch man auch den code 
nicht weiter anfassen.

Geht mit gcc-4.2.0 und gcc-3.4.4.

Ach ja besser ist ein jump und kein call, da apicall ja 'nur' ein jump 
pad ist. Solltest du die function inline declarieren, dann: s/jmp/call/

mfg.
Olaf

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.