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 }
Jon, Your program doesn't follow the guidelines laid out in the application note. So, you must use the overlay directive. If you follow the application note's directions, you can create programs using tables of function pointers without the need for the overlay directive. I just assumed that you read the application note, created a program that didn't follow those directions, and then needed help with the overlay directive. Jon
Jon, I would like to use this table of function pointers technique, to eliminate the OVERLAY directive. I have read the app note. I just do not see how I can use it. I have the typical requirement of assigning the fn pointer in one routine and calling the fn pointer in another routine. Can my simple example be restructured to follow the app note?
I have the typical requirement of assigning the fn pointer in one routine and calling the fn pointer in another routine. Can my simple example be restructured to follow the app note? If that's the case, then no. If you can make the assignment inside the function that actually calls thru the function pointers, then yes. However, that doesn't appear to be the case. The call tree is built using the associations that your program physically has. If you have a function that accesses a table of function pointers, then a reference is made (because that function references the table). And, the linker, in the call tree, indicates that the function that accessed the table calls that code segment which in turn calls the functions in the table. You can disable this assumption using the SPEEDOVL linker directive. But, that doesn't automatically add the functions into the call tree for you. If you call the function thru a different pointer (like you example does), the linker cannot be expected to create the call tree. Since the value of the variable may be anything, the linker can't guess what function(s) it may be used to call. Therefore, you must add the reference to the call tree manually. The application note makes the following points: If you... 1. Create a table of function pointers, and 2. Store the table in CODE space (so the pointers cannot be changed), and 3. Access this table in the function where you actually call the functions whose addresses are in the table, then... The linker creates a call tree that requires no changes (using OVERLAY). The application note was intended to show all sides of the overlay issue as well as a trick that I use to avout using the overlay directive for large tables of function pointers. Jon
Here is another approach that would work well for me. Just optimize ( *constFnTbl[i] )(<parms>);
// //c code // typedef char (code* PFN)(char); code fnTbl[] = { fn1, fn2, fn3 }; void main( void ) { volatile char i; volatile char x = ( *fnTbl[i] )( 2 ); } // // I would like // main: mov r7,#2 mov a,i mov dptr,#jmpTbl call evalfn mov x,r7 ret jmpTbl: ajmp fn1 ajmp fn2 ajmp fn3 evalfn: lsl a jmp @+dptr // // Current code // 0000 AF00 R MOV R7,i 0002 EF MOV A,R7 0003 25E0 ADD A,ACC 0005 2400 R ADD A,#LOW fnTbl 0007 F582 MOV DPL,A 0009 E4 CLR A 000A 3400 R ADDC A,#HIGH fnTbl 000C F583 MOV DPH,A 000E E4 CLR A 000F 93 MOVC A,@A+DPTR 0010 FE MOV R6,A 0011 7401 MOV A,#01H 0013 93 MOVC A,@A+DPTR 0014 F582 MOV DPL,A 0016 8E83 MOV DPH,R6 0018 7F02 MOV R7,#02H 001A 120000 R LCALL ?C0005 001D 8002 SJMP ?C0006 001F ?C0005: 001F E4 CLR A 0020 73 JMP @A+DPTR 0021 ?C0006: 0021 8F00 R MOV x,R7 ;0023 22 RET ; FUNCTION main (END)