avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [avr-gcc-list] eicall on ATmega2561


From: Dusan Ferbas
Subject: RE: [avr-gcc-list] eicall on ATmega2561
Date: Fri, 08 Aug 2008 10:31:24 +0200

Hi Stu,

we always work in a way functionality 1st :-).
Problem was, that local variables should be used as arguments for asm.
I missed that, when we tried several approaches. Also r18, r19 were put into clobber list. This helped too.
But now, it seems to me, that we are now at a point, when code was generated by compiler :-).
So I should check, where is the difference.

Anyhow, it works when fn is called from bootloader, but fails when called from application.
Probably I should check application startup code.

If we replace eicall (fn pointers in array) with switch case, it works. This made me think, whether eicall works as we expect.
You are right with EIND, but realize, that current compiler generates eicall, but do not care about EIND.
This requires, to put all functions, that are targeted with eicall-s, in .lowtext* sections.
To work with optimization, we ned to assign each such a function to a different section.
So minimally, you need to set EIND back to 0 on return.

Our scenario is simpler - we call only 1 entry point in bootloader (BL), which then decides which fn to call according to data content.
Our 1st assumption was just to set EIND=1.
When we replace eicall with switch case construction, things are better with SAME application code.

from "main"
  upload_valid = boot_loader_data_send(workbuf, buf, len);

bldr.c
- stub
- with ATmega128, this was only a macro
- cannot be done as an inline fn, compiler optimizes code and does not fill arguments into regs (maube atribute used should be applied)
int boot_loader_data_send(unsigned char *p_WorkBuffer, unsigned char *received_data_p, unsigned short data_length)
{
        asm volatile ("jmp 0x3F00A");

        return 0;                //prevent compiler warning, never goes this way
}

in BL
        asm volatile ("clr       __zero_reg__");
        cli();
        asm volatile ("rjmp next");
        asm volatile ("jmp boot_loader_data_init");
        asm volatile ("jmp boot_loader_data_send");              //fixed "API" @ 0x3F00A
...
int boot_loader_data_send(unsigned  char *p_WorkBuffer, unsigned  char *received_data_p, unsigned short data_length)
...
BootInfoHeader->fn[BootInfoHeader->SectionID](BootInfoHeader->address, (unsigned short *)received_data_p, BootInfoHeader->pagesize);
(this we substituted with code below)

More detailed
Finally we succeded. Problem was, that we forgot to put new local vars as args for asm. Then compiler did optimization.
When we start bootloader, it now properly uploads from a serial port.
But when we call from application, it still does not work.

Any plans to support 24 bit function pointers ? Otherwise we have to fiddle with ld script to made a correct order of modules. eicall is generated, so all called fns should reside in lower flash.

  register unsigned short call_address asm ("r30");
  register unsigned short address asm ("r24");
  register unsigned short *p_data asm ("r22");
  register unsigned short pagesize asm ("r20");
  address = BootInfoHeader->address;
  p_data = (unsigned short *)received_data_p;
  pagesize = BootInfoHeader->pagesize;
  call_address = (unsigned short)BootInfoHeader->fn[BootInfoHeader->SectionID];
 
  unsigned char eind_local;
  eind_local = EIND;
  EIND = 0x3F800 >> (16 + 1); //highest bit of call_address (for ATmega2561 == 1, because in words)

//  BootInfoHeader->fn[BootInfoHeader->SectionID](BootInfoHeader->address, (unsigned short *)received_data_p, BootInfoHeader->pagesize);
  asm volatile ( 
    ";movw r30,%3" "\n\t"  //R30:31 is already seeded with call_address
    ";movw r20,%0" "\n\t"  //load args
    ";movw r22,%1" "\n\t"
    ";movw r24,%2" "\n\t"
    "eicall" "\n\t"
    ::
    "r" (pagesize),  //(BootInfoHeader->pagesize),
    "r" (p_data),    //(received_data_p),
    "r" (address),   //(BootInfoHeader->address),
    "r" (call_address)
    : "r18", "r19"   //neither fn destroys r26,r27
    );
 
  EIND = eind_local;
At 00:04 8.8.2008, Stu Bell wrote:
*sigh*  Okay, now you're forcing me to work. ;-)

I'll start with EIND.  The return value is a bit of a "red herring" as
it doesn't really have much to do with the problem but is instead an
artifact of how you are trying to solve the problem.  EIND is used in
only two instructions: EIJMP and EICALL.  You don't really care what the
value is after you return from the EICALL, since you will need to set it
up next time for your *next* EICALL.  Same argument for EIJMP.  In other
words, stop obsessing about EIND.  So long as it is set to 1 before you
call the bootloader function from app space, you're golden.
 
Second, stop assigning C variables to registers.  It doesn't really
improve anything and, as you found out, makes your life miserable.  If
you think it makes faster code, I counter with the mantra, "*FIRST* make
it work, *THEN* make it fast".  You have yet to make it *work*, so you
don't pass step one of the mantra.
 
By the way, the "register" keyword is considered a hint by GCC, and
barely that.  GCC tends to ignore you, but then pays heed at the most
inopportune time.  Especially do not consider the register keyword to
apply across separate compile modules.

Dusan


reply via email to

[Prev in Thread] Current Thread [Next in Thread]