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 . .
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)
Thanks. I forgot all about "bit field".
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
... 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?
... 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)
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.
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)
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)
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
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