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
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?
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
MOVR7,#result_ok
3
LDRR3,nvmc_ready/* R3 == NVMC_READY */
4
LDRR4,nvmc_config/* R4 == NVMC_CONFIG */
5
6
MOVR5,#NVMC_CONFIG_WEN_Wen
7
STRR5,[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.
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.
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.
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).
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.
>Welche Alternativen hätte ich? (Einen Stack könnte ich wohl in der Regel>aufsetzen). Verwendete Toolchain ist arm-none-eabi-gcc.
Nimm C, das ist nichts anderes als ein Makro-Assembler!
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...
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.
Oliver
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:
Die gesamten Mikrokontroller sind von GCC Code besetzt. Die gesamten?
Nein, ein von unbeugsamen Programmieren erstellter Compiler macht das
anders (cosmic)