Forum: Compiler & IDEs C asm Inline-Coding im AVR-Studio


von Georg S. (hgs07)


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"
                );
.
.
.
}

von Stefan E. (sternst)


Lesenswert?

Georg Schl. schrieb:
> "lds data, r4"  "\n\t"

sts

von Ralf (Gast)


Lesenswert?


von Johann L. (gjlayde) Benutzerseite


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
}

von Georg S. (hgs07)


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.

von Johann L. (gjlayde) Benutzerseite


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.

von Georg S. (hgs07)


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.

von Ralf (Gast)


Lesenswert?

@Georg Schl.
'funktionsähnlich'! Es soll ja nur mit den oberen 4Bits gewürfelt 
werden.

von Georg S. (hgs07)


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.

von Ralf (Gast)


Lesenswert?

@Georg Schl.
Du änderst die unteren 4Bits mit.

von Ralf (Gast)


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

von Georg S. (hgs07)


Lesenswert?

@Ralf
... das gesamte untere Nibble ist aber von vornherein Null. Denn vor dem 
asm-Schnipsel steht
1
data &= 0xF0;
Aber bezogen auf den Allgemeinfall hast Du wohl recht.

von Ralf (Gast)


Lesenswert?

Georg Schl. schrieb:
> ... das gesamte untere Nibble ist aber von vornherein Null.
Mmh. Hatte nicht mehr so weit hochgescrollt.

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.