This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

use of bit as array index fails? (if bit is set)

Hi,

I suspect I have hit upon a bug in C51 V6.
When a bit variable is used as an index into
array of int or long int, it fails. Actually,
it fails only if the bit is 1; otherwise it
works ok. I am not 100% sure whether this
is a bug or am I doing something wrong?
For now, I replaced the bit variable by an
unsigned char, but I can not afford to do
so in the final version of my program. Is
there a workaround?

I wrote the test code below when I suspected
this bug. I tested it with the simulator and
I see un-expected results.

One User

#include <reg52.h>
#include <stdio.h>

xdata unsigned int UnIntArr[2] = {	0x1234, 0x5678	} ;
xdata unsigned long int UnLongIntArr[2] = {	0x12345678, 0x9abcdef0	} ;

void main ()
{
	unsigned char uch ;
	bit b ;

	RCAP2H = 0xff ;
	RCAP2L = 0xdc ;
	T2CON = 0x34 ;
	SCON = 0x50 ;
	TI = 1 ;

	uch = 0 ;
	b = 0 ;
	printf("first uch = 0 and b = 0\n") ;
	printf("UnIntArr[uch] = %04X, UnIntArr[b] = %04X\n",UnIntArr[uch],UnIntArr[b]) ;
	// expected values = 0x1234, 0x1234 (works ok)
	printf("UnLongIntArr[uch] = %08lX, UnLongIntArr[b] = %08lX\n",UnLongIntArr[uch],UnLongIntArr[b]) ;
	// expected values = 0x12345678, 0x12345678 (works ok)

	uch = 1 ;
	b = 1 ;
	printf("now uch = 1 and b = 1\n") ;
	printf("UnIntArr[uch] = %04X, UnIntArr[b] = %04X\n",UnIntArr[uch],UnIntArr[b]) ;
	// expected values = 0x5678, 0x5678
	// BUG HERE-> you get 0x5678, 0x3456
	printf("UnLongIntArr[uch] = %08lX, UnLongIntArr[b] = %08lX\n",UnLongIntArr[uch],UnLongIntArr[b]) ;
	// expected values = 0x9ABCDEF0, 0x9ABCDEF0
	// BUG HERE TOO-> you get 0x9ABCDEF0, 0x3456789A
}

Parents
  • I get the same results with 7.02b. The manual doesn't list use as an array index among the limitations of a bit type, so I'd call it a bug. Package it the demo project and send it to support@keil.com.

    Here's the generated code for the offending line, with my comments:

                                               ; SOURCE LINE # 86
                           MOV     R3,#0FFH
                     R     MOV     R2,#HIGH ?SC_67
                     R     MOV     R1,#LOW ?SC_67
    
    ; here's where we get UnIntArray[uch]
    
                           ; retrieve uch
                     R     MOV     DPTR,#uch
                           MOVX    A,@DPTR
    
                           ; * 4 (sizeof(long))
                           ADD     A,ACC
                           ADD     A,ACC
    
                           ; set up DPTR to grab
                           ; value
                     R     ADD     A,#LOW UnLongIntArr
                           MOV     DPL,A
                           CLR     A
                     R     ADDC    A,#HIGH UnLongIntArr
                           MOV     DPH,A
                     E     CALL    ?C?LLDXDATA
                     E     MOV     DPTR,#?_printf?BYTE+03H
                     E     CALL    ?C?LSTXDATA
    
    ; Here's where we get UnIntArray[b]
    
                           ; retrieve b
                     R     MOV     C,b
                           CLR     A
                           MOV     R6,A
                           RLC     A
    
    ; bug is here -- missing multiply by
    ; sizeof(long) (a couple of ADD A, ACCs); A is 1 at this point, not 4
    
                           ; set up DPTR for
                           ; UnIntArray[b]
                     R     ADD     A,#LOW UnLongIntArr
                           MOV     DPL,A
                           MOV     A,R6
                     R     ADDC    A,#HIGH UnLongIntArr
                           MOV     DPH,A
                     E     CALL    ?C?LLDXDATA
                     E     MOV     DPTR,#?_printf?BYTE+07H
                     E     CALL    ?C?LSTXDATA
                     E     CALL    _printf
    
    

    As a workaround, you can cast the bit type to an int and get the right answer:

    	printf("UnLongIntArr[uch] = %08lX, UnLongIntArr[b] = %08lX\n",UnLongIntArr[uch],UnLongIntArr[(int)b]) ;
    
    produces code like:
    
    
                     R     MOV     C,b
                           CLR     A
                           MOV     R6,A
                           RLC     A
                           MOV     R0,#02H
                 ?C0005:
                           CLR     C
                           RLC     A
                           XCH     A,R6
                           RLC     A
                           XCH     A,R6
                     R     DJNZ    R0,?C0005
    
    

    Kind of miss the elegance of the A += A; A += A; sequence to get A *= 4 here. It's a whole loop! And it's acting on both A and R6; should just leave R6 until the end. Bleah. You get much cleaner code if you declare a temporary U8 instead of the cast:

    	tmp = b;
    	printf("UnIntArr[uch] = %04X, UnIntArr[b] = %04X\n",UnIntArr[uch],UnIntArr[tmp]) ;
    	// expected values = 0x5678, 0x5678
    	// BUG HERE-> you get 0x5678, 0x3456
    	printf("UnLongIntArr[uch] = %08lX, UnLongIntArr[b] = %08lX\n",UnLongIntArr[uch],UnLongIntArr[tmp]) ;
    
    
    ;; cost to set up tmp
                           MOV     C,b
                           CLR     A
                           RLC     A
                     R     MOV     DPTR,#tmp
                           MOVX    @DPTR,A
    

    If you put tmp in data instead of xdata, the object would get cleaner yeet.

Reply
  • I get the same results with 7.02b. The manual doesn't list use as an array index among the limitations of a bit type, so I'd call it a bug. Package it the demo project and send it to support@keil.com.

    Here's the generated code for the offending line, with my comments:

                                               ; SOURCE LINE # 86
                           MOV     R3,#0FFH
                     R     MOV     R2,#HIGH ?SC_67
                     R     MOV     R1,#LOW ?SC_67
    
    ; here's where we get UnIntArray[uch]
    
                           ; retrieve uch
                     R     MOV     DPTR,#uch
                           MOVX    A,@DPTR
    
                           ; * 4 (sizeof(long))
                           ADD     A,ACC
                           ADD     A,ACC
    
                           ; set up DPTR to grab
                           ; value
                     R     ADD     A,#LOW UnLongIntArr
                           MOV     DPL,A
                           CLR     A
                     R     ADDC    A,#HIGH UnLongIntArr
                           MOV     DPH,A
                     E     CALL    ?C?LLDXDATA
                     E     MOV     DPTR,#?_printf?BYTE+03H
                     E     CALL    ?C?LSTXDATA
    
    ; Here's where we get UnIntArray[b]
    
                           ; retrieve b
                     R     MOV     C,b
                           CLR     A
                           MOV     R6,A
                           RLC     A
    
    ; bug is here -- missing multiply by
    ; sizeof(long) (a couple of ADD A, ACCs); A is 1 at this point, not 4
    
                           ; set up DPTR for
                           ; UnIntArray[b]
                     R     ADD     A,#LOW UnLongIntArr
                           MOV     DPL,A
                           MOV     A,R6
                     R     ADDC    A,#HIGH UnLongIntArr
                           MOV     DPH,A
                     E     CALL    ?C?LLDXDATA
                     E     MOV     DPTR,#?_printf?BYTE+07H
                     E     CALL    ?C?LSTXDATA
                     E     CALL    _printf
    
    

    As a workaround, you can cast the bit type to an int and get the right answer:

    	printf("UnLongIntArr[uch] = %08lX, UnLongIntArr[b] = %08lX\n",UnLongIntArr[uch],UnLongIntArr[(int)b]) ;
    
    produces code like:
    
    
                     R     MOV     C,b
                           CLR     A
                           MOV     R6,A
                           RLC     A
                           MOV     R0,#02H
                 ?C0005:
                           CLR     C
                           RLC     A
                           XCH     A,R6
                           RLC     A
                           XCH     A,R6
                     R     DJNZ    R0,?C0005
    
    

    Kind of miss the elegance of the A += A; A += A; sequence to get A *= 4 here. It's a whole loop! And it's acting on both A and R6; should just leave R6 until the end. Bleah. You get much cleaner code if you declare a temporary U8 instead of the cast:

    	tmp = b;
    	printf("UnIntArr[uch] = %04X, UnIntArr[b] = %04X\n",UnIntArr[uch],UnIntArr[tmp]) ;
    	// expected values = 0x5678, 0x5678
    	// BUG HERE-> you get 0x5678, 0x3456
    	printf("UnLongIntArr[uch] = %08lX, UnLongIntArr[b] = %08lX\n",UnLongIntArr[uch],UnLongIntArr[tmp]) ;
    
    
    ;; cost to set up tmp
                           MOV     C,b
                           CLR     A
                           RLC     A
                     R     MOV     DPTR,#tmp
                           MOVX    @DPTR,A
    

    If you put tmp in data instead of xdata, the object would get cleaner yeet.

Children
  • Hi,

    Thanks!
    I tried to cast the bit to unsigned char:

    	printf("UnIntArr[uch] = %04X, UnIntArr[b] = %04X\n",UnIntArr[uch],UnIntArr[(unsigned char) b]) ;
    

    It produced:

    00B2 A200        R     MOV     C,b
    C51 COMPILER V6.21  TEST                                                                   02/08/2003 20:18:31 PAGE 4
    
    00B4 E4                CLR     A
    00B5 33                RLC     A
    00B6 25E0              ADD     A,ACC
    

    Looks pretty good. So I don't need to use
    an extra unsigned char. 1 byte saved is
    precious for me. Thanks for the suggestion
    of using cast!

    One User

  • I have never heard of "bit index to array" and thus have no idea if it is even legal. Have you tried

    printf("UnIntArr[(unsigned char)uch]

    It should be worth a try

    Erik

  • As a bit can only index one of two values, could you use an if or - if you can handle it - a conditional expression?
    eg,

    x = array[ b ? 1 : 0 ];
    I'll leave you to look at the generated assembler to see if that has any advantage over the cast...