Hallo,
Ich versuche folgendes in Inline Assembler zu realisieren:
1
inlinevoidspi_putb(u08b)
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
inlinevoidspi_putb(u08b)
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 :-)
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
staticinlinevoidspi_putb(uint8_tb)
5
{
6
SPDR0=b;
7
while(!(SPSR0&(1<<SPIF0)));
8
9
}
10
11
voiddoit(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.
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?!
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
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.
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:
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
>>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!