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

Array indexing with unsigned int

C251 v3.12

The C251 compiler does not handle arithmetic for array indices consistently. Consider

char tt[30] ;
char test ;
unsigned char aaa = 27 ;
unsigned int  bbb = 27 ;

test = tt[aaa - 20] ;
test = tt[bbb - 20] ;
The assembly code for the index using the unsigned char (aaa) has "-20" in its address construction. The assembly code for the index using the unsigned int (bbb) has "+65576" in its address construction. OOPS!
With the 8051's 16-bit address, this is no problem, but when using far addressing on the 251 you end up in different memory banks. int and char index variables work correctly like the unsigned char.

  • Joel,

    I got the following:

    stmt  level    source
    
        1          char tt[30] ;
        2          char test ;
        3          unsigned char aaa = 27 ;
        4          unsigned int  bbb = 27 ;
        5          
        6          void main (void)
        7          {
        8   1      
        9   1      test = tt[aaa - 20] ;
       10   1      test = tt[bbb - 20] ;
       11   1      
       12   1      
       13   1      }
       14          
       15          
       16          
    ASSEMBLY LISTING OF GENERATED OBJECT CODE
    
    ;       FUNCTION main (BEGIN)
                                                 ; SOURCE LINE # 6
                                                 ; SOURCE LINE # 9
    000000 7E1100      R  MOV      R1,aaa
    000003 2E1000      R  ADD      R1,#LOW tt+236
    000006 A5E7           MOV      A,@R1         ; A=R11
    000008 F500        R  MOV      test,A        ; A=R11
                                                 ; SOURCE LINE # 10
    00000A 7E0500      R  MOV      WR0,bbb
    00000D 9E040014       SUB      WR0,#014H
    000011 2E1000      R  ADD      R1,#LOW tt
    000014 A5E7           MOV      A,@R1         ; A=R11
    000016 F500        R  MOV      test,A        ; A=R11
                                                 ; SOURCE LINE # 13
    000018 22             RET      
    ;       FUNCTION main (END)
    
    

    This looks about right to me. Can you give me a complete example showing the problem that you get?

    Thanks,
    Jon

  • Sorry for the long delay in responding. I forgot to check back right away and a month slipped by.
    My test was a little different in that I used local parameters. Note the code expansion for line #96 versus #97. This test was compiled with v3.20b. I used the following compiler options:
    CD SB DB XSMALL OT(3,SPEED)
    DF(PROCESSOR=251)

    ----------------------------------
    89 void main(void)
    90 {
    91 1 char tt[30];
    92 1 char test ;
    93 1 unsigned char aaa = 27 ;
    94 1 unsigned int bbb = 27 ;
    95 1
    96 1 test = tt[aaa - 20] ;
    97 1 test = tt[bbb - 20] ;
    98 1 }

    ------------------------------------
    ; FUNCTION main (BEGIN)
    ; SOURCE LINE # 89
    ; SOURCE LINE # 90
    ; SOURCE LINE # 93
    000000 7E701B MOV R7,#01BH
    ;---- Variable 'aaa' assigned to Register 'R7' ----
    ; SOURCE LINE # 94
    000003 7E24001B MOV WR4,#01BH
    ;---- Variable 'bbb' assigned to Register 'WR4' ----
    ; SOURCE LINE # 96
    000007 0A37 MOVZ WR6,R7
    000009 09730000 R MOV R7,@WR6+tt-20
    ;---- Variable 'test' assigned to Register 'R7' ----
    ; SOURCE LINE # 97
    00000D 09720000 R MOV R7,@WR4+tt+65516
    ; SOURCE LINE # 98
    000011 22 RET
    ; FUNCTION main (END)
    --------------------------------
    Joel

  • Joel, -20 and 65516 translate into the same 16-bit hex value 0xFFEC. So the offset is in both cases identical. I agree that the listing might be a little clearer, but the code seems correct to me.

  • -20 and 65516 do not translate into the same 24-bit hex value! This is the 251 with 24-bit addressing. I got entirely different behavior in my indexed addressing between the two forms because they weren't looking at the same memory space (e.g. 00 space versus 01 space).

    Joel

  • -20 and 65516 do not translate into the same 24-bit hex value!

    You are right. But that is not important. The move is using a WORD register (16-bits) and not a DOUBLE register.

    If you look at the 2 instructions:

    MOV R7,@WR6+tt-20
    MOV R7,@WR4+tt+65516
    

    you will see that these are forms of the

    MOV Rm, @WRj + dis16
    

    instruction. This instruction is described in the Intel 251 User's Guide. Its encoding matches the example exactly. The '+dis16' is a 16-bit displacement--not a 24-bit displacement.

    The offset of tt is resolved by the linker and is added to 65516 or to -20. Either way, the result is the same.

    When I debug this program, the 2 instructions appear as follows in my debugger:

    0xFF0022   0973FFEC      MOV     R7,@WR6+0xFFEC
    0xFF0026   0972FFEC      MOV     R7,@WR4+0xFFEC
    

    This is the 251 with 24-bit addressing. I got entirely different behavior in my indexed addressing between the two forms because they weren't looking at the same memory space (e.g. 00 space versus 01 space).

    Hmmmm. How are you testing this example? If the 2 instructions listed above do not reference the same memory location, then...

    A) WR4 and WR6 do not contain the same value.

    B) The 16-bit offset is getting corrupted between the time it loads and the time it executes? Are you running from RAM?

    C) An interrupt is occurring that corrupts WR4 or WR6.

    D) The chip you have is not a fully-functional 251.

    Maybe there is some other problem that is not related to the compiler?

    Jon

  • Thanks for discussion. I'll take another look at what happened in the first place.

    By the way, I've been checking if other old bugs were fixed in C251 v3.20b.
    1. The need to explicitly use using 0 in main() is gone.
    2. An old bug in v2 I posted over a year ago (before you remodeled your discussion forum) about using sbit and _at_ together is fixed. Since I had a work-around, I never checked back on it until now.

    Thanks. Joel

  • 1. The need to explicitly use using 0 in main() is gone.

    I've never heard of this problem. Register bank 0 is selected by default. Why did you need to specify it in your application?

    Jon

  • I finally had some time to look at the array indexing problem. There are a lot details that may or not be relevant. My program ROM and hardware memory map reside in 0xFF space. My system RAM is in 0x00 space.

    typedef unsigned char BYTE ;
    typedef unsigned int  WORD ;
    typedef struct {
      BYTE dac;
      BYTE x1;
      BYTE roll;
      BYTE x2;
    } ASIC_AGS ;
    enum {
      DCA_LEL_WRDAC=1,
      DCA_LEH_WRDAC,
      DET_BIAS_WRDAC,
      AGS_DAC_1_WRDAC=24,
      AGS_ECHO_WRDAC=40,
      LASER_WRDAC,
      END_LIST_WRDAC
    } ;
    
    export volatile ASIC_AGS far asic_ags[16] _at_ 0xFFFFA0 ;
    
    void local_func(WORD dacID, WORD dacVal)
    {
      BYTE ch ;
      BYTE far * tempointer1 ;
      BYTE far * tempointer2 ;
    
      if((dacID<AGS_DAC_1_WRDAC)||(dacID>AGS_ECHO_WRDAC))
      { /* Do something else */ }
    
      /* case 1 */
      asic_ags[dacID - AGS_DAC_1_WRDAC] = (BYTE)dacVal ;
      tempointer1 = (BYTE far *)(&asic_ags[dacID - AGS_DAC_1_WRDAC].dac) ;
    
      /* case 2 */
      ch = dacID - AGS_DAC_1_WRDAC ;
      asic_ags[ch] = (BYTE)dacVal ;
      tempointer2 = (BYTE far *)(&asic_ags[ch].dac) ;
    
      /* print to system debug port */
      sprintf(msg,"t1 = %lX, t2 = %lX", tempointer1, tempointer2);
      debug_msg(msg);
    }
    
    My printout is:
    t1 = 100FFA0, t2 = FFFFA0
    And in both cases, the value ends up where address points: case 2 goes to my DAC, but case 1 ends up in system RAM (0xFFA0)!

    Assembly listing:
    ; case 1
      mov  wr6,wr14
      sll  wr6
      sll  wr6
      mov  wr14,#WORD0 asic_ags+65440
      mov  wr12 #WORD2 asic_ags+65440
      add  wr14,wr6
    ;--- 'tempointer1' assigned to Reg DR12 ---
    
    ; case 2
      mov  r10,ch
      mov  a,#4
      mul  ab
      mov  wr2,#WORD0 asic_ags
      mov  wr0,#WORD2 asic_ags
      add  wr2,wr10
      mov  tempointer2,dr0
    


    -------------------------------
    Regarding the using 0 problem. When I first installed v3.12, I started getting bizarre behavior when making simple changes to my code. I looked in the linker (v3.14) file and found variables assigned to locations 0 to 7 (bank 0). Rearranging variable defintions made the linker put different variables in bank 0 and the bizarre behavior would change. Only by explicitly adding using 0 to the main definition did the linker stop assigning variables to bank 0.

    I just went back and tried v3.12 again and commented out the using 0 from the main definition and the linker did its old trick of assigning variables to bank 0. The linker in v3.20 doesn't do this.

    Joel