AVR indirect_jump addresses limited to 16 bits

2005-03-19 Thread Marek Michalkiewicz
Hello,

I'm looking into adding support for ATmega256x and larger devices to
the AVR port.  This means that program memory addresses no longer fit
in 16 bits - and I'm looking how to avoid making pointers larger.

Jumps and function calls are no problem as long as they use labels
(constant addresses).  Indirect jumps and calls (address in a register)
are a problem.  For function calls, it seems easy - generate each
function in two parts, placed by linker script in different sections:

 - jump to function body
 - function body

and locate the jumps below 128K (64K words), while the function body
can be anywhere in the address space.  If you need to take a 16-bit
address of the function, simply take the address of the jump.  The
added runtime overhead of the jump is a small price to pay compared
to making pointers 3 or 4 bytes long (instead of 2 bytes) on the AVR.

But, now there is the "indirect_jump" pattern - mandatory, even though
I haven't yet seen it actually used in real applications on the AVR.
The question is, how to make sure that if indirect_jump ever happens
to be used, its target address is guaranteed to fit in 16 bits?  Where
do these pointers come from?  (Like function pointers come from taking
the address of a function, and this may be solved as described above.)

Looking at the source, I've found one use of indirect_jump so far -
returning from a function with some data still on the stack.
I suspect this may not work properly on the AVR anyway, because
return address is stored on the stack in the wrong byte order -
big endian, even though the AVR is little endian.  Anything else?

Thanks,
Marek



Re: AVR indirect_jump addresses limited to 16 bits

2005-03-19 Thread Marek Michalkiewicz
On Sat, Mar 19, 2005 at 01:51:05PM -0500, Paul Schlie wrote:

> - Fully agree, just can't keep from wondering if this may be most
>   efficiency accomplish by simply requiring the alignment of all
>   function entry points to be two instruction word aligned. Thereby

This only doubles the available address space, and I'd rather not do
it all again (this time with 4-word alignment) if 512K chips appear.
Supporting the maximum possible address space on the AVR would require
64-word function alignment, and shifting the word address by 6.

But function entry points are not the only problem - indirect jumps are
another (as you can see in the subject of my message), they can point
somewhere within a function (so function alignment may not help here).
On the other hand, indirect_jump is rarely seen, so it must be correct
but doesn't have to be very efficient (OK if it costs even a few more
instructions to stay in the low 64K words).

So, I'm trying to figure out when the indirect_jump pattern can actually
be generated on the AVR (haven't yet seen it in any real application),
and where does the pointer comes from (to see if the jump target can be
moved to the low 64K words somehow).

Marek


Re: AVR indirect_jump addresses limited to 16 bits

2005-03-19 Thread Marek Michalkiewicz
On Sat, Mar 19, 2005 at 04:38:28PM -0500, Paul Schlie wrote:

> - understood, however unlikely; observing it will likely take Atmel at
>   least 2-3 years to stabilize production of the 256K devices, and larger
>   device volume potential vs. competitive offerings couldn't likely justify
>   their development (as just an opinion).

I thought the same about 128K devices, and then 256K devices appeared :)

> - Sorry, I'm confused; can you give me an example of legal C expression
>   specifying an indirect jump to an arbitrary location within a function?

Good question - I can't.  On the other hand, the manual says:

`indirect_jump'
An instruction to jump to an address which is operand zero.  *This pattern
name is mandatory on all machines.*

Why would it be mandatory if it was not truly needed?  If the manual is
correct, it seems this pattern is truly needed (not just an optional
optimization like some other patterns).

If it is impossible on the AVR, it could be implemented with invalid
assembler output (so we get an error if "impossible" ever happens).
But I'd like to be sure if this is really the case.  GCC is not only
a C compiler, perhaps indirect_jump is needed for some other language?

Thanks,
Marek


Re: AVR indirect_jump addresses limited to 16 bits

2005-03-19 Thread Marek Michalkiewicz
On Sat, Mar 19, 2005 at 06:37:54PM -0500, Paul Schlie wrote:

> - or possibly GCC may try to be clever by jumping to no-return attribute
>   function calls?

Such "trying to be clever" would most likely be optional.
Again, why is indirect_jump _mandatory_ on all machines?

Please, don't try to be too clever :) - just look at the GCC source
and try to figure out exactly what is indirect_jump used for, and how
much of this (if anything) matters for the AVR port.

If the address of a label is loaded into a register, then we have to
switch to a different section around that label:

/* ... */
jmp label
.section .text_low,"ax",@progbits
label:
jmp 1f
.text
1:
/* ... */

then it will be safe to load the address of the label into a register,
no need to do anything with the highest bits as pm_hh8(label) == 0:

ldi r30,pm_lo8(label)
ldi r31,pm_hi8(label)
/* ... */
ijmp; PC <- 0:r31:r30

Note that this adds two jumps around the label, so we only want to
do it infrequently - if the address of the label is loaded into
a register (not if the only users of the label are direct jumps).

Thanks,
Marek


Re: AVR indirect_jump addresses limited to 16 bits

2005-03-20 Thread Marek Michalkiewicz
On Sun, Mar 20, 2005 at 02:58:29AM +0100, Giovanni Bajo wrote:

> It is possible in GNU C at least:
> 
> int foo(int dest)
> {
>__label__ l1, l2, l3;
>void *lb[] = { &&l1, &&l2, &&l3 };
>int x = 0;
> 
>goto *lb[dest];
> 
> l1:
>x += 1;
> l2:
>x += 1;
> l3:
>x += 1;
>return x;
> }

Thanks for explaining this.  So yes, unfortunately we have to support
indirect_jump properly (I was hoping it was only for something like
trampolines, which can't work on the AVR anyway).

I was wrong about needing two jumps - just one for each label should
be enough, because switching to .text_low and back to .text doesn't
disrupt the normal flow of instructions in .text.  So, it's not that
bad, really the same thing for indirect jumps and calls (using function
pointers), each affected label needs to be output like this:

.section .text_low,"ax",@progbits
label:
jmp 1f
.text
1:

This includes all global labels (visible to other object files, like
function entry points), and local labels referenced by anything other
than direct jumps or calls).

On the other hand, branches within the same function should avoid the
extra jump and go to "1:" directly.  If the same label is used in both
ways (direct jump/branch, and address taken), two separate labels (at
the same address) should be output for both of these uses, but I'm not
sure how to do this in GCC.  Any suggestions?

(The problem can be seen by adding something like "if (dest > 2) goto l3;"
above the goto in the original example: in the assembler output, there is
only one label corresponding to l3 which is both 1. referenced with pm()
and 2. target of a branch for which .text_low would be out of range.)

Marek



Re: AVR indirect_jump addresses limited to 16 bits

2005-03-21 Thread Marek Michalkiewicz
On Sun, Mar 20, 2005 at 04:29:01PM -0800, Richard Henderson wrote:

> The easiest way is to do this in the linker instead of the compiler.
> See the xstormy16 port and how it handles R_XSTORMY16_FPTR16.  This
> has the distinct advantage that you do not commit to the creation of
> an indirect jump until you discover that the target label is outside
> the low 64k.

Looks perfect to me.  So we are not the first architecture needing
such tricks...  AVR would need 3 new relocs, used like this:

.word pm16(label)

ldi r30,pm16_lo8(label)
ldi r31,pm16_hi8(label)

and the linker can do the rest of the magic (add jumps in a section
below 64K words if the label is above).

Cc: to Denis, as I may need help actually implementing these changes
(you know binutils internals much better than I do).

Thanks,
Marek