Date: Mon, 30 Jun 2008 13:14:12 +0200
To: address@hidden
From: Dusan Ferbas <address@hidden>
Cc: Andy H <address@hidden>
Subject: [avr-gcc-list] eicall & EIND
Hi guys,
we have 2 issues with eicall instruction on ATmega2561 platform.
1st is, that a call to a constant bootloader (BL) location is
compiled with eicall instruction without setting EIND register.
2nd is, that in BL area, indexed call /that is compiled with
eicall/ seems not to work, when used from application area.
We tried both WinAVR-20071221 and WinAVR-20080610.
I noticed, that even on ATmega128, call was compiled with all
unused PC bits set to 1.
Does it mean, that we should set all "1"s in EIND ?
ad 1) same c code works on ATmega128
ATmega128 way:
-------------------------
typedef int boot_loader_send(unsigned char *, unsigned char *,
short);
#define boot_loader_data_send ((boot_loader_send*) 0x3F80A)
...
rslt = boot_loader_data_send(workbuf, buf, len);
(compiled with simple call)
2561 solution
------------------
- code for 128 generates eicall
- using a static inline wrap function with asm call
- it is optimized (arguments are not used, so they are not
prepared in registers)
- preparing registers in a "called" rtn did not work
(however i believe that is nearly the same as a next working case)
- finally we created a rtn in an external .c module (see code with
asm jmp below)
-> anyone knows an easier way ?
ad 2) works from BL area, does not from an application
following is called both from BL when XMODEM is used over a UART
and also from an application
it works from BL, but does not, when called from an application
- when indexed call was replaced with a list of calls in
switch-case, it works (but we do not fit in BL area :-) )
init
BootInfoHeader->fn[0] = FlashPage;
BootInfoHeader->fn[1] = EEprom_write_page;
call
unsigned char eind_local = EIND;
EIND = 0x3F800 >> (16 + 1); //highest bit of LoadAddr (for
ATmega2561 == 1, because in words)
BootInfoHeader->fn[section_id](address, (unsigned short *)
p_received_data, pagesize);
EIND = eind_local;
code for ad 1) case
-------------------------------
int boot_loader_data_send(unsigned char *p_WorkBuffer, unsigned
char *received_data_p, unsigned short data_length)
{
p_WorkBuffer = p_WorkBuffer;
received_data_p = received_data_p;
data_length = data_length;
// int rslt;
// asm volatile ( "movw r20,%3" "\n\t"
// "movw r22,%2" "\n\t"
// "movw r24,%1" "\n\t"
// "call 0x3F00A" "\n\t"
// "movw %0,r24" :
// "=r" (rslt) :
// "r" (p_WorkBuffer),
// "r" (received_data_p),
// "r" (data_length));
asm volatile ("jmp 0x3F00A");
// return rslt;
}
======================================
At 02:27 4.6.2008, Andy H wrote:
I cant answer your question fully. ...
Anatoly is adding support for 256 on version gcc 4.3 and gcc 4.4.
He or Eric may provide you a better way to do call. (Even if it
needs asm /macro wrapper)
Dusan Ferbas wrote:
Hi,
I am using WinAVR-20071221, because none of the most recent
toolchains produces a runnable code for our application.
Our bootloader starts at 0x3f800 (2kB).
In its code, we are using function[id](...) construction.
This is compiled with eicall instruction, but no EIND register
is set.
Is there a way, how to tell the compiler, that code is linked in
upper half of flash ?
In bootloader code we can live with EIND=1 at its init.
But when we have a call from our application, neither EIND is
set, even address is not divided by 2 (WinAVR bug #1959227).
Probably some far attribute should be applied ?
When compiled for ATmega128 (with 0x1f806), it works ...
typedef void boot_loader_init(unsigned char *);
#define boot_loader_data_init ((boot_loader_init *)
0x3F806)
...
boot_loader_data_init(buffer);
...
Dusan