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


Reply via email to