mikrocontroller.net

Forum: Compiler & IDEs Inline Assembler


Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Ich versuche folgendes in Inline Assembler zu realisieren:
inline void spi_putb(u08 b)        
{
  SPDR0 = b;
  while(!(SPSR0 & (1<<SPIF0)));

}

Ich habe mir dazu 
http://www.nongnu.org/avr-libc/user-manual/inline_asm.html durchgelesen. 
Aber mir werden sicher einige zustimmen, wenn ich sage, dass es nicht so 
einfach ist, sofort jedes Detail zu verstehen ;)

Ich habe einfach mal per Try&Error folgenden Code geschrieben:

inline void spi_putb(u08 b)        
{
  asm("out %0, %1" "\n\t"
      "sbis %2, 7" "\n\t"
      "rjmp .-4" "\n\t"
      :"=I" (_SFR_IO_ADDR(SPDR0))
      :"r" (b),
       "I" (_SFR_IO_ADDR(SPSR0)));

}

Allerdings funktioniert das ganze auch nicht so recht...
Der Compiler gibt mir folgende Fehlermeldungen aus:

../sd.c:55: error: invalid lvalue in asm statement
../sd.c:50: error: output operand constraint lacks `='


Meine Fragen:

1. Wieso ist der lvalue (damit ist doch sicher die Rückgabe von 
_SFR_IO_ADDR gemeint) invalid?
2. Was hat es mit dem Gleichheitszeichen, das in der Fehlermeldung 
angesprochen wird auf sich?
3. Wann muss ich genau Operanden in den Output-Operand Bereich und wann 
in den Input-Operand Bereich schreiben?
Versteh ich das richtig, dass zB "out" einen Output und einen Input 
Operanden hat, "sbis" jedoch zwei Input Operanden?

Bitte Hilfe :-)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon Küppers wrote:

> Ich versuche folgendes in Inline Assembler zu realisieren:

Nur aus Neugier: warum eigentlich?  Der Compiler macht aus:
#include <stdint.h>
#include <avr/io.h>

static inline void spi_putb(uint8_t b)
{
  SPDR0 = b;
  while(!(SPSR0 & (1<<SPIF0)));

}

void doit(void)
{
        spi_putb(42);
}
das hier:
doit:
        ldi r24,lo8(42)
        out 78-0x20,r24
.L2:
        in __tmp_reg__,77-0x20
        sbrs __tmp_reg__,7
        rjmp .L2
        ret
Ich wüsste nicht, was es da noch einzusparen gäbe. :)

> 1. Wieso ist der lvalue (damit ist doch sicher die Rückgabe von
> _SFR_IO_ADDR gemeint) invalid?

Weil es kein lvalue ist.  Ein output parameter muss Dinge aus dem
inline asm statement ins C-Programm zurückgeben können, dazu benötigt
es ein zuweisbares Objekt (lvalue) im C-Programm.  Ein IO-Register ist
sowas nicht.

Ein IO-Register kann man nur als input parameter übergeben (man
übergibt dessen Wert aus dem C-Programm ins inline asm statement).

> 2. Was hat es mit dem Gleichheitszeichen, das in der Fehlermeldung
> angesprochen wird auf sich?

Das erübrigt sich dann von selbst.

Der clobber ist übrigens auch Quatsch: das bezieht sich nur auf
CPU-Register, nicht auf IO-Register.  Mit einem clobber teilt man ja
dem Compiler lediglich mit, dass er das entsprechende CPU-Register in
dieser Zeit nicht selbst verfügbar hat.  Auf IO-Register (mit Ausnahme
des Stackpointers) greift der Compiler sowieso nicht selbst zu.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Jörg,

Die Iteration
      sbis %2, 7
      rjmp .-4

ist doch wohl kürzer als
        in __tmp_reg__,77-0x20
        sbrs __tmp_reg__,7
        rjmp .L2

oder vertue ich mich da? ;)


>>Weil es kein lvalue ist.  Ein output parameter muss Dinge aus dem
>>inline asm statement ins C-Programm zurückgeben können, dazu benötigt
>>es ein zuweisbares Objekt (lvalue) im C-Programm.  Ein IO-Register ist
>>sowas nicht.

Oha..

>>Ein IO-Register kann man nur als input parameter übergeben (man
>>übergibt dessen Wert aus dem C-Programm ins inline asm statement).

Aha!

>>Der clobber ist übrigens auch Quatsch:....

Was denn für ein Clobber? Ich habe doch nur Input und Output Operands 
angegeben. Für den Clobber übergebe ich doch garkeine Daten. Dafür fehlt 
doch ein ":" am Ende. Oder etwa nicht?!

Autor: Günter R. (galileo14)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, Jörg,

dieses Thema interessiert mich auch sehr. Ich möchte aus einem 
Applikationsprogramm zum Bootloader zurückspringen können und benutze 
dazu derzeit

asm volatile ("jmp 0x1e000"::);

Es gibt noch weitere Eintrittspunkte im Bootloader; diese möchte ich 
alle aber lieber nicht explizit in die Zeile reinschreiben, sondern als 
Defines am Programmanfang angeben, also etwa so:

#define BL_ADDR 0x1e000

asm volatile ("jmp BL_ADDR"::);

Aber so geht es natürlich nicht, weil der Präprozessor innerhalb von 
Strings keine Parameter ersetzt. Also hätte ich gerne geschrieben

asm volatile ("jmp %0" : "???" (BL_ADDR) :);

Aber ich komme nicht drauf, was ich an die Stelle "???" einsetzen müßte; 
das im Thread genannte Asm-Tutorial kenne ich schon (ist Teil des 
avr-libc Reference Manuals), aber in der dortigen Liste der Mnemonics 
(S. 205 in der Version 1.4.3) fehlt "jmp", und auch in der 
Constraint-Liste gibts nichts für Adressen (jedenfalls erkenne ich 
nichts). Kannst Du mir weiterhelfen?

Danke schon mal.

Günter



Autor: Dirk Broßwick (sharandac)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon Küppers wrote:
> Hi Jörg,
>
> Die Iteration
>
>       sbis %2, 7
>       rjmp .-4
> 

irgentwie vermisse ich den zugriff auf das IO bei deiner optimierung :-)

> ist doch wohl kürzer als
>
>         in __tmp_reg__,77-0x20
>         sbrs __tmp_reg__,7
>         rjmp .L2
> 

MfG Dirk

Autor: Dirk Broßwick (sharandac)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
äh ... sorry, sehe selber den fehler :-) schnell vergessen

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon Küppers wrote:

> Die Iteration
>
>       sbis %2, 7
>       rjmp .-4
> 

> ist doch wohl kürzer als

>
>         in __tmp_reg__,77-0x20
>         sbrs __tmp_reg__,7
>         rjmp .L2
> 

Ja, ist sie.  2 Bytes gespart.  Zeit sparst du eh' nicht, weil's ja
eine Warteschleife ist. ;-)  Wenn nicht gerade diese beiden Bytes
darüber entscheiden, dass man sonst die nächstgrößere ROM-Größe nehmen
muss, würde ich dafür meine Zeit nicht mit dem Inline-Assembler
vertun.

>>>Der clobber ist übrigens auch Quatsch:....

> Was denn für ein Clobber?

Sorry, ich habe die drei Zeilen flasch gelesen.  War ein bisschen
zwischen Tür und Angel heute mittag.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Günter R. wrote:

> #define BL_ADDR 0x1e000

> asm volatile ("jmp BL_ADDR"::);

> Aber so geht es natürlich nicht, weil der Präprozessor innerhalb von
> Strings keine Parameter ersetzt.

Naja, dafür gibt's doch die string concetanation:
#define BL_ADDR 0x1e000
#define STR(x) STRINGIFY(x)
#define STRINGIFY(x) #x

void foo(void)
{
  asm volatile ("jmp " STR(BL_ADDR)::);
}

  

Autor: Günter R. (galileo14)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, Jörg,

herzlichen Dank! Funktioniert perfekt! So einfach geht das ... aber man 
muß eben wissen, wie. Auf das doppelte String-Makro wäre ich nicht 
gekommen.

Günter

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>Ja, ist sie.  2 Bytes gespart.  Zeit sparst du eh' nicht, weil's ja
>>eine Warteschleife ist. ;-)  Wenn nicht gerade diese beiden Bytes
>>darüber entscheiden, dass man sonst die nächstgrößere ROM-Größe nehmen
>>muss, würde ich dafür meine Zeit nicht mit dem Inline-Assembler
>>vertun.

Hehe, habe ich auch gemerkt. Man wartet ja eh.. Aber das war ja eh nur 
ein Beispiel. Von daher..

Vielen Dank!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.