We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Is there a way to change the DEFINE statement to get rid of the two useless mov(s)?
C51 COMPILER V6.02, COMPILATION OF MODULE MAIN OBJECT MODULE PLACED IN .\MAIN.OBJ COMPILER INVOKED BY: C:\PROGRAM FILES\KEIL\C51\BIN\C51.EXE .\MAIN.C OPTIMIZE(7,SPEED) NOINTPROMOTE MODDP2 DEBUG OBJECTEX -TEND CODE SYMBOLS NOCOND stmt level source 1 typedef unsigned char BYTE; 2 typedef unsigned int WORD; 3 4 typedef pdata struct 5 { 6 BYTE PC0 :1; 7 BYTE PC1 :1; 8 BYTE nFifoPend :1; //PC2 9 BYTE PC3 :1; 10 BYTE FpgaReset :1; //PC4 11 BYTE PC5 :1; 12 BYTE PC6 :1; 13 BYTE PC7 :1; 14 } CType; 15 16 extern volatile BYTE pdata xOUTC; 17 18 #define IoPins_FpgaReset ( ((CType pdata*)(&xOUTC))->FpgaReset ) 19 20 void main(void) 21 { 22 1 IoPins_FpgaReset = 1; 23 1 } 24 25 ; FUNCTION main (BEGIN) ; SOURCE LINE # 20 ; SOURCE LINE # 21 ; SOURCE LINE # 22 0000 7A00 E MOV R2,#HIGH xOUTC 0002 7900 E MOV R1,#LOW xOUTC 0004 7800 E MOV R0,#LOW xOUTC 0006 E2 MOVX A,@R0 0007 4410 ORL A,#010H 0009 F2 MOVX @R0,A ; SOURCE LINE # 23 000A 22 RET ; FUNCTION main (END)
1. bit-fields in Keil C (8051's fault) are horribly inefficient. 2. Pdata still requires two bytes for a pointer when we cannot guarantee that the page (a 256 byte block of xdata) is not currently loaded. How does this work for you?
typedef enum { PC0 = 1 << 0, PC1 = 1 << 1, FIFO_PEND = 1 << 2, PC3 = 1 << 3, FPGA_RESET = 1 << 4, PC5 = 1 << 5, PC6 = 1 << 6, PC7 = 1 << 7 } FpgaPortC; typedef unsigned char U8; // I use 'r_' to indicate some sore of register variable. static volatile U8 pdata r_portC _at_ 0x8000; // 0x8000 is a guess. #ifdef MUST_INLINE #define resetFpga() do { r_portC |= FPGA_RESET; } while (0) #else void resetFpga(void) { r_portC |= FPGA_RESET; } #endif void main(void) { resetFpga(); for (;;); } ;; *** No inlining *** ; FUNCTION resetFpga (BEGIN) ; SOURCE LINE # 273 ; SOURCE LINE # 274 ; SOURCE LINE # 275 0000 7800 MOV R0,#LOW r_portC 0002 E2 MOVX A,@R0 0003 4410 ORL A,#010H 0005 F2 MOVX @R0,A ; SOURCE LINE # 276 0006 22 RET ; FUNCTION resetFpga (END) ; FUNCTION main (BEGIN) ; SOURCE LINE # 279 ; SOURCE LINE # 280 ; SOURCE LINE # 281 0000 120000 R LCALL resetFpga ; SOURCE LINE # 283 0003 ?C0002: 0003 80FE SJMP ?C0002 ; FUNCTION main (END) ;; *** Inlining *** ; FUNCTION main (BEGIN) ; SOURCE LINE # 279 ; SOURCE LINE # 280 ; SOURCE LINE # 281 0000 7800 MOV R0,#LOW r_portC 0002 E2 MOVX A,@R0 0003 4410 ORL A,#010H 0005 F2 MOVX @R0,A ; SOURCE LINE # 283 0006 ?C0004: 0006 80FE SJMP ?C0004 ; FUNCTION main (END) In both cases: C51 COMPILER V6.10, COMPILATION OF MODULE UART OBJECT MODULE PLACED IN .\a.OBJ COMPILER INVOKED BY: C:\Keil\C51\BIN\C51.EXE .\a.c BROWSE NOINTPROMOTE DEBUG OBJECTEXTEND CODE PAGEWIDTH(132) PAGELENGTH(6600)
There are several problems in the program that you have that cause the superfluous moves. They are: 1. The pdata in the typedef does nothing so it should be removed. 2. The volatile on the "extern BYTE pdata xOUTC" is not necessary and it is what causes the goofy access to get the address of xOUTC. 3. The volatile chould be placed on the pointer derefencing (in the #define). The following minor modificationto your program generates the desired results:
typedef unsigned char BYTE; typedef unsigned int WORD; //typedef pdata struct typedef struct { BYTE PC0 :1; BYTE PC1 :1; BYTE nFifoPend :1; //PC2 BYTE PC3 :1; BYTE FpgaReset :1; //PC4 BYTE PC5 :1; BYTE PC6 :1; BYTE PC7 :1; } CType; extern BYTE pdata xOUTC; #define IoPins_FpgaReset ( ((CType volatile pdata *) &xOUTC)->FpgaReset ) void main(void) { IoPins_FpgaReset = 1; }
0000 7800 E MOV R0,#LOW xOUTC 0002 E2 MOVX A,@R0 0003 4410 ORL A,#010H 0005 F2 MOVX @R0,A ; SOURCE LINE # 24 0006 22 RET ; FUNCTION main (END)
Hey, them there bit-fields aren't so bad! I'm impressed. But couldn't we dispense with the nasty macro altogether?
typedef struct { BYTE PC0 :1; BYTE PC1 :1; BYTE nFifoPend :1; //PC2 BYTE PC3 :1; BYTE FpgaReset :1; //PC4 BYTE PC5 :1; BYTE PC6 :1; BYTE PC7 :1; } CType; volatile CType pdata r_portC _at_ 0x8000; void main(void) { r_portC.FpgaReset = 1; }
Thanks for the suggestion. However 1. I have never found that the bit-fields in Keil C inefficient. 2. When there is only one page of XDATA (which is common in small designs), it is fairly easy guarantee the correct page is loaded. If fact the 'upper address byte' is irrelevent. In particular, this design is using an Anchor chip that has all of it's control registers on one page. I just load the MPAGE register with the page address once and never have to use the DPTR for control access again.
Thanks for pointing out that it was the volatile qualifier that was tripping the compiler up. I can now work around it. I sure do prefer the bit field semantics over bit mask semantics. However, I disagree that 'The volatile on the "extern BYTE pdata xOUTC" is not necessary'. For example, add the following line
xOUTC = xOUTC;
However, I disagree that 'The volatile on the "extern BYTE pdata xOUTC" is not necessary'. It is not necessary because C ignores it on extern'd variable declarations. It only matters on the definition which is in some other translation unit for your project. If you don't put volatile on the definition then, yes, xOUT = xOUT will be optimized out. Remember definitions allocate storage, declarations do not have to (a definition is an implicit declaration). So I agree with your bit-fields being efficient after playing with them. What did you think of my other example using
volatile CType pdata r_portC _at_ 0x8000;
I am sorry, I am quite wrong. Obviously since the compiler cannot know that the definition might have the volatile keyword if the declaration does not then it will optimize out the xOUT = xOUT statement. You do need to make the definition and extern declaration volatile if the memory "location" is actually a memory mapped device or can be changed by an ISR or other task. Please excuse my whilst I eat this large crow. - Mark
I think the real problem here comes from the fact that the memory location that is referenced is an unsigned char type. However, the actual data is a structure. So, to access the structure you must take the address of the unsigned char, cast it to a structure pointer, and dereference an element of the structure. I think it would be much more clear if the original variable were declared as a structure of the appropriate type. Then you don't have to do all of this explicit type casting and you won't run into that sneaky volatile problem. Jon