Hi all,
In my project, I write some codes like this sample:
1 void foo(char xdata *pbuf, char a, char b) 2 { 3 int pdata bufaddr; 4 long pdata testval; 5 6 testval = 0x200; 7 bufaddr = pbuf; 8 } 9 10 void main(void) 11 { 12 char xdata buf[10]; 14 15 foo(buf, 0, 1); 16 }
And C51 would be compile these codes to this assembly:
; FUNCTION _foo (BEGIN) ; SOURCE LINE # 1 0000 8D00 R MOV a,R5 0002 8B00 R MOV b,R3 ;---- Variable 'pbuf' assigned to Register 'DPTR' ---- 0004 8F82 MOV DPL,R7 0006 8E83 MOV DPH,R6 ; SOURCE LINE # 2 ; SOURCE LINE # 6 0008 7800 R MOV R0,#LOW testval 000A 120000 E LCALL ?C?LSTKPDATA 000D 00 DB 00H 000E 00 DB 00H 000F 02 DB 02H 0010 00 DB 00H ; SOURCE LINE # 7 0011 AF82 MOV R7,DPL 0013 7800 R MOV R0,#LOW bufaddr 0015 E583 MOV A,DPH 0017 F2 MOVX @R0,A 0018 08 INC R0 0019 EF MOV A,R7 001A F2 MOVX @R0,A ; SOURCE LINE # 8 001B 22 RET ; FUNCTION _foo (END) ; FUNCTION main (BEGIN) ; SOURCE LINE # 10 ; SOURCE LINE # 11 ; SOURCE LINE # 14 0000 7E00 R MOV R6,#HIGH buf 0002 7F00 R MOV R7,#LOW buf 0004 7B01 MOV R3,#01H 0006 E4 CLR A 0007 FD MOV R5,A 0008 020000 R LJMP _foo ; FUNCTION main (END)
C51 would assign parameter pbuf to DPTR when function foo is called. Then in foo function, program first would call ?C?LSTKPDATA to assign a constant long type value to testval. ?C?LSTKPDATA would do the following assembly:
D083 POP DPH(0x83) D082 POP DPL(0x82) E4 CLR A 93 MOVC A,@A+DPTR F2 MOVX @R0,A 08 INC R0 7401 MOV A,#0x01 93 MOVC A,@A+DPTR F2 MOVX @R0,A 08 INC R0 7402 MOV A,#0x02 93 MOVC A,@A+DPTR F2 MOVX @R0,A 08 INC R0 7403 MOV A,#0x03 93 MOVC A,@A+DPTR F2 MOVX @R0,A 7404 MOV A,#0x04 73 JMP @A+DPTR
When finished ?C?LSTKPDATA, program would assign pbuf value to bufaddr. But pbuf is stored in DPTR, and ?C?LSTKPDATA used DPTR to assgin value before, it cause pbuf value in DPTR is overwrited, so the bufaddr would store the wrong value.
It seems this situation is caused by optimization of C51. I want to ask whether any method to prevent this situation occur.
Thanks all.
Sorry, it seems that my sample code let all misunderstand my question.
Actually, the code having the issue in my project is the following:
1915 BYTE MsReadOnePage(BYTE xdata * pbBuf,UINT iBlockAddr,BYTE bPageAddr) 1916 { 1917 BYTE bIntVal; 1918 1919 /* Set transfer length */ 1920 CardByteLenReg = 0x200; 1921 1922 /* Set CardFifoAdr */ 1923 CardFifoAdrReg = pbBuf; 1924 1925 if( !MsSetReadCmdParameter(DATA_AND_EXTRA_DATA_BY_PAGE,iBlockAddr,bPageAddr) ) 1926 { 1927 return FAILURE; 1928 } 1929 1930 bIntVal = MsGetInt(); 1931 1932 if( bIntVal == FAILURE ) 1933 { 1934 return FAILURE; 1935 } ... 1960 return SUCCESS; 1961 }
In this function, some basic data type is defined as the following:
#define BYTE unsigned char #define UINT unsigned int #define ULONG unsigned long
CardByteLenReg, CardFifoAdrReg is the hardware registers accessed as external ram by 8051. In project, I declare them to pdata and access them
UINT volatile pdata CardFifoAdrReg _at_ 0x20; ULONG volatile pdata CardByteLenReg _at_ 0x22;
C51 compile this function to these assembly:
; FUNCTION _MsReadOnePage (BEGIN) ; SOURCE LINE # 1915 0000 8C00 R MOV iBlockAddr,R4 0002 8D00 R MOV iBlockAddr+01H,R5 0004 8B00 R MOV bPageAddr,R3 ;---- Variable 'pbBuf' assigned to Register 'DPTR' ---- 0006 8F82 MOV DPL,R7 0008 8E83 MOV DPH,R6 ; SOURCE LINE # 1916 ; SOURCE LINE # 1920 000A 7800 E MOV R0,#LOW CardByteLenReg 000C 120000 E LCALL ?C?LSTKPDATA 000F 00 DB 00H 0010 00 DB 00H 0011 02 DB 02H 0012 00 DB 00H ; SOURCE LINE # 1923 0013 AF82 MOV R7,DPL 0015 7800 E MOV R0,#LOW CardFifoAdrReg 0017 E583 MOV A,DPH 0019 F2 MOVX @R0,A 001A 08 INC R0 001B EF MOV A,R7 001C F2 MOVX @R0,A ; SOURCE LINE # 1925 001D AD00 R MOV R5,iBlockAddr+01H 001F AC00 R MOV R4,iBlockAddr 0021 7F20 MOV R7,#020H 0023 120000 R LCALL _MsSetReadCmdParameter 0026 EF MOV A,R7 0027 7002 JNZ ?C0367 ; SOURCE LINE # 1926 ; SOURCE LINE # 1927 0029 FF MOV R7,A 002A 22 RET ; SOURCE LINE # 1928 002B ?C0367: ; SOURCE LINE # 1930 002B 120000 R LCALL MsGetInt ;---- Variable 'bIntVal' assigned to Register 'R7' ---- ; SOURCE LINE # 1932 002E EF MOV A,R7 002F 7002 JNZ ?C0369 ; SOURCE LINE # 1933 ; SOURCE LINE # 1934 0031 FF MOV R7,A 0032 22 RET ; SOURCE LINE # 1935 0033 ?C0369: ... ; SOURCE LINE # 1961 005F ?C0368: 005F 22 RET ; FUNCTION _MsReadOnePage (END)
These code would have the same problem with the sample code in my first post when assigning value to CardByteLenReg and CardFifoAdrReg: DPTR is overwrited in ?C?LSTKPDATA, so CardFifoAdrReg would be assigned a wrong value.
What should I do to avoid this situation occur?
That's one of the common problems caused by trying to present a problem while not presenting the actual problem. Writing good problem reports is a seriously underestimated skill.
It can take very deep understanding of all tools and languages involved to boil down a given source code to the minimal, yet sufficient example that still actually demonstrates the problem faithfully. You got one thing right in your first code sample: self-sufficiency, i.e. you showed code that actually compiled as-is, with no further assumptions, unknown include files, etc (Unfortunately, you got this wrong the second time round). You did get the other major aspect wrong the first time round, though: making sure that the code is still functionally equivalent to the original which you didn't want to publish. Exchanging static, volatile fixed-address variables for unqualified automatic ones totally changed the scope of the problem.
It would still be better if you changed the type of CardFifoAdrReg to (xdata void *), and brought your second sample code into stand-alone, compilable form, but from what I can see, that does look like you might have a support case to bring to Keil's attention there. Because whatever goes wrong there, it appears to happen between the compiler and its support library functions, so there's little else you could do about it.
A possible workaround suggests itself, though: switch order of assignments to those two registers, if the hardware behind them permits it.