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