Aus irgendeinem Grund möchte ich ein bisschen Assembly mit C ++ (nicht C) mischen.
Damit der Code mit der Standard-Arduino-IDE kompiliert werden kann, möchte ich keine direkte Assembly-Quelle verwenden.
Ich möchte auch keine Wrapper-C-Datei verwenden.
Mein Problem ist wie folgt:
Ich habe eine Klasse mit einer einzelnen Instanz (die eine Art Treiber implementiert), die folgendermaßen aussieht:
class cDriver {
public:
char ISR_param;
// ...
};
cDriver Driver;
Wenn ich ISR_param
innerhalb eines ISR auf diese einzelne Instanz zugreifen möchte , kann ich Folgendes tun:
ISR (TIMER2_COMPA_Vect) {
do_something_with (Driver.ISR_param);
}
Dies funktioniert wie ein Zauber: Die Adresse Driver.ISR_param
beign eine Konstante, der Compiler generiert einfach eine lds r24, &Driver.ISR_param
Anweisung, um das richtige Byte als Parameter für zu laden do_something_with
.
Wenn ich jetzt versuche, denselben Mechanismus mit dem Inline-Assembler zu replizieren, werden die Dinge viel komplizierter.
Die Adresse von Driver.ISR_param
ist dem C ++ - Compiler nur als entstelltes Label bekannt, und ich kann keine Möglichkeit finden, sie an den Inline-Assembler zu übergeben, um das Äquivalent zu generieren lds r24, <&Driver.ISR_param>
.
versuchen, die Variable erneut zu bestimmen
Das Umbenennen von Variablen für Assembly wie folgt:
char global_var asm("my_var");
und ein Versuch, es so zu benutzen:
asm ("lds r24, my_var\n");
wird kompiliert, erzeugt aber einen Linkerfehler ( my_var
ist undefiniert).
In der Objektsymboltabelle ist die einzige Bezeichnung für global_var
einen C ++ - ähnlichen verstümmelten Namen.
So sehr ich mich auch um diesen Umbenennungstrick bemühte, ich konnte den Compiler nicht dazu bringen, ein my_var
Label zu generieren .
versuchen, asm-Einschränkungen zu verwenden
Eine Einschränkung wie
asm (lds r24, %0\n" : : "I"(&global_var));
wird einfach nicht kompiliert. Ich habe die möglichen Parametertypen durchsucht und konnte keinen Weg finden, den Assembler über diese blutige Adresse zu informieren.
eine schrecklich umständliche Problemumgehung
Die einzige Möglichkeit, den Compiler dazu zu bringen, diese gefürchtete lds r24,...
Anweisung zu generieren , besteht darin, einen tatsächlichen Funktionsaufruf auszuführen.
Sie können also Folgendes tun:
__attribute__((always_inline)) give_me_my_friggin_variable(char data)
{
asm volatile ("cmp %0,%0\n"::"r"(data));
}
ISR (TIMER2_COMPA_Vect, ISR_NAKED) {
<some prologue to save SREG and all needed registers>
//...
give_me_my_friggin_variable(Driver.ISR_param);
// continue assembly code with r24 properly initialized
}
Das wird erzeugen:
lds r24, <the proper address> // added by the compiler...
cmp r24,r24 // ...because of the register constraint here
Nun, diese Art von Arbeiten, aber auf Kosten einer völlig nutzlosen Anweisung.
meine frage ist also ...
Gibt es eine einfachere Möglichkeit, den Assembler über Adressen von statischen C ++ - Variablen zu informieren?
quelle
"i"
Einschränkung fehlt tatsächlich im Inline Assembler-Kochbuch von avr-libc . Ich habe einen Link zur gcc-Dokumentation hinzugefügt, in der er aufgeführt ist.