This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Problems using Functon Pointers in Banked Application

I am having a problem with function pointers used in a banked C51 application. They work under some cases and not in others. Let me try to carefully describe the exact details of the problem.

I am using the C51 Version 7 compiler and the corresponding BL51 to build a bank switched application on a Cygnal C8051F126 processor. This device has 128K bytes of FLASH arranged in four 32K banks. Bank 0 and the common bank are the same. I am using function pointers to dispatch keyboard functions through a generic handler that has a function pointer per functional key. The main executive loop code and the routine which does the function dispatching are contained in the commom bank. The code that the function dispatcher is branching to is a whole collection of subroutines in Bank 2 that correspond to the various keystroke actions in all the system menus.

The function pointers, which happen to be declared in XDATA memory space, are allocated in the main executive module. For the initial menu the main code in the common area sets the function pointer (lets use my ENTER key for an example) for the "EnterPtr" to "HomeScreen" which is in Bank 2 code as I described before. When the main executive module (from the common bank) dispatches the first ENTER key from the user it branches through the pointer with a call that looks like:

(*EnterPtr)();

... to the HomeScreen() code. I have traced all through this with the Cygnal IDE debugger and see it work nicely. It goes all through the interbank branch table code in the common bank and executes the target routine properly and returns directly back to the original keypad dispatcher routine in the main executive.

A part of the code that the HomeScreen() routine executes is a setup a new value for the "EnterPtr" because the ENTER key will have a new function in this menu. So the EnterPtr is set to "ChannelScreen". It so happens that the ChannelScreen() subroutine is also in the same Bank 2 module along with the HomeScreen() routine.

When the next ENTER key arrives at the main module keyboard dispatcher that is executing in the common bank it once again dispatches through the (*EnterPtr)(); call code. This time when I trace the code with the Cygnal debugger the branching code however does not go through the interbank branck table. Instead it goes directly to the ChannelScreen() functon address, but the bank does not get changed and as such the program crashes because it trys to execute code that is sitting in Bank 1 at the same offset address as the ChannelScreen() subroutine.

Now, it does seem to be that the BL51 linker thought that the setting of the EnterPtr value to ChannelScreen from Bank 2 code thinks that this is a call to the same bank and therefore it elected to set the call as a direct "within bank call" without branching through the interbank branch table. Under most cases this is reasonable for normal direct calls. However the BL51 linker did not realize that the EnterPtr call would be dispatched elsewhere after the bank has been changed to something else.

So what I need help with is how to get this to work properly. In particular I need to know how to get it so that BL51 will always program the branches through the function pointers such as the "EnterPtr" so that they will always use the interbank branch table.

Note this is a part of a very large project that has been ported from an old IAR implementation from about 5->7 years ago to the Cygnal platform using the Keil tools. I would like to find a soultion that will work properly with the function pointers since there are many many of them set all over the place. It is just not attractive to try to re-code the structure of all this existing code to not use the function pointers.

Thanks,
Michael Karas

Parents
  • Joh:
    I had read your referenced article two times. At first take it does not seem to directly apply to my situation if you read my post carefully. Indeed in my case the interbank call table does have entries for the functions that are being transferred. In fact I described how in one case the function pointer worked correctly from one bank to the other. However the problem arises when the function pointer is set to a value in one function in the same bank as the target pointer value...but the invokation of that pointer value is not used until later off in another bank. In this case the linker tried to fake me out and use the more efficient direct "in same bank" call as opposed to going through the function pointers.

    I can possibly try to see if the problem can be fixed with an OVERLAY statement fed to the linker. However if this does work for one case it will be a disappointing type of fix. There are a total of 12 of these types of function pointers in the code base that I am working with and they are set to values in as many as 45 or 50 functions. The size of the list of OVERLAY commands to fix this is unbelievable......and would be next to a nightmare to maintain. Surely there must be come technique or method to change the source code to trick the linker to always make the function pointers work properly. I just cannot think of how to do it. Such a solution would need to also be a thing that still permits the code the still use function pointers because the code changes needed to find a different architecture just dont fit my project schedule. (Note this project is one of porting a massive sized set of code over to Keil supported compile environment on a new Cygnal processor platform. I did not originate the design of all this code!!). I just need to try to get it working properly with bank switching.

    Michael Karas

Reply
  • Joh:
    I had read your referenced article two times. At first take it does not seem to directly apply to my situation if you read my post carefully. Indeed in my case the interbank call table does have entries for the functions that are being transferred. In fact I described how in one case the function pointer worked correctly from one bank to the other. However the problem arises when the function pointer is set to a value in one function in the same bank as the target pointer value...but the invokation of that pointer value is not used until later off in another bank. In this case the linker tried to fake me out and use the more efficient direct "in same bank" call as opposed to going through the function pointers.

    I can possibly try to see if the problem can be fixed with an OVERLAY statement fed to the linker. However if this does work for one case it will be a disappointing type of fix. There are a total of 12 of these types of function pointers in the code base that I am working with and they are set to values in as many as 45 or 50 functions. The size of the list of OVERLAY commands to fix this is unbelievable......and would be next to a nightmare to maintain. Surely there must be come technique or method to change the source code to trick the linker to always make the function pointers work properly. I just cannot think of how to do it. Such a solution would need to also be a thing that still permits the code the still use function pointers because the code changes needed to find a different architecture just dont fit my project schedule. (Note this project is one of porting a massive sized set of code over to Keil supported compile environment on a new Cygnal processor platform. I did not originate the design of all this code!!). I just need to try to get it working properly with bank switching.

    Michael Karas

Children
  • I can confirm that the OVERLAY directive will fix this problems. Even when the input list might be very long, this will not cause problems for you.

    We agree that the OVERLAY directive is not an optimal solution, but we do not have a better yet. If you have something in mind, send you suggestion to: support.intl@keil.com.