The AT90USB1287 and ATmega2561 push/pop 3 byte PC's with call/ret and reti.  
However, function pointers on these parts seem to be 2 bytes.

Compiling the following:

typedef void (*FPTR_T)(void);

const unsigned char sizeof_fptr_t = sizeof(FPTR_T);

Yields the following assembly for both the AT90USB1287 and ATmega2561:

sizeof_fptr:
        .byte   2

Now I know that the USB1287 only has 128K, so it doesn't need a 3 byte PC, but 
the mega2561 could need it.

In my specific case, I discovered the problem when trying to get uC/OS-II to 
run.  I'm using the port on the Micrium website, and in OSTaskStkInit (in 
os_cpu_c.c) it does:

OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, 
INT16U opt)
{
    INT8U  *stk;
    INT16U  tmp;

    opt     = opt;            /* 'opt' is not used, prevent warning  */
    stk     = (INT8U *)ptos;  /* AVR return stack ("hardware stack") */
    tmp     = (INT16U)task;

    /* "push" initial register values onto the stack */
    *stk-- = (INT8U)tmp;        /* Put task start address on top of stack */
    *stk-- = (INT8U)(tmp >> 8);


Of course this then fails later when using the ret to pop the return address.  
So I modified it to do:

    tmp     = (INT32U)task;

    /* "push" initial register values onto the stack */
    *stk-- = (INT8U)tmp;        /* Put task start address on top of stack */
    *stk-- = (INT8U)(tmp >> 8);
    *stk-- = (INT8U)(tmp >> 16);

And, voila!  uC/OS starts running fine.

However, it works because all of my task entry points are in the bottom of 
flash.  If a task entry point were to live beyond the bottom 64K words, it 
wouldn't.  Even doing something like this would not work:

void foo()
{
  extern void task(void *);

  uint32_t addr;

  addr = (uint32_t)task;
}

Yields the following assembly to set addr:

        ldi r24,lo8(gs(task))
        ldi r25,hi8(gs(task))

Which still is only a 16-bit pointer.

So, how does one get a pointer to a function deep in flash?  I've spent a 
considerable amount of time today searching for information on this, and all I 
can find is in the AVR LIBC documentation:

char is 8 bits, int is 16 bits, long is 32 bits, long long is 64 bits, float 
and double are 32 bits (this is the only supported floating point format), 
pointers are 16 bits (function pointers are word addresses, to allow addressing 
the whole 128K program memory space on the ATmega devices with > 64 KB of flash 
ROM).

But they apparently aren't words, but half-words.  Am I missing something here? 
 Is there a switch I am missing?

Thanks for your help,
Pete
-- 
"To love for the sake of being loved is human;  to love for the sake of loving 
is Angelic."  -- Alphonse de Lamartine
_______________________________________________
AVR-GCC-list mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/avr-gcc-list

Reply via email to