Inline Assembler

OP Persönliche Seite #427829
Lesenswert?
• ▲
▼
Hallo,

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

6
}

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:
1
inline void spi_putb(u08 b)        
2
{
3
  asm("out %0, %1" "\n\t"
4
      "sbis %2, 7" "\n\t"
5
      "rjmp .-4" "\n\t"
6
      :"=I" (_SFR_IO_ADDR(SPDR0))
7
      :"r" (b),
8
       "I" (_SFR_IO_ADDR(SPSR0)));
9

10
}

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 :-)
Moderator Persönliche Seite #427861
Lesenswert?
• ▲
▼
Simon Küppers wrote:

> Ich versuche folgendes in Inline Assembler zu realisieren:

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

4
static inline void spi_putb(uint8_t b)
5
{
6
  SPDR0 = b;
7
  while(!(SPSR0 & (1<<SPIF0)));
8

9
}
10

11
void doit(void)
12
{
13
        spi_putb(42);
14
}
das hier:
1
doit:
2
        ldi r24,lo8(42)
3
        out 78-0x20,r24
4
.L2:
5
        in __tmp_reg__,77-0x20
6
        sbrs __tmp_reg__,7
7
        rjmp .L2
8
        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.
OP Persönliche Seite #427866
Lesenswert?
• ▲
▼
Hi Jörg,

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

ist doch wohl kürzer als
1
        in __tmp_reg__,77-0x20
2
        sbrs __tmp_reg__,7
3
        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?!
#427973
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


Moderator Persönliche Seite #428057
Lesenswert?
• ▲
▼
Simon Küppers wrote:

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

> ist doch wohl kürzer als

>
1
>         in __tmp_reg__,77-0x20
2
>         sbrs __tmp_reg__,7
3
>         rjmp .L2
4
>

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.
Moderator Persönliche Seite #428065
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:
1
#define BL_ADDR 0x1e000
2
#define STR(x) STRINGIFY(x)
3
#define STRINGIFY(x) #x
4

5
void foo(void)
6
{
7
  asm volatile ("jmp " STR(BL_ADDR)::);
8
}

  
OP Persönliche Seite #428365
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

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.