Alternative zu Assembler

OP (Firma: Torrox.de) #5989003
Lesenswert?

Hallo,
ich schreibe gerade für meine BLE Debug Probe einige Flash Routinen für 
verschiedene Microcontroller.

Diese Routinen werden ins RAM des Targets geladen und dort ausgeführt, 
um das flash der Controller zu beschreiben. Ausgeführt werden diese 
Routinen, in dem die Parameter direkt in Register geladen werden, der PC 
auf den Start der Routine gesetzt wird und die CPU nach einen Halt 
wieder los gelassen wird. Am Ende der rennt die Routine auf einen 
Break-Point und der Debugger wartet auf das Erreichen des Breakpoints. 
Dann kann sich der Debugger das Ergebnis der  Routine in einem Register 
abholen (so grob skizziert).

Im Moment geht es ausschließlich um ARM Assembler (Thumb). Einige Flash 
Controller sind allerdings komplex genug, damit es recht schnell 
unübersichtlich wird, diese Routinen von Hand in Assembler zu schreiben.

Welche Alternativen hätte ich? (Einen Stack könnte ich wohl in der Regel 
aufsetzen). Verwendete Toolchain ist arm-none-eabi-gcc.

schöne Grüße,

Torsten
OP (Firma: Torrox.de) #5989016
Lesenswert?

Dr. Sommer schrieb:
> Seltsame Frage...
>
> Torsten R. schrieb:
>> Verwendete Toolchain ist arm-none-eabi-gcc.
>
> Das unterstützt C, C++ und Assembler. Die sollten alle drei gehen. Wo
> ist das Problem?

Ich kann in C, C++ keinen ausführbaren Code deklarieren, der ausserhalb 
einer Funktion steht:
1
start:
2
    MOV R7, #result_ok
3
    LDR R3, nvmc_ready                  /* R3 == NVMC_READY                         */
4
    LDR R4, nvmc_config                 /* R4 == NVMC_CONFIG                        */
5

6
    MOV R5, #NVMC_CONFIG_WEN_Wen
7
    STR R5, [ R4 ]                      /* NVMC_CONFIG = NVMC_CONFIG_WEN_Wen        */
8
...
9
    BKPT

Aufgerufen wird so eine "Routine", in dem ich die CPU des Controllers 
anhalte, die Routine ins RAM lade. Den PC auf den Anfang der Routine 
setze, die Register mit Parametern fülle und die CPU dann wieder weiter 
laufen lasse.

Am Ende der Routine ist dann ein SW-Breakpoint, auf den wartet der 
Debugger.

Ich könnte natürlich von dieser ASM-Routine aus, eine C Funktion 
aufrufen. Ich frage mich, ob es aber ggf. einfacher geht, ohne direkt 
Assembler schreiben zu müssen.
OP (Firma: Torrox.de) #5989038
Lesenswert?

Ich habe gerade mal in die Source von der Blackmagic Probe geguckt. Die 
verwenden C Funktionen, der mit `__attribute__((naked))` anotiert ist:
1
void __attribute__((naked))
2
efm32_flash_write_stub(uint32_t *dest, uint32_t *src, uint32_t size, uint32_t msc)
3
{
4
  ...
5
}

Die Dokumentation vom GCC sagt dazu aber:
1
naked
2
This attribute allows the compiler to construct the requisite function declaration, while allowing the body of the function to be assembly code. The specified function will not have prologue/epilogue sequences generated by the compiler. Only basic asm statements can safely be included in naked functions (see Basic Asm). While using extended asm or a mixture of basic asm and C code may appear to work, they cannot be depended upon to work reliably and are not supported.
#5989051
Lesenswert?

Dann mach halt normale C-Funktionen, auf die paar Byte wirds ja wohl 
nicht ankommen. Initialisier den Stackpointer, ruf die Funktion auf und 
wenn sie zurückkommt lass es in den Breakpoint laufen. Dann hast Du ne 
kleine Hand voll Assembler der immer gleich ist und eine bliebig 
komplexe stinknormale C-Funktion.
OP (Firma: Torrox.de) #5989052
Lesenswert?

Vincent H. schrieb:
> Das Problem ist dass es keinerlei Garantie gibt dass Code innerhalb
> einer Funktion nicht munter am Stack herumspielt. Das Attribut entfernt
> lediglich Stackpointer Manipulation am Anfang und Ende einer Funktion,
> nicht aber dazwischen.

Genau, und ich würde den Compiler gerne dazu bringen, z.B. eine 
Fehlermeldung auszugeben, wenn er doch einen Stackframe braucht (z.B. 
weil die Register nicht ausreichen).
#5997614
Lesenswert?

Torsten R. schrieb:
> Vincent H. schrieb:
>> Das Problem ist dass es keinerlei Garantie gibt dass Code innerhalb
>> einer Funktion nicht munter am Stack herumspielt. Das Attribut entfernt
>> lediglich Stackpointer Manipulation am Anfang und Ende einer Funktion,
>> nicht aber dazwischen.
>
> Genau, und ich würde den Compiler gerne dazu bringen, z.B. eine
> Fehlermeldung auszugeben, wenn er doch einen Stackframe braucht (z.B.
> weil die Register nicht ausreichen).

Beim GCC kann man sich mit -fstack-usage den Stackbedarf der einzelnen 
Funktionen ausgeben lassen. Das landet dann in einer .su-Datei die du 
mit einem Python-Script o.Ä., aufgerufen durch dein Build-System 
auswerten könntest.

Eine direkte Warnung kannst du ausgeben, wenn du die Compileroption 
-Wstack-usage=byte-size nutzt, wobei byte-size in deinem Fall dann 
logischerweise 0 sein müsste.
#6009700
Lesenswert?

da gibt es ja noch das Schlüsselwort Register wo man den Compiler fast 
soweit kriegt daß er Code absetzt wie man ihn auch selbst geschrieben 
hätte. Nur für einen Schleifenaufbau mit Rotieren durchs Carry bit habe 
ich noch nichts gefunden. Aber man muß halt immer höllisch aufpassen daß 
gcc keinen Blödsinn macht. Ist halt wie beim Autorouter in der 
Hardware...
Gast #6009716
Lesenswert?

Oliver S. schrieb:
> J. V. schrieb:
>> da gibt es ja noch das Schlüsselwort Register
>
> welches seit einem gefühlten Jahrhundert ganz offiziell von jedem
> Compiler ignoriert wird.

Oder besser nach eigenem Gutduenken optimiert...
Deshalb sagte ich dem gcc sowas:
1
register int foo asm ("r12");

> Oliver

leo

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren