www.mikrocontroller.net

Forum: GCC Übersetzen GCC in Assambler


Important announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Maria K. (maria_k)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hi,

ich wäre sehr dankbar, wenn mir jemand sagen könnte, wie der 
Assambler-Code hinter folgendem Makro aussieht, bzw. wie der gcc dieses 
Makro interpretieren würde:
#define mfmsr()         ({  unsigned int _rval;         \
                            __asm__ __volatile__ (      \
                                "mfs\t%0,rmsr\n" : "=d"(_rval) \
                            );                          \
                            _rval;                      \
                        })

Das Makro stammt aus einem Header für Xlinx Microblaze. Da ich mit 
dieser Syntax wirklich nicht viel anfangen kann, würde mir eine 
detailierte Erklärung wirklich weiterhelfen.
(Was bedeuten in diesem Kontext
 __volatile__ 
,
 \t%0 
,
\n" : "=d"(_rval) 
)

Schon mal Danke im voraus. Gruß Maria

Autor: Yalu X. (yalu) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
#define mfmsr() 
 -> Definiert das Makro mfmsr (move from machine status register)
unsigned int _rval;
 -> Definition einer temporären Variable
__asm__
 -> Jetzt kommt Inlineassemblercode.
__volatile__
 -> Der Compiler darf den nachfolgenden Assemblercodeabschnitt nicht
    wegoptimieren oder ihn aus einer Schleife vor die Schleife
    verschieben.
"mfs\t%0,rmsr\n" : "=d"(_rval) \
 -> Beschreibung des zu generierenden Assemblercodes
   mfs\t%0,rmsr\n
    -> Pattern für Assemblerbefehl. Für %0 wird etwas eingesetzt, was
       nach dem Doppelpunkt genauer spezifiziert wird.
      mfs
       -> move from special purpose register
      rmsr
       -> register "machine status register"
   "=d"(_rval)
    -> Spezifikation dafür, was für %0 eingesetzt werden soll
      =
       -> Gibt an, dass %0 ein Output ist.
      d
       -> Gibt an, dass %0 ein General-Register sein soll. Der Compiler
          wird also für %0 eines der Register r0—r31 einsetzen.
      (_rval)
       -> In dieser C-Variable soll der Inhalt von %0 am Schluss landen.
          Ist _rval eine Registervariable, wird der Compiler dieses
          Register für %0 einsetzen, so dass der msr-Befehl den Status
          direkt in _rval schreiben kann. Liegt _rval im RAM, wird
          der Compiler einen zusätzlichen Assemblerbefehl generieren,
          der den Inhalt des ausgewählten Registers (r0—r31) an die
          entsprechende RAM-Adresse kopiert.
_rval;
 -> Rückgabewert des vom Makro erzeugten C-Blocks.

Alles zusammengenommen macht das Makro also den Inhalt des Machine-
Statusregisters für das C-Programm verfügbar. Die Anweisung
  status = mfmsr();

schreibt den Inhalt des Statusregisters in die Variable status.

Noch viel mehr zu diesem Thema steht im GCC-Manual in diesen Kapiteln:

  http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
  http://gcc.gnu.org/onlinedocs/gcc/Constraints.html
  http://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html
  http://gcc.gnu.org/onlinedocs/gcc/Explicit-Reg-Vars.html

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Yalu X. schrieb:

>  __volatile__
>
>  -> Der Compiler darf den nachfolgenden Assemblercodeabschnitt nicht
>     [...] aus einer Schleife vor die Schleife verschieben.

Doch, darf er wohl.

Es darf nicht mit anderen volatile-Operationen vertauscht werden.

Mit "normalen" Operationen darf es vertauscht werden — sofern die 
Abhängigkeiten dies zulassen. Dies schliesst auch Speicherzugriffe ein 
sofern diese nicht volatile sind.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Johann L. schrieb:
>>  __volatile__
>>
>>  -> Der Compiler darf den nachfolgenden Assemblercodeabschnitt nicht
>>     [...] aus einer Schleife vor die Schleife verschieben.
>
> Doch, darf er wohl.

Sicher?

> Es darf nicht mit anderen volatile-Operationen vertauscht werden.
>
> Mit "normalen" Operationen darf es vertauscht werden — sofern die
> Abhängigkeiten dies zulassen.

Schon richtig, aber das von mir Geschriebene widerspricht dem ja auch
nicht. Ich war eigentlich der Auffassung, dass ein asm mit volatile, das
in einer sich 100mal drehenden Schleife steht, auch tatsächlich 100mal
ausgeführt wird. Ohne volatile kann der Compiler das asm vor die
Schleife stellen, wenn der Input nicht von Berechnungen in der Schleife
abhängt.

Liege ich da falsch?

Zumindest in diesem Beispiel verhält sich der Compiler genau nach meinen
Vorstellungen:
uint8_t x;

void test_volatile(void) {
  uint8_t i;

  for(i=0; i<10; i++) {
    __asm__ __volatile__ ("ldi %0,1" : "=d" (x));
  }
}

Mit __volatile__:
test_volatile:
  ldi r24,lo8(10)
.L2:
  ldi r25,1  ; <-- in der Schleife
  sts x,r25
  subi r24,lo8(-(-1))
  brne .L2
  ret

Ohne __volatile__:
test_volatile:
  ldi r24,lo8(10)
  ldi r25,1 ; <-- vor der Schleife
.L2:
  sts x,r25
  subi r24,lo8(-(-1))
  brne .L2
  ret

Anmerkung: Das Beispiel ist für den AVR, da ich mich mit dem Microblaze
nicht auskenne. Das sollte aber in diesem Zusammenhang nichts ausmachen.

Autor: Maria (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Vielen Dank,

für die wirklich ausführlichen und vor allem hilfreichen 
Antworten/Links.


Gruß
Maria

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Yalu X. schrieb:
> Johann L. schrieb:
>>>  __volatile__
>>>
>>>  -> Der Compiler darf den nachfolgenden Assemblercodeabschnitt nicht
>>>     [...] aus einer Schleife vor die Schleife verschieben.
>>
>> Doch, darf er wohl.
>
> Sicher?

Ja :-)

>> Es darf nicht mit anderen volatile-Operationen vertauscht werden.
>>
>> Mit "normalen" Operationen darf es vertauscht werden — sofern die
>> Abhängigkeiten dies zulassen.
>
> Schon richtig, aber das von mir Geschriebene widerspricht dem ja auch
> nicht. Ich war eigentlich der Auffassung, dass ein asm mit volatile, das
> in einer sich 100mal drehenden Schleife steht, auch tatsächlich 100mal
> ausgeführt wird.

Ja, das stimmt. Die Seiteneffekte müssen natürlich die gleichen sein.

Hier ein etwas komplexeres Beispiel:
#include <stdint.h>

uint8_t x;
uint8_t y;

void test_volatile (void)
{
    uint8_t i;

    for (i=0; i < 10; i++)
    {
        y = i;
        __asm__ __volatile__ ("ldi %0,1" : "=d" (x));
    }
}
 
und übersetzt mit avr-gcc-4.7.1 -O3
 
test_volatile:
  ldi r24,1
  ldi r24,1
  ldi r24,1
  ldi r24,1
  ldi r24,1
  ldi r24,1
  ldi r24,1
  ldi r24,1
  ldi r24,1
  ldi r24,lo8(9)
  sts y,r24
  ldi r24,1
  sts x,r24
  ret

Was hier nicht geht, ist das Schreiben von y mit dem von x zu 
vertauschen. Allerdings nicht wegen dem volatile, sondern wegen den 
Aliasing-Rules.

Bestübde der Seiteneffekt des asm jedoch in Umkonfigurieren der 
Hardware, zB Setzen von Segmentregistern die die Speicherzugriffe 
beeinflussen, hätte man mit dem obigem Code ein Problem, denn x bzw y 
hängen nicht vom asm ab.

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




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 erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net