Discussion Forum

Address bits in XDATA

Next Thread | Thread List | Previous Thread Start a Thread | Settings

DetailsMessage
Read-Only
Author
Alan Chen
Posted
22-May-2002 18:31 GMT
Toolset
C51
New! Address bits in XDATA
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
.
.
How can I implement such function in C51? Thanks.

Read-Only
Author
Jon Young
Posted
22-May-2002 19:18 GMT
Toolset
C51
New! RE: Address bits in XDATA
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)
Read-Only
Author
Alan Chen
Posted
22-May-2002 19:41 GMT
Toolset
C51
New! RE: Address bits in XDATA
Thanks. I forgot all about "bit field".
Read-Only
Author
Andrew Neil
Posted
23-May-2002 09:41 GMT
Toolset
C51
New! RE: Address bits in XDATA
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
Read-Only
Author
Andrew Neil
Posted
23-May-2002 13:55 GMT
Toolset
C51
New! RE: Address bits in XDATA
... 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?
Read-Only
Author
Jon Ward
Posted
27-May-2002 08:26 GMT
Toolset
C51
New! RE: Address bits in XDATA
... 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;
}

The function test_bitfield tests a struct with 3 bit fields (4, 3, and 9 bits wide). A write and a read is performed to all bit fields.

The function test_bitmask test an unsigned int that is masked into 3 blocks (4, 3, and 9 bits wide). A write and a read is performed to each.

Note that each function writes and reads in the same way. The resulting code is as follows:

test_bitfield

             ; 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)


test_bitmask
             ; 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)

As you can see, the bit masking code is actually 2 bytes longer. If you carefully compare these functions, you'll find that the code generated is nearly identical.

Jon
Read-Only
Author
Graham Cole
Posted
27-May-2002 10:16 GMT
Toolset
C51
New! RE: Address bits in XDATA
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.
Read-Only
Author
Jon Young
Posted
27-May-2002 13:29 GMT
Toolset
C51
New! RE: Address bits in XDATA
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)
Read-Only
Author
Jon Young
Posted
27-May-2002 14:46 GMT
Toolset
C51
New! RE: Address bits in XDATA
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)
Read-Only
Author
Jon Ward
Posted
27-May-2002 17:12 GMT
Toolset
C51
New! RE: Address bits in XDATA
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
Read-Only
Author
Jon Ward
Posted
27-May-2002 17:24 GMT
Toolset
C51
New! RE: Address bits in XDATA
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

Next Thread | Thread List | Previous Thread Start a Thread | Settings