• AVR Freaks

Hot!Long var return from near and far functions.

Author
markQ
Junior Member
  • Total Posts : 85
  • Reward points : 0
  • Joined: 2013/09/24 07:53:59
  • Location: 0
  • Status: offline
2019/07/04 02:58:28 (permalink)
0

Long var return from near and far functions.

I observed a weird effect when I was calling the TickGet function in the Ethernet stack code where it was returning corrupted values. It should return a 32 bit unsigined tick value but I found that the upper 16 bits were being sign extened from bit 15.
e.g
Value to return 0x12345678 is returned as 0x00005678
however return 0x12348765 is returned as 0xFFFF8765
 
I then determined after quite a bit of experiment that this effect seemed to dependent on the proximimity of the calling function from the "serving" function.
To show this I have constucted two simarly functions one placed near the original TickGet function and the other just above the the main loop that calls it.
// shared header defines
#define LOW_WORD_HI_BIT_SET 0x128456
#define LOW_WORD_HI_BIT_CLEAR 0x123456
 
// function placed in tick.c
uint32_t GetLongFar(void) // placed in tick.c
{
    static uint32_t var = LOW_WORD_HI_BIT_SET;
    if(var == LOW_WORD_HI_BIT_SET)
        var = LOW_WORD_HI_BIT_CLEAR;
    else
        var = LOW_WORD_HI_BIT_SET;
    return var;
}
// function placed in main loop
uint32_t GetLongClose(void)
{
    static uint32_t var = LOW_WORD_HI_BIT_SET;
    if(var == LOW_WORD_HI_BIT_SET)
        var = LOW_WORD_HI_BIT_CLEAR;
    else
        var = LOW_WORD_HI_BIT_SET;
    return var;
}
 
// main loop code

        printf("\nnear-0x%08lx ",(uint32_t)GetLongClose());
        printf(" far-0x%08lx",(uint32_t)GetLongFar());
 
Resulting output
near-0x00128456  far-0xffff8456                                                 
near-0x00123456  far-0x00003456                                                 
near-0x00128456  far-0xffff8456                                                 
near-0x00123456  far-0x00003456                                                 
near-0x00128456  far-0xffff8456                                                 
near-0x00123456  far-0x00003456                                                 
near-0x00128456  far-0xffff8456                                                 
near-0x00123456  far-0x00003456                                                 
near-0x00128456  far-0xffff8456                                                 
near-0x00123456  far-0x00003456                                                 
near-0x00128456  far-0xffff8456                                                 
near-0x00123456  far-0x00003456                                                 
near-0x00128456  far-0xffff8456  


I guess this is a compiler bug or am I doing something stupied? So this Post may be in the wrong place, but I am targetting a PIC24. I appologise if it should be somewhere else.
 
I created a work around function to pass the value in a pointer,
// safe alternative
void TickGetByRef(uint32_t *tick)
{
    *tick = TickGet();
}
this works, but I am worried that the other stack code that uses TickGet may be working badly, even though they are closer in the image. But allot of them are used in defines so it is not easy to go round and replace them all.
 
Extra info:
Targetting PIC24FJ1256GB410
Compiler XC16 (v1.26)
Optimisation tried 0 1 and 2
Map showing the following positions of functions as...
0x00b172                  _GetLongClose
0x00b3be                  _main 
0x00c490                  _GetLongFar
 
oh and assembler for the calls.
 
0xB3FA: CLR W8
!    while (1)
!    {
!        
!     
!        printf("\nnear-0x%08lx ",(uint32_t)GetLongClose());
0xB400: MOV #0xAE33, W9
0xB402: MOV #0xAE42, W14
0xB404: RCALL GetLongClose
0xB406: MOV.D W0, [W15++]
0xB408: MOV W9, [W15++]
0xB40A: CALL __printf_cdnopuxX
0xB40C: NOP
!        printf(" far-0x%08lx",(uint32_t)GetLongFar());
0xB40E: CALL GetLongFar
0xB410: NOP
0xB412: ASR W0, #15, W1
0xB414: MOV.D W0, [W15++]
0xB416: MOV W14, [W15++]
0xB418: CALL __printf_cdnopuxX
0xB41A: NOP
................................................................
!uint32_t GetLongClose(void)
!{
!    static uint32_t var = LOW_WORD_HI_BIT_SET;
!    if(var == LOW_WORD_HI_BIT_SET)
0xB172: MOV #0x8456, W0
0xB174: MOV #0x12, W1
0xB176: MOV 0x1614, W2
0xB178: MOV 0x1616, W3
0xB17A: SUB W2, W0, [W15]
0xB17C: SUBB W3, W1, [W15]
0xB17E: BRA NZ, .L4
!        var = LOW_WORD_HI_BIT_CLEAR;
0xB180: MOV #0x3456, W0
0xB182: MOV #0x12, W1
0xB184: MOV W0, 0x1614
0xB186: MOV W1, 0x1616
0xB188: BRA .L5
!    else
!        var = LOW_WORD_HI_BIT_SET;
0xB18A: MOV #0x8456, W0
0xB18C: MOV #0x12, W1
0xB18E: MOV W0, 0x1614
0xB190: MOV W1, 0x1616
!    return var;
!}
0xB192: MOV 0x1614, W0
0xB194: MOV 0x1616, W1
0xB196: RETURN
............................................................
!uint32_t GetLongFar(void)
!{
!    static uint32_t var = LOW_WORD_HI_BIT_SET;
!    if(var == LOW_WORD_HI_BIT_SET)
0xC490: MOV #0x8456, W0
0xC492: MOV #0x12, W1
0xC494: MOV 0x15D8, W2
0xC496: MOV 0x15DA, W3
0xC498: SUB W2, W0, [W15]
0xC49A: SUBB W3, W1, [W15]
0xC49C: BRA NZ, .L10
!        var = LOW_WORD_HI_BIT_CLEAR;
0xC49E: MOV #0x3456, W0
0xC4A0: MOV #0x12, W1
0xC4A2: MOV W0, 0x15D8
0xC4A4: MOV W1, 0x15DA
0xC4A6: BRA .L11
!    else
!        var = LOW_WORD_HI_BIT_SET;
0xC4A8: MOV #0x8456, W0
0xC4AA: MOV #0x12, W1
0xC4AC: MOV W0, 0x15D8
0xC4AE: MOV W1, 0x15DA
!    return var;
!}
0xC4B0: MOV 0x15D8, W0
0xC4B2: MOV 0x15DA, W1
0xC4B4: RETURN


#1

8 Replies Related Threads

    NKurzman
    A Guy on the Net
    • Total Posts : 17604
    • Reward points : 0
    • Joined: 2008/01/16 19:33:48
    • Location: 0
    • Status: offline
    Re: Long var return from near and far functions. 2019/07/04 09:10:57 (permalink)
    3 (2)
    What compiler version are you using?
    What compiler version is recommend by you stack?
    #2
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11243
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: Long var return from near and far functions. 2019/07/04 09:50:11 (permalink)
    4.5 (2)
    These kinds of issues are often caused by missing prototypes.  But you're using a years-old version of the compiler; upgrade and see if it's fixed.
    #3
    Chris A
    Super Member
    • Total Posts : 834
    • Reward points : 0
    • Joined: 2010/07/20 04:37:07
    • Location: 0
    • Status: offline
    Re: Long var return from near and far functions. 2019/07/04 12:59:56 (permalink)
    5 (1)
    Yes I aggree, it looks like missing prototype as the extension is done in the calling funtion.  Do you have:
     
    extern uint32_t GetLongFar(void);

    in main or an included header before you call the function otherwise the compiler will treat the function as returning int and warn you about it!
    post edited by Chris A - 2019/07/04 13:01:33
    #4
    dan1138
    Super Member
    • Total Posts : 3166
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: Long var return from near and far functions. 2019/07/04 13:12:09 (permalink)
    5 (1)
    NKurzman
    What compiler version are you using?
    What compiler version is recommend by you stack?

    It's buried in the middle of post #1:
    markQ
    Extra info:
    Targetting PIC24FJ1256GB410
    Compiler XC16 (v1.26)
    Optimisation tried 0 1 and 2

    The disassembly shows that the printf(" far-0x%08lx",(uint32_t)GetLongFar()); thinks that GetLongFar() returns a signed 16-bit integer. It then is promoted to a signed 32-bit integer.
     
    This can be reproduced using this code:
    /*
     * File:   GetLongFar.c
     * Author: dan1138
     *
     * Created on July 4, 2019, 1:45 PM
     */
    #include <stdint.h>

    // shared header defines
    #define LOW_WORD_HI_BIT_SET 0x128456
    #define LOW_WORD_HI_BIT_CLEAR 0x123456
     
    // function placed in tick.c
    uint32_t GetLongFar(void) // placed in tick.c
    {
        static uint32_t var = LOW_WORD_HI_BIT_SET;
        if(var == LOW_WORD_HI_BIT_SET)
            var = LOW_WORD_HI_BIT_CLEAR;
        else
            var = LOW_WORD_HI_BIT_SET;
        return var;
    }

    /*
     * File:   main.c
     * Author: dan1138
     *
     * Created on July 4, 2019, 1:45 PM
     */
    #pragma config BWRP = OFF, BSS = OFF, BSEN = OFF, GWRP = OFF, GSS = OFF
    #pragma config CWRP = OFF, CSS = DIS, AIVTDIS = DISABLE, BSLIM = 0x1FFF
    #pragma config FNOSC = FRC, PLLMODE = DISABLED, IESO = OFF, POSCMOD = NONE
    #pragma config OSCIOFCN = ON, SOSCSEL = OFF, PLLSS = PLL_PRI, IOL1WAY = OFF
    #pragma config FCKSM = CSECMD, WDTPS = PS32768, FWPSA = PR128, FWDTEN = OFF
    #pragma config WINDIS = OFF, WDTWIN = PS25_0, WDTCMX = WDTCLK, WDTCLK = LPRC
    #pragma config BOREN = OFF, LPCFG = OFF, ICS = PGx1, JTAGEN = OFF, BTSWP = OFF
    #pragma config DSWDTPS = DSWDTPS1F, DSWDTOSC = LPRC, DSBOREN = ON
    #pragma config DSWDTEN = ON, DSSWEN = ON, ALTCMPI = DISABLE, TMPRPIN = OFF
    #pragma config TMPRWIPE = OFF, ALTVREF = ALTVREFDIS

    #include <stdio.h>
    #include <stdint.h>
    #include <string.h>
    #include "xc.h"

    // shared header defines
    #define LOW_WORD_HI_BIT_SET 0x128456
    #define LOW_WORD_HI_BIT_CLEAR 0x123456

    // function placed in main loop
    uint32_t GetLongClose(void)
    {
        static uint32_t var = LOW_WORD_HI_BIT_SET;
        if(var == LOW_WORD_HI_BIT_SET)
            var = LOW_WORD_HI_BIT_CLEAR;
        else
            var = LOW_WORD_HI_BIT_SET;
        return var;
    }

    extern uint32_t GetLongFar(void);

    char buffer[80];

    int main(void)
    {
        char *pBuf;
        for(;;)
        {
            memset(buffer,0,sizeof(buffer));
            pBuf = buffer;
            pBuf += sprintf(pBuf,"\nnear-0x%08lx ",(uint32_t)GetLongClose());
            pBuf += sprintf(pBuf," far-0x%08lx",(uint32_t)GetLongFar());
        }
        return 0;
    }

    When the statement extern uint32_t GetLongFar(void); is commented out this code fails as described by the Original Poster.
    post edited by dan1138 - 2019/07/04 19:54:08

    Attached Image(s)

    #5
    markQ
    Junior Member
    • Total Posts : 85
    • Reward points : 0
    • Joined: 2013/09/24 07:53:59
    • Location: 0
    • Status: offline
    Re: Long var return from near and far functions. 2019/07/05 03:23:44 (permalink)
    0
    Hi Dan1138
    Well done THANKS!! My "school boy" error was not to include the the prototype ( Thanks Jtemples and Chris A !), which miss-lead the compiler for the caller object. Interestingly my compiler/linker did not warn me, which it should, but I suppose because it links after the compiles it is difficult to detect.
    This would have been true of my original call to TickGet.
    All solved, Cheers.
    Feeling a little foolish, Q
    #6
    markQ
    Junior Member
    • Total Posts : 85
    • Reward points : 0
    • Joined: 2013/09/24 07:53:59
    • Location: 0
    • Status: offline
    Re: Long var return from near and far functions. 2019/07/05 03:37:47 (permalink)
    0
    BTW does anyone know of an tool that can analyse,detect and warn of errors like these?
     
    #7
    Chris A
    Super Member
    • Total Posts : 834
    • Reward points : 0
    • Joined: 2010/07/20 04:37:07
    • Location: 0
    • Status: offline
    Re: Long var return from near and far functions. 2019/07/05 04:17:00 (permalink)
    5 (1)
    It happens to us all!
     
    You should get
    main.c:53: warning: implicit declaration of function 'TickGet'

    Maybe you do not have all the compiler warning enabled.
     
    post edited by Chris A - 2019/07/05 04:18:42
    #8
    markQ
    Junior Member
    • Total Posts : 85
    • Reward points : 0
    • Joined: 2013/09/24 07:53:59
    • Location: 0
    • Status: offline
    Re: Long var return from near and far functions. 2019/07/05 05:47:24 (permalink)
    0
    Are yes, I somehow disabled the "Additional warnings" in "the Preprocessing andf messages" properties of the gcc.
    That bought it back to the compile and to my memory.
    Cheers
    #9
    Jump to:
    © 2019 APG vNext Commercial Version 4.5