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

Locating 2 parameters at the same address

I am using an 8051 (C51/BL51) with no off-chip memory. I have two functions with parameters:

void Detect( U8 iLed )

and

static U8 INHSampleHandler( U16 u16Sample )


Now I understand that Keil will allocate a variable (in DATA) for these. The problem seems to be that the locator is using the same memory location for both. I cannot understand why.

Below are excerpts from the scratchpad showing 2 "D:0026H". These are the only places these symbols are declared. Any ideas what I'm doing wrong?

Thanks,
Jeff

BL51 BANKED LINKER/LOCATER V5.12              07/14/2011  09:36:23  PAGE 1


BL51 BANKED LINKER/LOCATER V5.12, INVOKED BY:
Z:\TOOLS\SOFTWARE\KEIL\BL51.EXE Z:\Software\FB_CPU_Init.obj,
>> Z:\Software\Settings.obj, Z:\Software\Glo
>> bals.obj, Z:\Software\Devices\Clock.obj, Z:\ 
>> Software\Devices\Flash.obj, Z:\Software\Devices\HMI.obj
>> , Z:\Software\Devices\INH.obj, Z:\ 
>> Software\Devices\ADC.obj, Z:\Software\Devices\Timer.obj, Z
>> :\Software\Builds\TestINH - 06-00039-21-09\Main.obj
>> , Z:\Software\Test\Test_Button.obj, Z:\So
>> ftware\Builds\TestINH - 06-00039-21-09\Version.obj TO Z:\ 
>> Software\Builds\TestINH - 06-00039-21-09\06-00039-21-09-xx.wsp
>>  RS (256) PL (68) PW (78) XDATA (?XD?SETTINGS (0X0)) CODE (?CO?VERSION (0X7
>> FC0))


MEMORY MODEL: SMALL

Deleted for brevity

  -------         PROC          _INHSAMPLEHANDLER
  D:0026H         SYMBOL        u16Sample
  C:0BF1H         LINE#         150
  C:0BF5H         LINE#         151
  C:0BF5H         LINE#         207
  C:0BF7H         LINE#         208
  -------         ENDPROC       _INHSAMPLEHANDLER
  -------         ENDMOD        INH

Deleted for brevity

  C:09FEH         PUBLIC        _Detect
  C:074EH         PUBLIC        main
  -------         PROC          _DETECT
  D:0026H         SYMBOL        iLed

  • I was trying to avoid lengthy code, but here is a concrete example that demonstrates my point.
    Here is the code:

    #include "compiler_defs.h"
    #include "C8051F930_defs.h"
    
    
    void Sub1( U8 SubVar1 )
    {
            SubVar1 = SubVar1 + 1;
    }
    
    void Sub2( U8 SubVar2 )
    {
            SubVar2 = SubVar2 + 1;
    }
    
    void main(void)
    {
            while(1)
            {
                    Sub1( 13 );
            }
    }
    
    
    static void ADC_ISR(void) interrupt 10
    {
            U16 u16Result = 12;
            Sub2( u16Result );
            ADC0CN &= ~0x20;
    }
    

    And here are excepts from map file:

    BL51 BANKED LINKER/LOCATER V5.12              07/14/2011  13:32:43  PAGE 1
    
    
    BL51 BANKED LINKER/LOCATER V5.12, INVOKED BY:
    Z:\TOOLS\SOFTWARE\KEIL\BL51.EXE C:\Users\JeffT\Documents\Temp\Main.obj TO C:\U
    >> sers\JeffT\Documents\Temp\Main RS (256) PL (68) PW (78)
    
    
    MEMORY MODEL: SMALL
    
      -------         PROC          _SUB1
      D:0007H         SYMBOL        SubVar1
      -------         ENDPROC       _SUB1
      -------         PROC          _SUB2
      D:0007H         SYMBOL        SubVar2
      -------         ENDPROC       _SUB2
    

    The linker builds its call tree and don't think the Sub2 and Sub1 overlap. But obviously they can. When the ISR fires Sub2 will overwrite Sub1's value. I can turn off the variable overlaying entirely, but that would be a waste. I suppose most people don't call functions from within ISRs. I have my reasons for doing so.

    Any ideas?

  • SubVar2 = SubVar2 + 1;
    

    changed that to:

    SubVar2 = 0;
    

    and

            SubVar1 = SubVar1 + 1;
    

    to

            SubVar1 = SubVar1 + 1; P2=SubVar1;
    

    so if subvar1/subvar2 are indeed overlaid, you will see that subvar1/subvar2/P2 maintains 13 and then periodically (as the isr 10 is fired) gets reset to 0.

    if the two variables are not overlaid, you will see P2 maintaining a value of 13.

    I tried to use tmr0 isr and I got a constant value on P2.

  • The trouble with your example is that neither function does anything - so the compiler generates no code for them:

    ASSEMBLY LISTING OF GENERATED OBJECT CODE
    
    
                 ; FUNCTION _Sub1 (BEGIN)
                                               ; SOURCE LINE # 6
    ;---- Variable 'SubVar1' assigned to Register 'R7' ----
                                               ; SOURCE LINE # 7
                                               ; SOURCE LINE # 8
                                               ; SOURCE LINE # 9
    0000 22                RET
                 ; FUNCTION _Sub1 (END)
    
                 ; FUNCTION _Sub2 (BEGIN)
                                               ; SOURCE LINE # 11
    ;---- Variable 'SubVar2' assigned to Register 'R7' ----
                                               ; SOURCE LINE # 12
                                               ; SOURCE LINE # 13
                                               ; SOURCE LINE # 14
    0000 22                RET
                 ; FUNCTION _Sub2 (END)
    
    

    We need a slightly more realistic example...

  • If I change the source code to:

    #include "c8051f9xx.h"
    
    typedef unsigned char U8;
    typedef unsigned int U16;
    
    void Sub1( volatile U8 SubVar1 )
    {
            SubVar1 = SubVar1 + 1;
    }
    
    void Sub2( volatile U8 SubVar2 )
    {
            SubVar2 = SubVar2 + 1;
    }
    
    void main(void)
    {
            while(1)
            {
                    Sub1( 13 );
            }
    }
    
    
    static void ADC_ISR(void) interrupt 10
    {
            U16 u16Result = 12;
            Sub2( u16Result );
            ADC0CN &= ~0x20;
    }
    


    The result is:

                 ; FUNCTION _Sub1 (BEGIN)
                                               ; SOURCE LINE # 6
    0000 8F00        R     MOV     SubVar1,R7
                                               ; SOURCE LINE # 7
                                               ; SOURCE LINE # 8
    0002 0500        R     INC     SubVar1
                                               ; SOURCE LINE # 9
    0004 22                RET
                 ; FUNCTION _Sub1 (END)
    
                 ; FUNCTION _Sub2 (BEGIN)
                                               ; SOURCE LINE # 11
    0000 8F00        R     MOV     SubVar2,R7
                                               ; SOURCE LINE # 12
                                               ; SOURCE LINE # 13
    0002 0500        R     INC     SubVar2
                                               ; SOURCE LINE # 14
    0004 22                RET
                 ; FUNCTION _Sub2 (END)
    


    And the map file says:

    -------         MODULE        OVERLAY
      C:0000H         SYMBOL        _ICE_DUMMY_
      D:00E8H         PUBLIC        ADC0CN
      D:00A8H         PUBLIC        IE
      C:0003H         SYMBOL        ADC_ISR
      D:00B8H         PUBLIC        IP
      C:0023H         PUBLIC        main
      D:0088H         PUBLIC        TCON
      C:002AH         PUBLIC        _Sub1
      C:002FH         PUBLIC        _Sub2
      D:0098H         PUBLIC        SCON0
      D:00D0H         PUBLIC        PSW
      -------         PROC          _SUB1
      D:0008H         SYMBOL        SubVar1
      C:002AH         LINE#         6
      C:002CH         LINE#         7
      C:002CH         LINE#         8
      C:002EH         LINE#         9
      -------         ENDPROC       _SUB1
      -------         PROC          _SUB2
      D:0009H         SYMBOL        SubVar2
      C:002FH         LINE#         11
      C:0031H         LINE#         12
      C:0031H         LINE#         13
      C:0033H         LINE#         14
      -------         ENDPROC       _SUB2
    
    

  • To use the keyword "volatile" was my first thought, and it worked for a while in my program. In this simplistic program it works as well. As I continued working with my code the problem got "unfixed".

    I think I've demonstrated the problem here and I'm not confident that this solution with "volatile" is at all guaranteed. I'd guess that we a bit afield of the ANSI standard it it's up to how Keil designed their optimization.

    I'll probably send this over to Keil technical support.

  • Another thing is to disable passing parameters in registers, and make sure that the functions do something:

    #pragma NOREGPARMS
    #include "c8051f9xx.h"
    
    typedef unsigned char U8;
    typedef unsigned int U16;
    
    U8 Sub1(  U8 SubVar1 )          // No 'volatile'
    {
            SubVar1 = SubVar1 + 1;
            return SubVar1;
    }
    
    U8 Sub2(  U8 SubVar2 )          // No 'volatile'
    {
            SubVar2 = SubVar2 + 1;
            return SubVar2;
    }
    
    
    void main(void)
    {
            while(1)
            {
                    Sub1( 13 );
            }
    }
    
    
    static void ADC_ISR(void) interrupt 10
    {
            U16 u16Result = 12;
            Sub2( u16Result );
            ADC0CN &= ~0x20;
    }
    

    Which then gives:

                 ; FUNCTION Sub1 (BEGIN)
                                               ; SOURCE LINE # 7
                                               ; SOURCE LINE # 8
                                               ; SOURCE LINE # 9
    0000 0500        R     INC     SubVar1
                                               ; SOURCE LINE # 10
    0002 AF00        R     MOV     R7,SubVar1
                                               ; SOURCE LINE # 11
    0004         ?C0001:
    0004 22                RET
                 ; FUNCTION Sub1 (END)
    
                 ; FUNCTION Sub2 (BEGIN)
                                               ; SOURCE LINE # 13
                                               ; SOURCE LINE # 14
                                               ; SOURCE LINE # 15
    0000 0500        R     INC     SubVar2
                                               ; SOURCE LINE # 16
    0002 AF00        R     MOV     R7,SubVar2
                                               ; SOURCE LINE # 17
    0004         ?C0002:
    0004 22                RET
                 ; FUNCTION Sub2 (END)
    

    and

    -------         MODULE        OVERLAY
      C:0000H         SYMBOL        _ICE_DUMMY_
      D:00E8H         PUBLIC        ADC0CN
      D:00A8H         PUBLIC        IE
      C:0003H         SYMBOL        ADC_ISR
      D:00B8H         PUBLIC        IP
      C:0024H         PUBLIC        main
      D:0088H         PUBLIC        TCON
      C:002CH         PUBLIC        Sub1
      C:0031H         PUBLIC        Sub2
      D:0098H         PUBLIC        SCON0
      D:00D0H         PUBLIC        PSW
      -------         PROC          SUB1
      D:0008H         SYMBOL        SubVar1
      C:002CH         LINE#         7
      C:002CH         LINE#         8
      C:002CH         LINE#         9
      C:002EH         LINE#         10
      C:0030H         LINE#         11
      -------         ENDPROC       SUB1
      -------         PROC          SUB2
      D:0009H         SYMBOL        SubVar2
      C:0031H         LINE#         13
      C:0031H         LINE#         14
      C:0031H         LINE#         15
      C:0033H         LINE#         16
      C:0035H         LINE#         17
      -------         ENDPROC       SUB2
    
    

  • "I think I've demonstrated the problem here"

    I am not as confident.

    I have tried to replicate your code, using a timer isr instead of your adc isr. Both variables are allocated at the same address.

    and I never observed them having the same value.

    so unless shown otherwise, I am going to agree with others that you are trying to solve a problem that doesn't exist.

  • No, I don't think that you have demonstrated it here.

    That may or may not mean that there is no problem - it might just be because the example presented here is over-simplified so that the problem doesn't arise.

    Probably worth a discussion with Keil support - likely to be easier to share a more substantial example with them...

  • I've tried to make my example more "complicated" but that darn optimizer is too smart. On the other hand my actual code is more than one swallow. I'll see if I can work up an example that actually fails.

  • Make sure your functions make use of the parameter, and have them write the parameter value to a volatile variable. Volatile variables are normally a good way to get the optimizer to stop removing code - you want to convince the compiler that there is an important side effect that must not be optimized away.

  • I've tried to make my example more "complicated" but that darn optimizer is too smart

    try optimize = 2. this is basically variable overlay and nothing else.

    to the homewrecker and the sardine: please not the word basically

    Erik

  • "please not the word basically"

    is it too much to ask that you write complete and comprehensible sentences, erik?

  • "I'll see if I can work up an example that actually fails."

    I have one that follows your basic structure but uses a tmr isr to trigger one of the subroutines.

    as andrew pointed out, you need to make sure that both subroutines actually operate on those two variables.

  • The linker builds its call tree and don't think the Sub2 and Sub1 overlap. But obviously they can.

    The problem is precisely that that is not at all obvious to the linker. Static call tree analysis pretty much always fails as soon as function pointers get involved, and deep down, it really has no chance --- there's an impossible task hiding in there, equivalent to the Halting Problem. Keil is no exception to that rule.

    So what you should do is: do not call functions via pointer from inside an ISR. Not on a '51, anyway. If at all possible, avoid calling any functios from a '51 ISR, period.

    If you really can't see any way of accomplishing that, see the app notes already referenced in this thread about ways to fudge the linker call tree data. And brace yourself, because this will hurt.

  • Hello,

    You are focusing in on the wrong section of the memory map. You need to view the "overlay analysis" section

    If the overlay analysis is incorrect, you can use the OVERLAY command to correct it:

    http://www.keil.com/support/man/docs/bl51/bl51_overlay.htm

    For example look at page 5 of this application note.

    http://www.keil.com/appnotes/docs/apnt_129.asp

    It explains exactly the issue you describe, a function called by a function pointer.

    Page 5 -6 show how to use the OVERLAY command to tell the linker that these functions are not independent. Once the linker is made aware of this, it will not overlay those variables.