Browsing the GCC source, I found this in gcc/config/avr/avr.c
if (AVR_HAVE_RAMPZ
&& TEST_HARD_REG_BIT (set, REG_Z)
&& TEST_HARD_REG_BIT (set, REG_Z + 1))
{
emit_push_sfr (rampz_rtx, false /* frame */, AVR_HAVE_RAMPD,
treg);
}
I wont pretend to fully understand this part of the compiler, but that
AVR_HAVE_RAMPD looks shady to me?
Anyone with deeper knowledge want to have a look?
-Ian
Hi Ian, the code is as intended:
It's during ISR prologue where we determine whether RAMPZ has to be
saved / restored. Conditions are that:
1) RAMPZ exists and
2) Z register is used.
The call to emit_push_sfr() to push RAMPZ has argument clr_p =
HAVE_RAMPD (sic!) because we have two cases when RAMPZ might occur:
A) The hardware has RAMPZ but none of the other RAMP* registers. This
is the case on devices with more than 64 KiB of flash and with RAM less
than 64 KiB. RAMPZ is only used to augment ELPM. The rule is that any
insn may use and clobber RAMPZ as needed *without* the requirement to
restore the previous value.
B) The hardware has more than 64 KiB of RAM and all RAMP registers are
present. The convention is that all RAMP* registers contain a value of
zero. If an insn clobbers RAMP*, it has to restore its value.
Consequently, upon entering an ISR, some RAMPZ might be non-zero, but
the compiler expects all RAMP registers to contain zero.
As both cases A) and B) have RAMPZ, AVR_HAVE_RAMPZ cannot be used to
discriminate these cases, but AVR_HAVE_RAMPD *does* discriminate.
There are similar use cases of AVR_HAVE_RAMPD in the startup code or
after using ELPM, for example at the end of avr.cc::avr_out_lpm():
if (xop[4] == xstring_e && AVR_HAVE_RAMPD)
{
/* Reset RAMPZ to 0 so that EBI devices don't read garbage from
RAM. */
xop[0] = zero_reg_rtx;
avr_asm_len ("out %i6,%0", xop, plen, 1);
}
xop[6] is RAMPZ, and xop[4] == xstring_e if ELPM was used.
Johann