Just as the compiler has added custom support for bits, it should also add custom support for function pointers. Here is one idea:
//Saves on storage (1 byte) //Is faster (fixed jump table) //No need to add/remove references in the linker void fn1( void ){}; void fn2( void ){}; void fn3( void ){}; void fn4( void ){}; enumfn MyFnType { fn1, fn2, fn3 }; //must have same signatures MyFnType myFnVar; void FnA(void) { myFnVar = fn1; // do not add fn1 to FnA's call tree myFnVar = fn4; // compiler error } void FnB(void) { (myFnVar)(); // do add fn1,fn2,fn3 to FnB's call tree }
You can accomplish the same thing with the tools now. Refer to the "TABLES OF FUNCTION POINTERS" section in the following application note: http://www.keil.com/appnotes/docs/apnt_129.asp Jon
Even though I am into "Tree preservation", not having to use the error prone OVERLAY directive sounds great. Can you help me? My simple example fails. I must be missing something.
void fn1(void){ } void fn2(void){ } void fn3(void){ } code void (code *fp_tab [])(void) = { fn1, fn2, fn3 }; void ( code* fp)(void); void fn( void ) { fp = fp_tab[0]; } void main(void) { fn(); (*fp)(); } ?C_C51STARTUP +--> ?PR?MAIN?STATETEST ?PR?MAIN?STATETEST +--> ?PR?FN?STATETEST ?? where is ?CO?STATETEST ?PR?FN?STATETEST +--> ?CO?STATETEST ?? ?CO?STATETEST should not be here ?CO?STATETEST +--> ?PR?FN1?STATETEST +--> ?PR?FN2?STATETEST +--> ?PR?FN3?STATETEST
; FUNCTION fn (BEGIN) ; SOURCE LINE # 12 ; SOURCE LINE # 13 ; SOURCE LINE # 14 0000 900000 R MOV DPTR,#fp_tab 0003 E4 CLR A 0004 93 MOVC A,@A+DPTR 0005 FE MOV R6,A 0006 7401 MOV A,#01H 0008 93 MOVC A,@A+DPTR 0009 8E00 R MOV fp,R6 000B F500 R MOV fp+01H,A ; SOURCE LINE # 15 000D 22 RET ; FUNCTION fn (END)
Since only constants are involved, the compiler should be able to optimize the "fp = fp_tab[0];" to a simple move. Instead you get... The 8051 only provides one instruction for reading code memory: MOV A, @A+DPTR. The code generated by the compiler looks pretty optimal to me. Can you suggest a better solution? Jon
Even though I am into "Tree preservation", not having to use the error prone OVERLAY directive sounds great. Can you help me? My simple example fails. I must be missing something. 1. Your program stores function pointers in the fp_tab which is stored in the code segment. The name of this segment is ?CO?STATETEST. It is important to note that these are the ONLY CODE variables in this module. If there are other CODE variables in this module the following method may not work. 2. Since your program references fp_tab in the fn function, the linker thinks that fn must call one of the functions in fp_tab and so creates an entry in the call tree. However, fn only reads the function address. 3. Main actually calls a function stored in fn_tab. However, since there is nothing in the main function that references fn_tab, the linker creates no entries in the call tree. 4. To fix this, you must remove the reference from the fn function to fn_tab (which is the ?CO?STATETEST segment) and you must add a reference from the main function to fn_tab. The following overlay commands will do the trick.
overlay (FN ~ ?CO?STATETEST, MAIN ! ?CO?STATETEST)
SEGMENT DATA_GROUP +--> CALLED SEGMENT START LENGTH ---------------------------------------------- ?C_C51STARTUP ----- ----- +--> ?PR?MAIN?STATETEST ?PR?MAIN?STATETEST ----- ----- +--> ?PR?FN?STATETEST +--> ?CO?STATETEST ?CO?STATETEST ----- ----- +--> ?PR?FN1?STATETEST +--> ?PR?FN2?STATETEST +--> ?PR?FN3?STATETEST ?PR?FN1?STATETEST 0008H 0008H ?PR?FN2?STATETEST 0008H 0010H ?PR?FN3?STATETEST 0008H 0004H
How about mov fp,#high(fn1) mov fp+1,#low(fn1)
View all questions in Keil forum