Inline-Assembler Delay

OP #1429358
Lesenswert?

Ich würde gern in Assembler ein delay schreiben.
Leider bekomme ich beim compilieren immer eine Fehlermeldung.

Fehlermeldung:
Compiling C: lcd.c
avr-gcc -c -mmcu=atmega16 -I. -gdwarf-2 -DF_CPU=8000000UL -O0
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall
-Wstrict-prototypes -Wa,-adhlns=./lcd.lst  -std=gnu99 -Wundef -MMD -MP
-MF .dep/lcd.o.d lcd.c -o lcd.o
C:\DOKUME~1\fiedler\LOKALE~1\Temp/cc4OaRcs.s: Assembler messages:
C:\DOKUME~1\fiedler\LOKALE~1\Temp/cc4OaRcs.s:38: Error: garbage at end
of line
C:\DOKUME~1\fiedler\LOKALE~1\Temp/cc4OaRcs.s:39: Error: garbage at end
of line
make.exe: *** [lcd.o] Error 1

Als Compiler benutze ich AVR-GCC.
Ich hoffe jemand kann mir weiter helfen. Danke schonmal.

Code:
void __waitXus(u16 time) {
  register u16 __time = time;

  asm volatile (
    "ldi R25,HIGH(%B[waitTime]); \n\t"
    "ldi R24,LOW(%A[waitTime]);  \n\t"
    "Loop:                       \n\t"
    "sbiw R24,1;                 \n\t"
    "brne Loop;                  \n\t"
  :
  :[waitTime] "r" (__time)
  );
}
Moderator Persönliche Seite #1429508
Lesenswert?

Stefan Ernst schrieb:
> Davon abgesehen, wie soll es möglich sein, per ldi einen variablen Wert
> in die Register zu laden?

;-)

Es gibt bei genauerem Hinsehen noch mehr Enten:

. ldi erwartet einen immediate value, aber der constraint gibt
  ein Register vor

. das Schlüsselwort "register" ist Unsinn; es ist ohnehin das
  constraint, das dem Compiler mitteilt, in welcher Form __temp
  implementiert werden muss

. __temp ist ein reservierter Bezeichner, der in einem Nutzerprogramm
  nichts zu suchen hat

. das separate Anlegen der Variablen __temp ist gar nicht nötig, man
  kann gleich den Parameter temp benutzen

. man braucht eigentlich das Registerpaar auch gar nicht im inline
  asm zu laden, sondern kann das komplett dem Compiler über die
  constraints aufdrängeln

Das nur der Vollständigkeit halber, falls jemand noch den Thread
später liest.  Hatte vorhin halt nicht so genau hingeschaut.
#1429528
Lesenswert?

Jörg Wunsch schrieb:

> Das nur der Vollständigkeit halber, falls jemand noch den Thread
> später liest.

Ok, dann noch als Ergänzung etwas konkreten Code zu den gemachten 
Einwendungen ;-)
1
void waitXus (uint16_t time) {
2

3
  asm volatile (
4
    "0:                       \n\t"
5
    "sbiw %[waitTime],1       \n\t"
6
    "brne 0b                  \n\t"
7
  :
8
  :[waitTime] "w" (time)
9
  );
10
}

Und als weitere Ergänzung: Die Semikolons sind natürlich nicht der 
"garbage" (die machen ja nur den Rest der Zeile zum Kommentar). Es sind 
diese unsinnigen "HIGH(%B[waitTime])" Konstruktionen.
Persönliche Seite #1430134
Lesenswert?

Stefan Ernst schrieb:
> Jörg Wunsch schrieb:
>
>> Das nur der Vollständigkeit halber, falls jemand noch den Thread
>> später liest.
>
> Ok, dann noch als Ergänzung etwas konkreten Code zu den gemachten
> Einwendungen ;-)

Noch ein Einwand: time wird verändert. Falls waitXus einmal als static 
oder inline-Funktion (sehr sinnvoll, also im Header als static inline) 
definiert wird, crasht es früher oder später.

Daher:
1
#include <stdint.h>
2

3
static inline void 
4
waitXus (uint16_t time) 
5
{
6
   __asm__ __volatile__ (
7
     "0: sbiw %[waitTime], 1"     "\n\t"
8
     "brne 0b"
9
       : [waitTime] "+w" (time));
10
}

Das Label hab ich in die gleiche Zeile geschrieben, weil gcc 4 die 
Anzahl der Instruktionen anhand der Zeilen im Inline Asm abschätzt (für 
relative Sprünge darüber).

Johann
Gast #2579951
Lesenswert?

Die Funktion soll ja eigentlich x Mikrosekunden warten. Allerdings muss 
dafür ja der CPU-Takt berücksichtigt werden, oder? Wenn ich richtig 
liege, dann benötigt die Abarbeitung der Inline-Funktion 4*time Takte. 
Mikrosekunden sind es also nur bei 4MHz CPU-Takt, oder habe ich da was 
missverstanden?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren