mikrocontroller.net

Forum: Compiler & IDEs mspgcc inline assembler nested loops


Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann der inline assembler auch nested loops verarbeiten? Das Manual gibt 
zu den Labels nichts her. Eine einfache Schleife ist einfach, jedoch ist 
nirgendwo beschrieben, wie nested Loops auszusehen haben und ob das 
überhaupt geht.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst, wie überall im gas (GNU assembler), "local labels" benutzen.
Das sieht ungefähr so aus:
1:   something
     something else
2:   more stuff
     goes here
     breq 99f
     other stuff
     brne 2b
     even more junk
     brne 1b
99:

Beim Sprungziel bezeichnet ein angehängtes `b', dass der entsprechende
Label rückwärts zu suchen ist, ein `f', dass die Suche vorwärts
statt findet.   Wenn es Labels mit gleicher Nummer gibt, ,,gewinnt''
der, der in Suchrichtung am nächsten liegt.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh danke, die Beispiele, die ich nur gefunden hatte, bezogen sich immer 
nur auf eine Schleife.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag. Und wenn man genau hinschaut, da steht in den Beispielen 
tatsächlich 1b und nicht lb. Hier sieht es auch noch gleich aus. Ich 
habe das 1b als Abkürzung für Label gelesen.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast wrote:

> Nachtrag. Und wenn man genau hinschaut, da steht in den Beispielen
> tatsächlich 1b und nicht lb. Hier sieht es auch noch gleich aus. Ich
> habe das 1b als Abkürzung für Label gelesen.

Beitrag "Re: Merkwürdige Fragen (Forum-Trolle?)"

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe jetzt ein wenig mit dem Syntax rumgespielt. Er ist einfach nur 
furchtbar :-) Aber für eine einfache aber genaue delay-Routine sollte er 
reichen.

Hier der Code, unabhängig davon, was er macht:
    void delay_ms(int time, int count)
    {
        __asm__ __volatile__
        (
          "1:                           \n\t"
          "2:                           \n\t"
          " dec %[inner]                \n\t"
          " jne 2b                      \n\t"
              : [inner] "=r"(time)
          " dec %[outer]                \n\t"
          " jne 1b                      \n\t"
              : [outer] "=r"(count)
        );
    }

Ich erhalte den Fehler "Syntax error before string constant". Gemeint 
ist damit die Zeile mit " dec %[outer]                \n\t".

Um den grauenvollen Syntax erst einmal zu verstehen, habe ich 
verschiedene Quellen benutzt:
http://www.roboternetz.de/wissen/index.php/Inline-...
http://mspgcc.sourceforge.net/manual/c1308.html
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assemb...

Abgeleitet war die Loop aus einem Beispiel, wo ein "+r" verwendet wurde. 
Es ist nirgendwo beschrieben, scheint aber zu funktionieren. Egal. Wo 
der Fehler oben liegt, habe ich noch nicht rausgefunden.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast wrote:

> Habe jetzt ein wenig mit dem Syntax rumgespielt. Er ist einfach nur
> furchtbar :-)

Naja, sie ist unwahrscheinlich mächtig, aber das macht sie für einen
Anfänger nicht leicht zu benutzen.  Wenn du sie aber mal mit anderen
Compilern vergleichst, bei denen darfst du oftmals darauf hoffen, dass
der Compiler deine internen Variablen in der nächsten Version noch im
gleichen Register ablegen wird wie in der aktuellen, da sie keine
Möglichkeit haben, derartige Dinge in das inline asm statement hinein
zu propagieren.

GCC benutzt für inline asm letztlich die gleiche Semantik wie für
seine compiler-internen "insns", d. h. es werden die gleichen Wege für
die Register-Allokation benutzt usw.  Der Vorteil ist, dass damit dem
Implementierer der Systembibliothek ein mächtiges Werkzeug in die Hand
gegeben ist, seinen Nutzern für viele Details der Zielplattform
effektive Lösungen anbieten zu können.  Für einen Anfänger sind sie
eher nicht geeignet, und sie können/sollen auch keinesfalls explizite
Assemblerprogramme ablösen.

>         _asm_ __volatile__
>         (
>           "1:                           \n\t"
>           "2:                           \n\t"

Warum zwei Labels auf die gleiche Stelle?

>           " dec %[inner]                \n\t"
>           " jne 2b                      \n\t"
>               : [inner] "=r"(time)
>           " dec %[outer]                \n\t"

Das geht nicht.  Die Syntax ist:

[prepasm("string" : output operands : input operands [: clober 
list]);[/pre]

Du versuchst gerade, mehrere Strings mit meheren Listen von Operanden
zu mischen.

> Abgeleitet war die Loop aus einem Beispiel, wo ein "+r" verwendet
> wurde.  Es ist nirgendwo beschrieben, scheint aber zu funktionieren.

"r" ist das constraint für einen Registeroperanden, das "+" macht ihn
read/write.  Sollte beschrieben sein, müsste ich dir raussuchen.

Ich kenne mich mit MSP430 nicht aus, aber guck dir mal sowas an:
    void delay_ms(int time, int count)
    {
        __asm__ __volatile__
        (
          "1:                           \n\t"
          " dec %[inner]                \n\t"
          " jne 1b                      \n\t"
          " dec %[outer]                \n\t"
          " jne 1b                      \n\t"
        :
              : [inner] "r"(time), [outer] "r"(count)
        );
    }

Vermutlich musst du dir register auch noch vorbelegen.  Im Moment ist
es bissel Humbug, weil du die erste innere Schleife mit dem Wert von
"time" (aus den Funktionsparameters) zu zählen beginnst, die folgenden
dann aber bei 0.  Vielleicht wolltest du ja sowas?
    void delay_ms(int time, int count)
    {
        int i;
        __asm__ __volatile__
        (
          "1:                           \n\t"
          " mov %[inner], %[preload]    \n\t"
          "2:                           \n\t"
          " dec %[inner]                \n\t"
          " jne 2b                      \n\t"
          " dec %[outer]                \n\t"
          " jne 1b                      \n\t"
              : [inner] "=&r"(i)
              : [preload] "r"(time), [outer] "r"(count)
        );
    }

Ich hab's rudimentär auf einem AVR-GCC getestet, die Registerzuweisung
scheint mir erstmal OK zu sein.

Eine Alternative wäre es, für [inner] ein festes Register vorzusehen
und dies in der clobber list aufzuführen.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Jörg, damit habe ich es jetzt hinbekommen.

#define XTAL 4000000

#define CYCLES XTAL/1000

void delay_ms(unsigned int time)
{
  unsigned int count = CYCLES;
  asm volatile
  (
    "1: dec %[outer]         \n\t"
    "2: dec %[inner]         \n\t"
    " jne 2b                 \n\t"
    " jne 1b                 \n\t"
        : : [inner] "r"(count), [outer] "r"(time)
  );
}

erzeugt mir
mov r15, r14
mov #4000, r15
dec r14
dec r15
jnz $-2
jnz $-6
ret     
  

Wobei in r15 time steht. Optimiert werden könnte es, wenn die übergebene 
Variable time nicht nach r15 sondern r14 geschrieben wird. Dann fällt 
natürlich die erste Zeile weg.
Anfangs wurde immer ein clr r15 eingeschoben, nicht gerade hilfreich in 
diesem Fall.

Was aus der Doku schwer raus kam:
Der erste Doppelpunkt beschreibt den Output, der zweite den Input, der 
dritte die clopper-Liste. Outputs habe ich ja keine. Schreibe ich die 
Doppelpunkte untereinander, wird ein Syntax Error ausgegeben.
In der Doku (ich habe mich an die des avr gelehnt), steht nur "r", "=r" 
und "=&r" drin. Es wäre wirklich hilfreich zu erfahren, wo genau das 
steht.

Mit einer guten Anleitung müssen die Jungs echt noch üben :-)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast wrote:

> Was aus der Doku schwer raus kam: Der erste Doppelpunkt beschreibt
> den Output, der zweite den Input, der dritte die clopper-Liste.

"clobber".

info gcc -> C Extensions -> Extended Asm

`` Each operand is described by an operand-constraint string followed
by the C expression in parentheses.  A colon separates the assembler
template from the first output operand and another separates the last
output operand from the first input, if any.''

(OK, die clobbers sind dort nicht beschrieben.)

> Outputs habe ich ja keine. Schreibe ich die Doppelpunkte
> untereinander, wird ein Syntax Error ausgegeben.

Dann hast du noch was anderes vermurkst, das geht auf jeden Fall.  Das
oben zitierte Beispiel war bei mir ja durch den Compiler gegangen (nur
assemblieren konnte ich es nicht mangels MSP430-Tools).

> In der Doku (ich habe mich an die des avr gelehnt), steht nur "r",
> "=r" und "=&r" drin. Es wäre wirklich hilfreich zu erfahren, wo
> genau das steht.

info gcc -> C Extensions -> Constraints -> Modifiers

```+' Means that this operand is both read and written by the
     instruction.''

> Mit einer guten Anleitung müssen die Jungs echt noch üben :-)

Nein, ich würde stattdessen von der Bibliothek erwarten, dass sie dir
eine entsprechende delay-Funktion zur Verfügung stellt.  Die
Entwickler der Bibliothek sollten wissen, wie man mit dem
inline-Assembler umgeht, du als Endnutzer musst das nicht unbedingt.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Nein, ich würde stattdessen von der Bibliothek erwarten, dass sie dir
> eine entsprechende delay-Funktion zur Verfügung stellt.

Codevision macht das für den AVR. Die haben es tatsächlich geschafft, 
relevante Funktionen wie getchar, putchar oder delay in Assembler zu 
definieren. Vielleicht bastle ich mir da selber etwas zusammen.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die avr-libc macht das auch für den AVR, aber hier ging's ja um den
MSP430.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.