// imports.c -- Unterstützung für zweigeteilte Programme, RAM-Hälfte // Wenn eine Hälfte des Programms im Flash steht und eine Hälfte im RAM, // brauchen die Cortex-M ein Trampolin ("veneer"), wenn das Programm // im RAM Funktionen im Flash aufrufen will (danke, ARM!). Das kostet // pro Funktion 16 Byte (beim M0; beim M4 immer noch 8 Byte). Und, das // RAM-Programm muss neu gelinkt werden, wenn sich das Flash-Programm // ändert. Natürlich könnte man genauso aus dem Flash Funktionen im // RAM aufrufen, nur dann müsste man ständig neu flashen. // // Hier ist ein Verbesserungsvorschlag. // Die Funktionsadressen stehen in einer Tabelle im Flash. Hier Im RAM // steht nur die Adresse der Tabelle (exports:), im jedem Trampolin // steht der passende Index dazu. Die Tabelle hat im Flash eine eigene // section in der Nähe der vectortable. Es gibt also keinen Grund, // warum sich die jemals wieder verschieben sollte ;) // // Die Funktionsadresse kann so nicht als literal geladen werden, das // kostet auch wieder 2 Befehle mehr, aber in der Summe weniger Bytes: // 6 Byte pro Funktion + 14 bis 16 gemeinsam + 4/Funktion im Flash. // Selbst mit den 4 im Flash, lohnt das schon ab 2 Funktionen. // // Beide Programmteile sind völlig normal und brauchen nur einen Trick, // und den nur, wenn man die Tabell ohne asm erzeugen will. Eigentlich // müsste das eine union aus diversen Funktionstypen sein, aber am Ende // sind es doch nur 32 Bits mit "extern uint32_t" als Kompromiss. Die // festgelegte section funktioniert genau wie die vectortable und für // CRC über den Programmcode und Schreibschutz per MPU gibt es auch // nichts neues. #include "import-export.h" void __attribute__ ((aligned (4))) imports (void) { __asm__ ( "__assert_func: push {r0, r1}\n movs r0, #4 * ASSERT_FUNC \n b switch\n .global __assert_func\n" "clock_setup: push {r0, r1}\n movs r0, #4 * CLOCK_SETUP \n b switch\n .global clock_setup \n" "getchar: push {r0, r1}\n movs r0, #4 * GETCHAR \n b switch\n .global getchar \n" "printf: push {r0, r1}\n movs r0, #4 * PRINTF \n b switch\n .global printf \n" "putchar: push {r0, r1}\n movs r0, #4 * PUTCHAR \n b switch\n .global putchar \n" "puts: push {r0, r1}\n movs r0, #4 * PUTS \n b switch\n .global puts \n" "uart_init: push {r0, r1}\n movs r0, #4 * UART_INIT \n b switch\n .global uart_init \n" "\n" "switch: ldr r1, tab \n" " ldr r0, [r1, r0] \n" " mov ip, r0 \n" " pop {r0, r1} \n" " bx ip \n" "\n" "tab: .word 0x20000080\n" ); return; }