Hi, I am looking for a way to write some C51 functions to set or clear bits stored in the 8051 external data memory. For example, the following code was done in the 8051 assembly language:
;******************************* SYSTEM_TROUBLE1 XDATA 1000H AC_FAIL ACC.0 LOW_BAT ACC.1 . . SYSTEM_TROUBLE2 XDATA 1001H TELCO1_FAIL ACC.0 TELCO2_FAIL ACC.1 . . ;******************************* . . MOV DPTR, #SYSTEM_TROUBLE1 MOVX A, @DPTR SETB AC_FAIL MOVX @DPTR . .
Graham, Thanks for that. I missed your earlier post. The points you make are very good and I've passed them on to engineering to incorporate in a future release. Jon
Opps, sorry, I picked the wrong flag to test. You are correct, bit fields are inefficient. Uhhhh. You only tested one case of bit-fields -- a 1-bit bit-field. I would make more tests before making such a broad, sweeping statement. Anyway, what is so inefficient about the code that was generated? Jon
Opps, sorry, I picked the wrong flag to test. You are correct, bit fields are inefficient. It would also be great if the compiler also optimized: <bitfield> <op> <const> or <const> <op> <bitfield> Where <op> is ==, !=, <, >, <=, >=, &&, || xdata struct { char AC_FAIL :1; char LOW_BAT :1; } SYSTEM_TROUBLE1 _at_ 0x1000; void main( void ) { if( SYSTEM_TROUBLE1.LOW_BAT ) SYSTEM_TROUBLE1.AC_FAIL = 1; } ; FUNCTION main (BEGIN) 0000 901000 MOV DPTR,#SYSTEM_TROUBLE1 0003 E0 MOVX A,@DPTR 0004 FF MOV R7,A 0005 C3 CLR C 0006 13 RRC A 0007 30E004 JNB ACC.0,?C0002 000A EF MOV A,R7 000B 4401 ORL A,#01H 000D F0 MOVX @DPTR,A 000E ?C0002: 000E 22 RET ; FUNCTION main (END)
Can you give an example? The following looks pretty good.
xdata struct { char AC_FAIL :1; char LOW_BAT :1; } SYSTEM_TROUBLE1 _at_ 0x1000; void main( void ) { if( SYSTEM_TROUBLE1.AC_FAIL ) SYSTEM_TROUBLE1.LOW_BAT = 1; } ; FUNCTION main (BEGIN) 0000 901000 MOV DPTR,#SYSTEM_TROUBLE1 0003 E0 MOVX A,@DPTR 0004 30E003 JNB ACC.0,?C0002 0007 4402 ORL A,#02H 0009 F0 MOVX @DPTR,A 000A ?C0002: 000A 22 RET ; FUNCTION main (END)
I think that Andy was thinking of bit fields that comprise a single bit - which is after all what the original question was about. They are not as efficient as they could be. See: http://www.keil.com/forum/docs/thread1291.asp Particularly strange is testing a single bit field in, for example, an if statement. Of course, it can all be done with masks, but that is inellegant and error prone.
... and another thing: I seem to remember that the Keil implementation is pretty inefficient. I've used both bit-fields and bit masking and have not noticed a real difference in the code generated for either.
/*-------------------------------------- Struct for bit field test. --------------------------------------*/ struct bf_st { unsigned int bf1: 4; unsigned int bf2: 3; unsigned int bf3: 9; }; struct bf_st bfst; // Structure for 3 bit fields (16 bits) /*-------------------------------------- Unsigned int for bit mask test. --------------------------------------*/ unsigned int bfui; // int for 3 bit fields (16 bits) /*-------------------------------------- Macros used to read and write bits in the unsigned int. --------------------------------------*/ #define Get_BF1a (bfui & 0x0F) #define Get_BF2a ((bfui >> 4) & 0x07) #define Get_BF3a ((bfui >> 7) & 0x01FF) #define Set_BF1a(x) (bfui = (bfui & ~0x000F) | (x) & 0x0F) #define Set_BF2a(x) (bfui = (bfui & ~0x0070) | ((x) & 0x07) << 4) #define Set_BF3a(x) (bfui = (bfui & ~0xFF80) | ((x) & 0x1FF) << 7) /*-------------------------------------- Function to test bit field. --------------------------------------*/ void test_bitfield (void) { volatile unsigned int y; bfst.bf1 = 14; bfst.bf2 = 7; bfst.bf3 = 0x1A5; y = bfst.bf1; y = bfst.bf2; y = bfst.bf3; } /*-------------------------------------- Function to test bit masking. --------------------------------------*/ void test_bitmask (void) { volatile unsigned int y; Set_BF1a(14); Set_BF2a(7); Set_BF3a(0x1A5); y = Get_BF1a; y = Get_BF2a; y = Get_BF3a; }
; FUNCTION test_bitfield (BEGIN) 34 void test_bitfield (void) 35 { 36 1 volatile unsigned int y; 37 1 38 1 bfst.bf1 = 14; 0000 E500 R MOV A,bfst+01H 0002 54F0 ANL A,#0F0H 0004 850000 R MOV bfst,bfst 0007 440E ORL A,#0EH 0009 F500 R MOV bfst+01H,A 39 1 bfst.bf2 = 7; 000B 850000 R MOV bfst,bfst 000E 4470 ORL A,#070H 0010 F500 R MOV bfst+01H,A 40 1 bfst.bf3 = 0x1A5; 0012 547F ANL A,#07FH 0014 FF MOV R7,A 0015 74D2 MOV A,#0D2H 0017 F500 R MOV bfst,A 0019 EF MOV A,R7 001A 4480 ORL A,#080H 001C F500 R MOV bfst+01H,A 41 1 42 1 y = bfst.bf1; 001E FF MOV R7,A 001F 750000 R MOV y,#00H 0022 EF MOV A,R7 0023 540F ANL A,#0FH 0025 F500 R MOV y+01H,A 43 1 y = bfst.bf2; 0027 E500 R MOV A,bfst 0029 C4 SWAP A 002A F8 MOV R0,A 002B 54F0 ANL A,#0F0H 002D C8 XCH A,R0 002E E500 R MOV A,bfst+01H 0030 C4 SWAP A 0031 540F ANL A,#0FH 0033 48 ORL A,R0 0034 750000 R MOV y,#00H 0037 5407 ANL A,#07H 0039 F500 R MOV y+01H,A 44 1 y = bfst.bf3; 003B AE00 R MOV R6,bfst 003D E500 R MOV A,bfst+01H 003F 7807 MOV R0,#07H 0041 ?C0006: 0041 CE XCH A,R6 0042 C3 CLR C 0043 13 RRC A 0044 CE XCH A,R6 0045 13 RRC A 0046 D8F9 DJNZ R0,?C0006 0048 FF MOV R7,A 0049 EE MOV A,R6 004A 5401 ANL A,#01H 004C F500 R MOV y,A 004E 8F00 R MOV y+01H,R7 45 1 } 0050 22 RET ; FUNCTION test_bitfield (END)
; FUNCTION test_bitmask (BEGIN) 50 void test_bitmask (void) 51 { 52 1 volatile unsigned int y; 53 1 54 1 Set_BF1a(14); 0000 E500 R MOV A,bfui+01H 0002 54F0 ANL A,#0F0H 0004 850000 R MOV bfui,bfui 0007 440E ORL A,#0EH 0009 F500 R MOV bfui+01H,A 55 1 Set_BF2a(7); 000B 548F ANL A,#08FH 000D 850000 R MOV bfui,bfui 0010 4470 ORL A,#070H 0012 F500 R MOV bfui+01H,A 56 1 Set_BF3a(0x1A5); 0014 547F ANL A,#07FH 0016 FF MOV R7,A 0017 74D2 MOV A,#0D2H 0019 F500 R MOV bfui,A 001B EF MOV A,R7 001C 4480 ORL A,#080H 001E F500 R MOV bfui+01H,A 57 1 58 1 y = Get_BF1a; 0020 750000 R MOV y,#00H 0023 E500 R MOV A,bfui+01H 0025 540F ANL A,#0FH 0027 F500 R MOV y+01H,A 59 1 y = Get_BF2a; 0029 E500 R MOV A,bfui 002B C4 SWAP A 002C F8 MOV R0,A 002D 54F0 ANL A,#0F0H 002F C8 XCH A,R0 0030 E500 R MOV A,bfui+01H 0032 C4 SWAP A 0033 540F ANL A,#0FH 0035 48 ORL A,R0 0036 750000 R MOV y,#00H 0039 5407 ANL A,#07H 003B F500 R MOV y+01H,A 60 1 y = Get_BF3a; 003D E500 R MOV A,bfui+01H 003F AE00 R MOV R6,bfui 0041 7807 MOV R0,#07H 0043 ?C0007: 0043 CE XCH A,R6 0044 C3 CLR C 0045 13 RRC A 0046 CE XCH A,R6 0047 13 RRC A 0048 D8F9 DJNZ R0,?C0007 004A FF MOV R7,A 004B EE MOV A,R6 004C 5401 ANL A,#01H 004E F500 R MOV y,A 0050 8F00 R MOV y+01H,R7 61 1 } 0052 22 RET ; FUNCTION test_bitmask (END)
... and another thing: I seem to remember that the Keil implementation is pretty inefficient. So, C51 bitfields are poorly documented, and the implementation is confusing and inefficient - but apart from that they're great! Probably best to stick to masking, etc?
Beware! From K&R, "Almost everything about fields is implementation-dependent" Unfortunately, it is not documented in the C51 manual. :-( See the following Knowledge Base articles, which document a couple of the quirks of Keil's implementation: http://www.keil.com/support/docs/928.htm http://www.keil.com/support/docs/1279.htm
Thanks. I forgot all about "bit field".
try:
xdata struct { char AC_FAIL :1; char LOW_BAT :1; } SYSTEM_TROUBLE1 _at_ 0x1000; void main( void ) { SYSTEM_TROUBLE1.LOW_BAT = 1; } ; FUNCTION main (BEGIN) 0000 901000 MOV DPTR,#SYSTEM_TROUBLE1 0003 E0 MOVX A,@DPTR 0004 4402 ORL A,#02H 0006 F0 MOVX @DPTR,A 0007 22 RET ; FUNCTION main (END)
View all questions in Keil forum