// 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, im jedem Trampolin steht der // passende Index dazu. Die Tabelle hat eine eigene section, im Flash // 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 Byte im Flash lohnt das schon ab 2 Funktionen. // // Beide Programmteile sind ziemlich normal und bis auf die vereinbarte // feste Adresse unabhängig. Die section $exports funktioniert wie die // vectortable und für CRC über den Programmcode und Schreibschutz per // MPU gibt es auch nichts neues. // // imports.c könnte eine reine Assembler-Quelle sein, aber dazu müsste // man ca. 25 kryptische Assembler-Direktiven verstehen. So macht der // GCC die Drecksarbeit. #define MAKE_IMPORT 1 #include "import-export.h" void __attribute__ ((naked, section ("$imports"), aligned (256))) imports (void) { IMPORT_EXPORT_VERSION (TIMESTAMP) GENERATE_CODE __asm__ ( "jump: ldr r1, [pc, #8]\n" " ldr r0, [r1, r0]\n" " mov ip, r0\n" " pop {r0, r1}\n" " bx ip\n" " nop\n" " .word flash_exports\n" "\n" ); IMPORT ( getchar ) IMPORT ( puts ) IMPORT ( crash ) IMPORT ( putchar ) IMPORT ( printf ) IMPORT ( clock_info ) IMPORT ( clock_setup ) IMPORT ( uart_init ) }