Forum: Compiler & IDEs Inline Assembler Code Probleme


von Sebastian S. (rudimentor)


Lesenswert?

Hallo,
ich habe mich aufgrund eines zeitkritischen Codeteils in den Inline 
Assembler reingefummelt. Nun habe ich folgendes Problem.

Zum Ausprobieren habe ich folgenden Code geschrieben:
(Die Inhalte der Arrays sind nur Beispielhaft. 16bit sind schon nötig, 
und ich nutze AVR Studio4 mit GCC und programmiere einen ATMega8 mit 
10MHz. Die Optimierung ist auf -0s eingestellt. Das ganze steckt in 
einer main. Die Arrays werden in der main auf der Ebene der Deklaration 
der PortIO über Funktionen, die mir zum einen die Bitfolge  und zum 
anderen das Delay dazwischen berechnen, deklariert und belegt. Der ganze 
Code ist in C, bis auf die 2 verschachtelten For-Schleifen, die aufgrund 
des präzisen Timings in inline Assembler realisiert werden sollen.
1
uint16_t Bitfolge[10]={1,2,3,4,5,6,7,8,9,10};
2
3
asm volatile(
4
             "    lds r30, Bitfolge"   "\n\t"
5
             "    lds r31, Bitfolge"   "\n\t"
6
             "    ldi r18, 10          "\n\t"
7
             "1:  out 0x15, r30"       "\n\t"
8
             "    adiw r30, 1"         "\n\t"
9
             "    lds r19, 10000       "\n\t"
10
             "    lds r20, 10000       "\n\t"
11
             "2:  nop"                 "\n\t"
12
             "    subi r19"            "\n\t"
13
             "    brne 2b"             "\n\t"
14
             "    dec r18"             "\n\t"
15
             "    brne 1b"             
16
             : : "e" (Bitfolge) : "r18", "r19", "r20", "r30", "r31", "memory");

Das funktioniert auch ganz gut. Die Bitfolge wird an PORTC geschickt und 
zur Kontrolle auf LEDs ausgegeben. Alles so wie es soll. Das Delay mit 
den Nops ist hier nur dazu da, dass ich überhaupt was sehe. Mein Problem 
tritt im nächsten Schritt auf....

In diesem Schritt wollte ich das Delay auf die gleiche Art und Weise wie 
die Bitfolge über ein Array Delay[10] übergeben, dessen Inhalt vorher 
mit der Formel "Zählwert=Delay[s]*Taktfrequenz/Anzahl Takte" berechnet 
wird:
1
uint16_t Bitfolge[10]={1,2,3,4,5,6,7,8,9,10};
2
uint16_t Delay[10]={10000,20000,30000,40000,50000,60000,70000,80000,90000,100000};
3
4
5
asm volatile(
6
             "    lds r30, Bitfolge"   "\n\t"
7
             "    lds r31, Bitfolge"   "\n\t"
8
             "    lds r26, Delay"      "\n\t"
9
             "    lds r27, Delay"      "\n\t"
10
             "    ldi r18, 10          "\n\t"
11
             "1:  out 0x15, r30"       "\n\t"
12
             "    adiw r30, 1"         "\n\t"
13
             "    lds r19, r26         "\n\t"
14
             "    lds r20, r27         "\n\t"
15
             "2:  nop"                 "\n\t"
16
             "    subi r19"            "\n\t"
17
             "    brne 2b"             "\n\t"
18
             "    adiw r26, 1"         "\n\t"
19
             "    dec r18"             "\n\t"
20
             "    brne 1b"             
21
             : : "e" (Bitfolge), "e" (delay) : "r18", "r19", "r20","r26", "r27", "r30", "r31", "memory");

Hier werden mir nun immer Fehler in einem xyz1234.s File produziert, die 
sagen, dass je nach obigen Code (ich habe vieles ausprobiert) z.B. 
X_POINTER_REG nicht gefunden wird? Nehme ich andere Register z.B. 28:27 
kommt die Meldung r28 in asm nicht möglich. Auch alle Register mit 
%A0,%B0, usw. im obigen Code anzugeben ändert nichts. Verwende ich %a0, 
usw. kommen Meldungen über nicht gefundene Referenzen zu x,y,z 
Registern. Weiterhin wird ausgegeben, dass die falschen Constraints 
benutzt wurden. Ich habe alle durch, die etwas mit Pointern zu tun haben 
(und auch sowieso alle anderen), aber der Fehler geht nicht weg. Das .s 
File ist im Temp nach Kompilerangabe, aber ich finde es dort nicht. 
Falls es überhaupt hilft da rein zu schauen?

Was mache ich hier falsch? Ich würde mich über Hinweise sehr freuen, da 
mir so langsam die Ideeen, Internetquellen und Bücher ausgehen. Zumahl 
ich da jetzt schon seit diversen Stunden erfolglos rumkompiliere.

Eine Frage hätte ich noch zusätzlich:
Wie spricht man denn Zahlenwerte an, die die 16bit sprengen, was ja bei 
großen Delays bzw. Zählwerten gut passieren kann?

von Helfer (Gast)


Lesenswert?

> "e" (delay)
       ^

>             "    lds r19, r26         "\n\t"
>             "    lds r20, r27         "\n\t"
                   ^^^

mov statt lds. 2. Operand beim lds muss eine Konstante sein.

von Sebastian S. (rudimentor)


Lesenswert?

Danke für die schnelle Antwort!
Morgen früh werde ich das gleich mal testen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Deine Verwendung von inline Assembler ist nicht korrekt:

* du beschreibst Input-Operanden, verwendest sie aber nicht
* du clobberst Register, die nicht verwendet werden
* in "e" sind weniger Register verfügbar (wegen den Clobbers) als 
benötigt werden
* der Code selbst sieht überaus seltsam aus, zB Verwendung von Z. Du 
kannst so immer nur auf das erste Array-Element zugreifen. Von daher 
scheint es eher angebracht, wenn du bei C bleibst.

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.