Forum: Compiler & IDEs Inline Asm


von Michael S (Gast)


Lesenswert?

Hi, ich habe folgenden Code, um in einer Interruptroutine Port D
einzulesen:
1
unsigned char volatile G_cLastData = 0xAA;
2
3
void __attribute__ ((naked)) SIG_INTERRUPT0 (void) { 
4
  // Port D einlesen 
5
   __asm__ __volatile( 
6
      "push    r2"          "\n\t" 
7
      "in      r2, %1"      "\n\t" 
8
      "sts     %2, r2"      "\n\t" 
9
      "pop     r2"          "\n\t" 
10
      "reti" 
11
      : 
12
      : "M" (_SFR_IO_ADDR(PORTD)) 
13
      : "i" (&G_cLastData) 
14
   ); 
15
}

Leider bringt mir der Compiler folgende Meldung:
[quote]
../Treiber_Parallel.c: In function `__vector_1':
../Treiber_Parallel.c:143: error: parse error before '(' token
C:\AVR\WinAVR\utils\bin\make.exe: *** [Treiber_Parallel.o] Error 1

[/quote]

Zeile 143 ist:
1
: "i" (&G_cLastData)

Kann mir jemand sagen, woher diese Meldung kommt, bzw. wie ich sie weg
bekomme?

Ps:
Für diejenigen, die bei Roboternetz mitlesen, tut mir leid für den
Doppelpost, aber es ist sehr wichtig!

Freundlichen Gruss
Michael

von Rolf Magnus (Gast)


Lesenswert?

Mir scheint die leere Liste von Ausgangsoperanden falsch zu sein. Das i
(&G_cLastData) ist glaub ich auch kein  korrekter Eintrag für die
clobber-Liste. Es scheint alles um eins verschoben zu sein. Mach mal
den ersten Doppelpunkt weg.

von Michael S (Gast)


Lesenswert?

Hi, danke für deine Antwort.
Ich habe jetzt folgendes ausprobiert:
1
void  __attribute__ ((naked)) SIG_INTERRUPT0 (void){
2
   __asm__ __volatile( 
3
      "push    r2"          "\n\t" 
4
      "in      r2, %1"      "\n\t" 
5
      "sts     %2, r2"      "\n\t" 
6
      "pop     r2"          "\n\t" 
7
      "reti" 
8
      : "M" (_SFR_IO_ADDR(PORTD)) 
9
      : "i" (&G_cLastData) 
10
    );
11
}
liefert:
[quote]
../Treiber_Parallel.c: In function `__vector_1':
../Treiber_Parallel.c:200: error: invalid lvalue in asm statement
../Treiber_Parallel.c:192: error: output operand constraint lacks `='
C:\AVR\WinAVR\utils\bin\make.exe: *** [Treiber_Parallel.o] Error
1
[/quote]

von Michael S (Gast)


Lesenswert?

Wenn ich das mit der clobber-Liste richtig verstanden habe teilt diese
doch dem Compiler nur mit, welche Werte sich geändert haben, oder?

Und da ich das Speichern in G_cLastData ja bereits im Asm Code mache,
muss ich als Output nichts angeben?! Ansonsten hätte ich mir das
1
"sts     %2, r2"      "\n\t"

sparen können, oder?

Gruss
Michael

von Michael S (Gast)


Lesenswert?

Der Asm-Code hierzu, wie ich meine dass es ohne Clobber gehört:
1
void  __attribute__ ((naked)) SIG_INTERRUPT0 (void){
2
   __asm__ __volatile( 
3
       "in %0,%1"        "\n\t"
4
       "reti"
5
             : "=&r" (G_cLastData) 
6
             : "I" (_SFR_IO_ADDR(PORTD))
7
    );
8
}

wäre
1
     d5a:  82 b3         in  r24, 0x12  ; 18
2
     d5c:  18 95         reti
3
     d5e:  80 93 79 00   sts  0x0079, r24
4
     d62:  80 91 79 00   lds  r24, 0x0079

allerdings wird hier das R24 verwendet, welches ja vorher nicht
gesichert wird!

Gruss
Michael

von Michael S (Gast)


Lesenswert?

Noch eine Frage:
Ist groß 'I' eigentlich das Gleiche wie klein 'i'?
Sprich ist das Ganze case sensitiv?

Gruss
Michael

von Rolf Magnus (Gast)


Lesenswert?

Ich hatte nicht genau genug hingesehen. Also, du liest aus dem
IO-Register und schreibst in den Speicher. Dann ist _SFR_IO_ADDR(PORTD)
ein Input-Parameter.
Was ist "i" eigentlich für ein Operandentyp? Den kann ich in der
avr-libc-Doku nicht finden. Vielleicht ist das der Fehler?

> Wenn ich das mit der clobber-Liste richtig verstanden habe teilt
> diese doch dem Compiler nur mit, welche Werte sich geändert haben,
> oder?

Ja. Du teilst damit dem Compiler mit, daß deine asm-Routine intern z.B.
mit einem Register arbeitet, das weder input- noch output-Parameter ist
und das von der Routine in geändertem Zustand hinterlassen wird.
Dadurch weiß der Compiler dann, daß er - wenn er den Wert nicht
verlieren darf - diesen sichern muß.

Wegen der Variablen, auf die zugegriffen wird, müßte es eigentlich
reichen, wenn diese als volatile deklariert ist. Als clobber muß man
sie dann nicht mehr angeben.
Ich weiß nur nicht, wie bzw. ob du dieses Adresse als Operand angeben
kannst. Wenn G_cLastData keine globale Variable ist, geht's so eh
nicht, da die Adresse dann erst zur Laufzeit bekannt ist. Bei einer
globalen Variable sehe ich aber das Problem, daß der Compiler die
Adresse noch nicht kennt, da sie erst vom Linker festgelegt wird.
Die avr-libc-Doku schweigt sich leider dazu aus.

von Michael S (Gast)


Lesenswert?

Ja das ganze ist wirklich nicht sonderlich gut dokumentiert.
Ja ich lese PortD ein, und will es in eine globale Variable G_cLastData
schreiben.

Das Problem scheint nur zu sein, dass meine Funktion naked ist. Wenn
ich also im Asm-Teil das Output benutze, habe ich danach keine
Möglichkeit mehr was zu tun, auchnicht das reti!

Gruss
Michael

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Schreib das Teil in eine separate Datei und dort komplett in
Assembler, statt derartige Verrenkungen zu machen.

#include <avr/io.h>

.global SIG_INTERRUPT0
SIG_INTERRUPT0:
  push  r2
  in  r2, _SFR_IO_ADDR(PORTD)
  sts  G_cLastData, r2
  pop  r2
  reti

Das Ganze kommt in eine Datei isr.S (per Konvention ein großes S am
Ende) und wird beim Standard-WinAVR-Makefile unter ASRC angegeben.

von Michael S (Gast)


Lesenswert?

Hi, gute Idee.
Habs gleich ausprobiert und einen Eintrag ASRC = isr.S in meinem
Makefile erzeugt.

Leider bekomme ich dann folgende Meldung:
C:\AVR\WinAVR\utils\bin\make.exe: *** No rule to make target
`isr.o', needed by `AppMain.elf'.  Stop.

Hast du eine Ahnung woran das liegt?

Grüsse
Michael

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Hast du eine Ahnung woran das liegt?

An deinem Makefile.

von Michael S (Gast)


Lesenswert?

Muss amn da noch an anderer Stelle etwas mitteilen? Ausser ASRC...

Gruss
Michael

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Naja, offenbar fehlt ihm irgendwie die Regel, wie man aus einer
.S-Datei eine .o-Datei erzeugt.  Er erkennt ja noch, dass er
die zugehörige .o-Datei braucht, aber es fehlen die Kommandos,
sie zu bauen.

# Assemble: create object files from assembler source files.
%.o : %.S
  @echo
  @echo $(MSG_ASSEMBLING) $<
  $(CC) -c $(ALL_ASFLAGS) $< -o $@

Sowas steht in Eric Weddington's Makefile-Template herum, ist
GNU-make
Syntax.  Generische make-Syntax wäre:

# Assemble: create object files from assembler source files.
.S.o:
  $(CC) -c $(ALL_ASFLAGS) $< -o $@

Nur so, mit Groß-/Kleinschreibung hast du dich aber nicht
vertan?  Wenn die Datei Isrs.S heißt, wird das make sie nicht
finden, wenn es isrs.o bauen soll.

von Michael S (Gast)


Angehängte Dateien:

Lesenswert?

So etwas ähnliches ist mit drin.
Habe mein Makefile mal mit angehängt.
Die Datei auf der Platte heisst isr.S, genauso wie im Makefile..

Gruss
Michael

von Michael S (Gast)


Lesenswert?

Hmm lag wohl daran, dass ich ExtCoff erzeugt habe. Hab mal ein Makefile
erstellt, in dem ich nur Coff erzeuge, und dann gehts.

Danke für die Hilfe
Gruss
Michael

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.