Hi Keil,
i'm currently working on project involving large memory model, reentrant function with auto-banking. i've met this unresolved bug involving keil stack frame causing my program flow generate an error.
the error generated when a callee function return to it's caller, instead of returning to it's caller address my program jump to current XBP value (lets say current XBP value at X:0xD00), then my program jump to that address (C:0xD00), that address already occupied by other piece of code, and execute that code causing my program running indeterminately. i've debugged the code and the returning address should be passed on to DPTR by ADDXBP function before calling SWITCH_BANK, the DPTR contain 0xD00 by the time SWITCH_BANK is called.
here's several questions regarding C51 that would help the debugging process: 1. i want to know where do keil save it's caller program counter for large reentrant model? my program might overwrite that area (in my case all function always set as reentrant). 2. what happened to stack frame when reentrant function called? program counter and local reentrant variable/argument is on different stack or same stack? stack frame structure if available would help a lot. 3. beside during function return when will XBP accessed? i believe my error caused by wrong access of XBP.
i use c51 compiler and lx51 linker, uVision3
Sincerely, Agus Purwanto
So what kept you from looking all this up in the documentation?
Who do you think you are addressing?
Thanks for the reply, no the documentation didn't said anything about stack frame structure or where did c51 put XBP pointer (though later i analyzed it from ADDXBP function and get it value from memory D:0x0D) and caller PC. im debugging from low level using memory viewer and third party emulator to access stack frame but didn't get the structure of stack frame.
large memory model, reentrant function with auto-banking. Isn't it time to switch to an ARM?
indeed, but my project will be used for mass product switching to ARM would increase production cost, of course for high end product i'm planning to use ARM
indeed, but my project will be used for mass product switching to ARM would increase production cost I actually doubt that, using banking means that you have external memory/ies and you, I'm confident, can find an ARM with the necessary memory for less than the combined cost
Just checked, you can get a STM32F071CBU7TR Cortex M0 with 128/16kb for $1.60, I doubt you can get a '51 and external memory for less
The low-end ARM chips have a very significant price overlap with 8051 chips. Especially when the 8051 solution requires extra external hardware.
Another aspect is the support/maintainance costs which are also a significant part of the full lifetime cost of a product. 32-bit integers, a generic stack, full support for reentrant code, function and data pointers, indexing etc while removing the need for banking can be quite significant advantages when talking about code complexity and sw maintainance costs.
The huge market share ARM chips are collecting isn't because they are expensive and only meaningful to select for high-end, or low-volume, products.
thanks so much for your advice, well my project involved about 10-15 cent C51 so it's about ten times cost, oh btw i've finally solve the problem (likely for now)
the problem arose when calling a reentrant function at the last operation on a function, keil likely to replace LCALL with LJMP for the last function
ex (perhaps reproduce the bug, haven't tested yet):
void caller() reentrant { char number; callee(); //by keil will be replaced with LJMP callee } void callee() reentrant { void * ptr; //any operations here return; }
solution :
void caller() reentrant { char dummy; //use dummy variable callee(); //it stays with LCALL callee dummy = 0; //dummy operation } void callee() reentrant { void * ptr; //any operations here return; }
perhaps replacing with LJMP causing unreleased variable in caller stack, supposed keil optimization for unreleased stack failed, it then producing my bug, still didn't confirmed it yet.
IF tail-end optimization was the reason for the bug (assuming that the compiler did know that both functions was reentrant) then it's time to contact Keil support.
well my project involved about 10-15 cent C51 nobody spoke of just the c51, it was about the C51 AND the external memory AND the latch AND .....
still haven't confirmed it yet, but so far by adding dummy operation at the end of function the code works great (at least the program didn't jump indeterminately)
ex (perhaps reproduce the bug, haven't tested yet): That example doesn't even compile as-is; and the reason it doesn't is very relevant to the issue at hand. The compiler would do tail recursion optimization that incorrectly only if you had failed to inform it the callee was reentrant, too. Proper function declarations are absolutely crucial when functions deviate from the configured default calling convention.
i've already aware of that, all functions already declared in header as reentrant, and even placed the callee on the same banking as the caller, but the problem still arise before i put that dummy operation at the end of caller function. should i made mess with my declaration then my solution shouldn't worked too.