Hi All, I've been lurking on this board for about 12 months now, but this is my first post... I have traced a memory corruption problem to a single assembler statement. The statement is the first statement in the Keil printf() function. The invocation of the printf() function is this: printf("\n"); From my limited knowledge of the XC161's segmented addressing, I can't figure out why the Keil C compiler is generating the assembler that it has. Please refer to this image during the following description: 68.178.219.18/.../printf_segment_problem.png From what I can tell the assembler statement that was just executed: MOV [-R0],R12 is moving the contents of register R12 (0x0BF2) to the absolute address 0x80BFE. It is using DPP2 to calculate that absolute address as follows (correct me if I'm wrong): DPP2 = 0x20 = 100000 + 0x8BFE & 0x3FFF = 0x0BFE = 00101111111110b = 100000b 00101111111110b = 10000000101111111110b = 0x80BFE My hardware has 512K of RAM memory located at address 0x80000. NDATA is (I presume) indexed using DPP2 which puts the 16K of near data at 0x80000. After compiling the code I can see in the *.M66 file that: - NDATA is located at 0x80000..0x8004E - HDATA is located at 0x80050 through to 0x87A6F. I have an 8192 byte array declared, it is located by the compiler/linker at: 0x80050..0x8204F My question is this: Why does the compiler produce code in the printf() function that writes to memory address 0x80BFE which is in the middle of my array. Or if there is no answer to the "why" question, then what can I do to stop this memory overwritting from occuring. I guess it probably has something to do with the memory model and near data definitions. For what it's worth I have selected the HLarge memory model and 16K near RAM and 16K near ROM. There is probably a lot more info I can provide. If you can help and need more info just tell me what info you need and I'll get it. Regards (and thanks in advance, this has had me stumped for 2 days now). Paul
Look through the map file to see where the user stack is located. If the memory location 0x80BFE is not part of the user stack, then something corrupted the user stack pointer R0. Or maybe you just didn't allocate enough memory for the user stack. Regards, - mike
Hi Mike, Thanks for the reply. The first thing I did was to suspect a stack overflow. I increased the stack sizes in the startup file to: System stack: 0x0800 User Stack: 0x0400 User stack reg bank 1: 0x400 User stack reg bank 2: 0x400 According to the *.M66 file, they are located here:
START STOP LENGTH TYPE RTYP ALIGN TGR GRP COMB CLASS SECTION NAME ===================================================================================== 00C000H 00C7FFH 000800H DATA REL WORD --- 2 PUBL SDATA ?C_SYSSTACK 00C800H 00CBFFH 000400H DATA REL WORD --- 1 PUBL SDATA ?C_USERSTACK 00CC00H 00CFFFH 000400H DATA REL WORD --- 1 PUBL SDATA ?C_USERSTACK1 00F600H 00F9FFH 000400H DATA REL WORD --- 1 PUBL SDATA ?C_USERSTACK2 00FC00H 00FC1FH 000020H DATA --- BYTE --- --- --- *REG* ?C_MAINREGISTERS 080000H 08001DH 00001EH DATA REL WORD --- 1 PUBL NDATA0 ?ND0?TIM ...
Ok, after much searching, I think I can see the cause of the problem. I just don't know why... I modified the following lines in the Start_V2.A66 file from this:
?C_USERSTACK SECTION DATA PUBLIC 'NDATA' ... ?C_USERSTACK1 SECTION DATA PUBLIC 'NDATA' ... ?C_USERSTACK2 SECTION DATA PUBLIC 'NDATA' ... ?C_SYSSTACK SECTION DATA PUBLIC 'IDATA'
?C_USERSTACK SECTION DATA PUBLIC 'SDATA' ... ?C_USERSTACK1 SECTION DATA PUBLIC 'SDATA' ... ?C_USERSTACK2 SECTION DATA PUBLIC 'SDATA' ... ?C_SYSSTACK SECTION DATA PUBLIC 'SDATA'
what is the correct way to force the stacks to be in DSRAM at 0xC000? I can't be 100% sure, but it looks like you just found the correct way of putting the stacks where you want them. The original version of Start_V2.A66 puts the user stacks into the NDATA class. Clearly you don't want them there. So you just put them into a different class. SDATA should do it, because we know that DPP3 is properly initialized for accessing SDATA. For a description of classes that the C166 compiler uses, see here: http://www.keil.com/support/man/docs/l166/l166_in_classes.htm Best of luck, - mike
I appreciate your response Mike, thanks for taking the time. I probably wasn't clear in my last message. I originally had changed the stacks from NDATA to SDATA and that is what had caused the initial memory conflict with the printf("\n") statement. Doing so, correctly put the stacks into memory at 0xCxxxx, but incorrectly left the stack pointer R0 pointing to someplace in 0x80xxx. After your comment about stacks overflowing I put the stacks back to NDATA (the default config in the Start_V2.A66 file) and that fixed the problem. But only because the stacks are now where R0 is initialised to be. So my question should really be expanded to: How do I force the stacks into memory at 0xCxxxx (answer: probably by setting them into SDATA). BUT MORE IMPORTANTLY how do I make the stack pointer R0 point to them at 0xCxxx instead of incorrectly to someplace in 0x80xxxx. You see when I place the stacks into SDATA, R0 is incorrectly set to 0x8xxx (using DPP2) when it should be 0xCxxx (using DPP3). I would have thought the compiler/linker would be clever enough to set R0 so that it correctly used DPP3 when the stacks are in the segment referenced by DPP3. Regards Paul
Oops, my mistake. I have Startup.A66 within my reach at the moment. It is written for the C167, but I think that Start_V2.A66 should be similar. In this file the initialization of R0 is hardcoded as
MOV R0,#DPP2:?C_USERSTKTOP
It is probably easiest to do it as Mike says, but you can also do it without hard coding the DPP register to the instruction loading the user stack top to R0. 1. Place the user stacks to SDATA as you have done. 2. Change the
ASSUME DPP3:SYSTEM
ASSUME DPP3:SDATA
SDATA DGROUP ?C_SYSSTACK, ?C_USERSTACK, ?C_USERSTACK1, ?C_USERSTACK2, SYSTEM
Please see: http://www.keil.com/support/docs/1695.htm It should be noted that you need also the USERSTACKDPP3 directive.
Thanks everyone for your replies. It all makes sense, now back to work... :) Regards Paul