C asm Inline-Coding im AVR-Studio

OP #2240705
Lesenswert?

Bei der C-Compilierung (Assemblierung) des untenstehenden
Code-Schnipsels  erhalte ich die Fehlermeldung:
...\Temp/ccC9yBGs.s:37: Error: constant value required
Gibt es im Forum einen Experten für diesen speziellen Fall, der mir
helfen kann? Ich habe vieles versucht, aber mir fällt nichts Gescheites
mehr ein.
Wo liegt der Fehler?
Danke im voraus
Georg

static void lcd_out( uint8_t data ) {
   data &= 0xF0;
   // Die 4 Bits im oberen Nibble spiegeln
   //  MSB                       LSB
   //  bit7 bit6 bit5 bit4 0 0 0 0
   // Nach der Spiegelung:
   //  MSB                       LSB
   //  bit4 bit5 bit6 bit7 0 0 0 0
   asm volatile ( "lds r3, data"  "\n\t"
                  "bst r3, 7"     "\n\t"
                  "bld r4, 4"     "\n\t"
                  "bst r3, 6"     "\n\t"
                  "bld r4, 5"     "\n\t"
                  "bst r3, 5"     "\n\t"
                  "bld r4, 6"     "\n\t"
                  "bst r3, 4"     "\n\t"
                  "bld r4, 7"     "\n\t"
                  "lds data, r4"  "\n\t"
                 : /* No Output List */
                 : /* No Input List */
                 : "r3", "r4"
                );
.
.
.
}
Persönliche Seite #2241180
Lesenswert?

Schreibe -save-temps, um die erzeugte Assembler-Datei (*.s) zu erhalten.

Neben dem Fehler, den Ernst schaon aufzeigte, ist er asm-Schnippel 
inkorrekt: data ist eine lokale Variable, für die kein Symbol angelegt 
wird. Das Symbol zu referenzieren führt also zu einem Linkerfehler oder 
zu falschen Code, falls ein gleichnamiges Symbol existiert. Korrekt 
lautet die Sequenz etwa:
1
static void lcd_out (uint8_t data)
2
{
3
   // Die 4 Bits im oberen Nibble spiegeln
4
   //  MSB                     LSB
5
   //  bit7 bit6 bit5 bit4 0 0 0 0
6
   // Nach der Spiegelung:
7
   //  MSB                     LSB
8
   //  bit4 bit5 bit6 bit7 0 0 0 0
9
   asm ("bst %1, 7"     "\n\t"
10
        "bld %0, 4"     "\n\t"
11
        "bst %1, 6"     "\n\t"
12
        "bld %0, 5"     "\n\t"
13
        "bst %1, 5"     "\n\t"
14
        "bld %0, 6"     "\n\t"
15
        "bst %1, 4"     "\n\t"
16
        "bld %0, 7"     "\n\t"
17
        : "=&r" (data)
18
        : "r" (data));
19

20
   data &= 0xF0;
21
   ...
22
}
OP #2241318
Lesenswert?

Herzlichen Dank an Johann L. für die sehr konstruktive und prompte 
Antwort.
Zumindest Compilierung und Assemblierung sind jetzt O.K. Eine 
Verständnisfrage bleibt aber noch:
1. Woher weiss die Assemblerroutine, welches Byte sie manipulieren soll 
und
2. wohin sie es nach getaner Arbeit abspeichern muss?
Die asm-Routine - wenn ich das richtig verstanden habe - arbeitet ja nur 
mit lokalen Variablen. Ich muss aber doch eine aus Sicht des Assemblers 
externe Variable (meine Variable data ) übergeben können und auch 
außerhalb der Routine wieder weiterverarbeiten können.
Persönliche Seite #2241405
Lesenswert?

Georg Schl. schrieb:

> 1. Woher weiss die Assemblerroutine, welches Byte sie manipulieren soll

Es gibt keine "Assemblerroutine" sondern nur einen String, in dem
GCC Ersetzungen macht (Inline Assembler).  Hier wird %0 dem ersten 
Operanden zugeordnet etc. ZB

http://www.rn-wissen.de/index.php/Inline-Assembler_in_avr-gcc

> 2. wohin sie es nach getaner Arbeit abspeichern muss?

Ditto. Das wird durch das Inline-Assembler Interface beschrieben.
Der Compiler allokiert die Register; das ist idR einer handverlesenen 
Vergabe vorzuziehen.

> Die asm-Routine - wenn ich das richtig verstanden habe - arbeitet ja nur
> mit lokalen Variablen. Ich muss aber doch eine aus Sicht des Assemblers
> externe Variable (meine Variable data) übergeben können und auch
> außerhalb der Routine wieder weiterverarbeiten können.

Wie gesagt: es gibt keine Assembler-Routine. Und data ist nicht extern, 
zumindest nicht so, wie extern in dem Zusammenhang verstanden wird: es 
ist eine lokale Variable für den Compiler, und selbst wenn er sie auf 
dem Stack zwischenspeichern muss oder sie auf dem Stapel übergeben 
bekommt, gibt's kein Symbol data. Der Assembler sieht nur ein 
Register.

Übrigens hat das rein garnix mit AVR-Studio zu tun, das ist allein ein 
Ding von avr-gcc bzw. gcc.
OP #2242818
Lesenswert?

Die asm-sequenz kann funktionsidentisch durch die folgenden 2 C-Coding 
Zeilen ersetzt werden:
1
data = ((data >> 1) & 0x55) | ((data << 1) & 0xaa);
2
data = ((data >> 2) & 0x33) | ((data << 2) & 0xcc);
Vielleicht etwas langsamer, dafür aber nachvollziehbar und transparent.
OP #2243278
Lesenswert?

@ Ralf
Die oberen 4 Bits sollten gespiegelt werden, und genau das leisten 
sowohl die beiden vorgeschlagenen C-Coding Zeilen als auch der 
asm-Schnipsel . Damit ist der asm-Schnipsel mit den beiden C-Coding 
Zeilen 'funktionsidentisch'! 'Funktionsähnlich' wäre zu wenig, denn dann 
müsstest Du sagen, in was sich die beiden Ergebnisse unterscheiden.
Gast #2243335
Lesenswert?

Weil wir gerade bei verschiedenen Möglichkeiten sind...
Den Code in eine extra Datei -> dann geht auch der Simulator drüber, 
falls es mal komplizierter wird.
1
extern void dataFunc(volatile uint8_t* data);
2
// 'extern' ist nicht unbedingt nötig.
1
r18  = 18
2
r19  = 19
3
r30  = 30
4
r31  = 31
5

6
.global dataFunc
7
.func dataFunc
8
dataFunc:
9
; Übergabe von Zeiger auf 'data' erfolgt in r24:r25
10
  movw r30, r24
11
  ld r18, Z
12
  mov r19, r18
13
  bst r18, 7
14
  bld r19, 4
15
  bst r18, 6
16
  bld r19, 5
17
  bst r18, 5
18
  bld r19, 6
19
  bst r18, 4
20
  bld r19, 7
21
  st Z, r19
22
  ret
23
.endfunc
24
.end

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