Preface: although this question is about bootloaders, I believe it also applies to anyone trying to implement function tables in C for devices with >64K.
I am working on separating my bootloader into two parts. One is fixed and the other is updateable. Because functions can move around in the updateable portion, I have implemented a FSM in the fixed portion which uses a function table in the updateable portion. Here is the function table definition in C:
typedef uint8_t (*fn_ptr_t)(void); #define JUMPTABLE_SECTION __attribute__ ((section (".jumptable"))) #define NUMBER_OF_STATES 3 const fn_ptr_t FunctionTable[NUMBER_OF_STATES] JUMPTABLE_SECTION = { Start, Update, Exit };
and here is the FSM in main:
register uint8_t state asm("r4"); int main(void) { state = 0; do { #if defined(RAMPZ) ((fn_ptr_t)pgm_read_word_far(0x10000 + (uint16_t)&FunctionTable[state]))(); #else ((fn_ptr_t)pgm_read_word_near(&FunctionTable[state]))(); #endif state++; } while (state != NUMBER_OF_STATES); while (TRUE); }
I have been able to just squeeze the fixed portion (including flash writing) in 256 bytes (a mega128 page). Part of the trick here was to use the version of GCC that generates the smallest code (3.4.5). However the generated code for deferencing the far pointer and calling the function is larger than I would have wanted (18 words in the icall).
The bootloader with updating feature all works correctly. However I wondering if there is a way to do what I want in C that uses less code? I think a table (function, jump or otherwise) is needed. I have seen assembler RJMP tables but I don't know how in C to make a generic function call which in turn then jumps to the word in the RJMP table.