This is only my second project with Keil, so I am not an expert, but I have Please read the manual'ed. :) The code I'm working on was released by the manufacturer of the system, which includes an embedded 8051. The original code worked, but was poorly written and lacked functionality. As I am making changes, I find that I hit CODE and DATA overflows. I can solve CODE overflows by moving code to other code banks and simplifying things. DATA overflows are a little more difficult.
The Memory Model is "Small: variables in DATA" and the Code Rom Size is "Large: 64K program". I'd prefer not to mess with these, as I have to give the code back working and reasonably like how I got it. The main source file (which is not overlayed) has a small allocation of RAM/dataspace, most of it being used by the ROM code that I can't modify. I've gotten rid of local variables and used XDATA wherever possible. Suddenly, after days of development (and probably 100 builds), I've overflowed DATA by 9 bytes somehow.
*** ERROR L107: ADDRESS SPACE OVERFLOW SPACE: DATA SEGMENT: _DATA_GROUP_ LENGTH: 0009H
My RAM map looks like:
* * * * * * * D A T A M E M O R Y * * * * * * * REG 0000H 0008H ABSOLUTE "REG BANK 0" DATA 0008H 0018H ABSOLUTE BIT 0020H.0 000FH.5 ABSOLUTE BIT 002FH.5 0000H.2 UNIT _BIT_GROUP_ 002FH.7 0000H.1 *** GAP *** DATA 0030H 0045H ABSOLUTE IDATA 0075H 0006H UNIT ?ID?RAMPROG 007BH 0001H *** GAP *** DATA 007CH 0002H ABSOLUTE DATA 007EH 0002H ABSOLUTE IDATA 0080H 0043H ABSOLUTE 00C3H 000DH *** GAP *** IDATA 00D0H 0030H ABSOLUTE
I'm assuming that the ABSOLUTE DATA allocations are for C function arguments and local variables -- except that I have now very little/few of either. In fact, the module's compiler output says:
MODULE INFORMATION: STATIC OVERLAYABLE CODE SIZE = 8573 ---- CONSTANT SIZE = 284 ---- XDATA SIZE = ---- 16 PDATA SIZE = ---- ---- DATA SIZE = ---- 10 IDATA SIZE = 6 ---- BIT SIZE = ---- 2 END OF MODULE INFORMATION.
which actually shows less DATA, IDATA and CONSTANTs used than when I first started. So I guess the question is:
1. If I've eliminated EVERY SINGLE local variable in the code, and 2. Reduced the C function parameters to just a small number, all BYTE data types.
what's left to do to eliminate the DATA overflow?
An update. I rolled back to a prior version and started slowly adding back code. I found that one small change (one line) caused the compiler to no longer be able to use registers to handle the function parameters, hence the need for 9 more bytes of RAM. Tricky, tricky :) I find myself changing a lot of code like
void SomeFunction(BYTE x, WORD y) { <do something with> x <do something with> y }
to
#define SomeFunction(x,y) {XBYTEx=x; XWORDy=y; someFunction();} void someFunction(void) { <do something with> XBYTEx <do something with> XWORDy }
where XBYTEx and XWORDy are defined in XDATA space.
This is probably old hat to the more experienced among you.
This line:
IDATA 0075H 0006H UNIT ?ID?RAMPROG
doesn't really make sense. You have IDATA below the 0x80 barrier, but unused space above the barrier:
00C3H 000DH *** GAP ***
It should be possible to move that block from 0x75 up to 0xc3, and thus ease the problem.
Actually, I think something must be wrong with how your program uses DATA space --- there really shouldn't be that much ABSOLUTE usage.
Thanks, H-B. The memory layout is just as I received it (and I haven't changed it), but I had EXACTLY the same question about IDATA, as I understood it is always in the region > 0x80. That may fix a few other things, too, perhaps.
One problem I have is that there is ROM code to which I don't have access that presumably chews up a lot of the DATA space.
Thanks again, J
The compiler analyzes the call tree of the program to determine when it can safely overlay memory used by two functions. If the functions can't be active at the same time (they're down different branches of the tree), then the compiler can reuse the data memory for the parameters, locals, and temps.
If you have functions that aren't called, those functions don't appear in the main call tree. They each act as the root of their own call tree (like an interrupt function or an RTOS task), and can't have their memory overlaid with any other function. Thus, unused functions can eat up a lot of memory.
See the REMOVEUNUSED linker directive. If possible, don't compile or link in the unused code at all.
Note that the memory model dictates where the parameters and locals live by default. If you switch the memory model to large, those will all move to XDATA. Best practice is generally considered to be to explicitly declare the memory space for every variable so that they are unaffected by changes in the memory model. You can also change the memory model function by function.
Thanks, Drew. I'll do that.
I'm still left with the mystery of those IDATA areas below 0x80. Where would I look for answers?
Regards, J
"The idata memory specifier refers to all 256 bytes of internal data memory"
See: http://www.keil.com/support/man/docs/c51/c51_le_intdatamem.htm
His mystery was not that IDATA can address the full 256 bytes, but why one IDATA block was placed before a DATA block, resulting in the DATA address space becoming full.
the linker allocates variables in blocks = segments.
Thus if you have a DATA segment that is larger than the available DATA space, the linker inserts IDATA there.
The trick is to spread the data variables into several modules when you are squeezed.
here is one case of mine where the linker used space below 0x80 (bdata to 0x20) for IDATA I used assembler to avoic the compiler assigning an identical segment name (maybe you can do it in C, I did not investigate)
;;//////////////////////////////////////////////////////////////////// ;; ;; FILE: SXZDATA.A51 ;; ;; Copyright TwinVision N.A., 2007 ;; ;; Overcome the Keil inability to save DATA parts in gropus lexx than "hole" $NOMOD51 PUBLIC GCDXdestListBeg PUBLIC GCDXdestListEnd PUBLIC GCDXprmsListBeg PUBLIC GCDXprmsListEnd PUBLIC GCDXcurrListBeg PUBLIC GCDXcurrListEnd PUBLIC GCDXothListBeg PUBLIC GCDXothListEnd ?DT?zdataf SEGMENT DATA RSEG ?DT?zdataf GCDXdestListBeg: ds 2 GCDXdestListEnd: ds 2 GCDXprmsListBeg: ds 2 GCDXprmsListEnd: ds 2 GCDXcurrListBeg: ds 2 GCDXcurrListEnd: ds 2 GCDXothListBeg: ds 2 GCDXothListEnd: ds 2 end
Erik
Thanks, Erik. I'll try it.