Forum: Compiler & IDEs Inline assembler Anfänger


von Udo S. (Firma: allround) (1udo1)


Lesenswert?

Hallo,

ich benötige eine Anfahrhilfe für den Inline assembler. Ihr kennt 
sicherlich dieses Beispiel aus dem Tutorial:

Meine Frage:

Der Aufruf des Assmblers soll doch die Bits 0000 0101 im Register 
"result" um ein Bit nach rechts verschieben.
Danach soll der neue Wert, also 0000 1010 in value abgespeichert sein, 
oder?
Im AVR Studio wird in 60H die 05H und in 62H die 04H angezeigt.

Ich mache sicherlich einen fehler, weiß aber nicht wo. Kann jemand mir 
sagen, wo es lang geht?


Udo


#include <avr/io.h>

  int  result=5;
  int  value=4;
  int  TAPP;

void main(void)
{
  DDRB =0xff;
  while (1)
  {
  asm("mov %0, %1, ror#1" : "=r" (result) : "r" (value));
  PORTB=TAPP;
  TAPP++;
  }
}

von Jörg X. (Gast)


Lesenswert?

Wenn du tatsächlich von
>> 0b0000 0101
nach
>> 0b0000 1010
schieben willst - geht das mit ROL ('L' wie links) besser ;)
1
 //und
2
asm("mov %0, %1 ror#1" : "=r" (result) : "r" (value));
3
//wirst du wohl so (oder so aehnlich) schreiben muessen:
4
asm(    "mov %0, %1 \n\t"
5
        "ror %0     \n\t"
6
        : "=&r" (result)
7
        : "r" (value)  );
Lies dir unbedingt mal das 
http://www.roboternetz.de/wissen/index.php/Inline-Assembler_in_avr-gcc 
durch.

hth. Jörg

von Udo S. (Firma: allround) (1udo1)


Lesenswert?

Hallo Jörg,

Danke für Deine Antwort. Leider funktioniert Dein Vorschlag auch nicht. 
Die Zellen bleiben unverändert mit den Anfangswerten. Der Inline 
assembler bewirkt nichts.

Ich verstehe das nicht. Dieses Beispiel ist doch wirklich nicht 
kompliziert. Der Compiler meldet keinen Fehler und ber built ist auch 
o.k.
Das Manual, dass Du mir empfohlen hast, habe ich schon von vorne bis 
hinten und zurück gelesen. Auch andere Tutorials durchforstet. Es gibt 
mir keine weiteren Ideen, wie der Inline assembler meine Bits schieben 
kann. Funktionieret auf Deinem Rechner die Schieberei?

Habe die aktuellen Versionen von AVR Studio und gcc.


#include <avr/io.h>

  int  result=6;
  int  value=34;
  int  TAPP;

void main(void)
{
  DDRB =0xff;
  while (1)
  {
  asm("mov %0, %1, \n\t"   /* schiebt nicht!!*/
        "rol %0     \n\t"
        : "=&r" (result)
        : "r" (value)  );

    PORTB=TAPP;
    TAPP++;
  }
}

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


Lesenswert?

Vielleicht beschreibst du ja dein gesamtes Problem mal?  Der Inline-
Assembler ist eine riesige Kanone, mit der man besser nicht auf
Spatzen schießt.  Er benutzt viele der internen Compiler-Mechanismen
selbst, was ihn einerseits flexibel aber andererseits reichlich
unübersichtlich gestaltet.

von Udo S. (Firma: allround) (1udo1)


Lesenswert?

Hallo Jörg,

in meinem Bühnenprogramm setze ich viele verschiedenen LED Lauflichter 
mit 100en LEDs ein. Ebenfalls über Triacs gesteuerte Lichtanlagen. Viele 
Lichtmuster erzeuge ich mit Rotationen im Akku. In gcc gibt es meines 
Erachtens keinen vergleichbaren Rotationsbefehl, oder doch? Diese 
Rotation im Akku brauche ich immer wieder. Aber natürlich genauso die 
kurzen Ausgabebefehle, Warteschleifen usw. mit gcc.

Kurzum:

Ich möchte meine Programme mit gcc in Verbindung mit dem Inline 
assembler optimieren. Das ist der Grund, warum ich den Inline assembler 
nutzen möchte.

Mich würde mal wirklich interessieren, ob ich einer der Wenigen bin, bei 
denen die Beispiele aus dem AVR Tutorial, Roboternetz Wissen usw. nicht 
klappen.

Muss der Inline assembler im C-Programm vielleicht vorher irgendwie 
angekündigt werden. Wenn es bei mir nicht klappt, dann dürfte es doch 
bei allen, die AVR Sudio4 und gcc benutzen (aktuellste Version) auch 
nicht klappen.

Noch zum Schluß:

Habe folgendes noch probiert:

void main(void)
{
  DDRB =0xff;
  DDRD =0xff;
  while (1)
  {

   PORTD=TAPP;
   TAPP--;

   asm("mov %0, %1, \n\t"
   "rol %0     \n\t"
   : "=&r" (result)
   : "r" (value)  );

  PORTB=TAPP;
  TAPP++;
  }
}

Im AVR Studio Simulator springt beim Single Step der Cursor immer nur 
von Ausgabe PORTD zu Ausgabe PORTB. Der Inline assembler kommt gar nicht 
zum Zug. Also auch keine Rotation.

von Jörg X. (Gast)


Lesenswert?

Ok, ICH hatte das auch gestern abend nicht getestet.
So funktioniert dein Beispiel - auch wenn ich nicht exakt weiß, was es 
tun soll ;) - d.h. es compiliert und simuliert.
1
#include <stdint.h>
2
#include <avr/io.h>"
3
4
int main(void)
5
{
6
7
  uint8_t result = 0x01;
8
  int8_t step = 0x74;
9
  DDRB =0xff;
10
  DDRD =0xff;
11
  while (1){
12
13
     PORTD = step;
14
     step--;
15
16
     asm ("mov %0, %1 \n\t"
17
    "rol %0     \n\t"
18
    : "=&r" (result)
19
    : "r" (step)  );
20
21
    PORTB = result;
22
    
23
  }
24
}
Aber auch ich hab was gelernt - ich werde den Inline Assembler solange 
meiden wie die Hölle, solange irgednwie möglich.
 Es scheint ja definitiv leichter aus einem .lss- oder .s-File ein neues 
.S-File zu machen, als jedes mal wieder die Inline-Assembler-doku zu 
bemühen ;)

hth. Jörg
ps.:
> Ich möchte meine Programme mit gcc in Verbindung mit dem Inline
> assembler optimieren.
ein heres Ziel, ist aber mit einem C-Buch und der (besser 
verständlichen) AVR-libc-doku einfacher zu erreichen.

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


Lesenswert?

Naja, ROL und ROR rotieren ja nicht wirklich das Register, sondern
sie rotieren aus dem / in das Carry-Flag.  Um das Register zu rotieren,
brauchst du also noch ein paar Assemblerbefehle mehr.  Letztlich bist
du dann ebenso bei 4 Befehlen, wie die C-Notation.

Hier mein Testbeispiel:
1
#include <inttypes.h>
2
#include <avr/io.h>
3
4
static inline uint8_t
5
rol(uint8_t x)
6
{
7
#ifdef USE_ASM
8
        asm volatile(
9
                "clc" "\n\t"
10
                "sbrc %0, 7" "\n\t"
11
                "sec" "\n\t"
12
                "rol %0"
13
                : "=&r"(x));
14
        return x;
15
#else
16
        uint8_t y;
17
18
        y = x << 1;
19
        if (x & 0x80) y |= 1;
20
21
        return y;
22
#endif
23
}
24
25
void
26
flicker(uint8_t x)
27
{
28
29
        PORTB = x;
30
        x = rol(x);
31
        PORTB = x;
32
        x = rol(x);
33
        PORTB = x;
34
}

Es finden sich im Code ein paar überflüssige "clr r25", aber das ist
unabhängig davon, ob man mit -DUSE_ASM oder nicht compiliert.
Letztlich spart die inline-assembler-Version für die Funktion
flicker() ganze zwei Takte ein (14 statt 16).  Weiß nicht, ob das
wirklich den Aufwand mit der Kryptizität des inline asm Wert ist.

von Udo S. (Firma: allround) (1udo1)


Lesenswert?

Also, Jörg,


Danke für Deine Mühe,

das geht mir zu sehr ins Eingemachte. Ich kann das mit meinen bisherigen 
Kenntnissen nicht nachvollziehen, was da im compiler passiert. Also, 
werde ich den inline assembler zu den Akten legen.

Eine abschließende Frage:

Gibt es überhaupt eine sinnvolle Alternative in gcc den 
Rotationsbefehl,-- wie im assembler --- umzusetzen? Oder geht das im gcc 
nur über Umwege, die allein der wirklich versierte Experte (effizient?) 
programmieren kann.

Udo

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


Lesenswert?

Ich schrieb doch oben schon, Rotieren in deinem Sinne kann selbst
der Assembler nicht.  ROL und ROR sind Schiebebefehle, keine echten
Rotationen.

Der Compiler benutzt ROL/ROR und SHL/SHR bereits.

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.