arch/avr: save RAMPZ register into thread context

On chips that have it, RAMPZ is part of the thread context
and needs to be saved as well.
This commit is contained in:
Kerogit 2025-03-17 12:20:35 +01:00 committed by Xiang Xiao
parent 958b18f25e
commit 88a66f18e6
10 changed files with 96 additions and 10 deletions

View file

@ -81,7 +81,13 @@
# define NR_IRQS 34
# define AVR_PC_SIZE 16
# define XCPTCONTEXT_REGS 37 /* Size of the register state save array (in bytes) */
# define XCPTCONTEXT_REGS 38 /* Size of the register state save array (in bytes) */
# if defined(CONFIG_AVR_HAS_RAMPZ)
# define AVR_HAS_RAMPZ
# else
# error CONFIG_AVR_HAS_RAMPZ is supposed to be set for this chip
# endif
#elif defined(CONFIG_ARCH_CHIP_ATMEGA1284P)
@ -122,7 +128,13 @@
# define NR_IRQS 34
# define AVR_PC_SIZE 16
# define XCPTCONTEXT_REGS 37 /* Size of the register state save array (in bytes) */
# define XCPTCONTEXT_REGS 38 /* Size of the register state save array (in bytes) */
# if defined(CONFIG_AVR_HAS_RAMPZ)
# define AVR_HAS_RAMPZ
# else
# error CONFIG_AVR_HAS_RAMPZ is supposed to be set for this chip
# endif
#elif defined(CONFIG_ARCH_CHIP_ATMEGA2560)
@ -185,7 +197,13 @@
# define NR_IRQS 58
# define AVR_PC_SIZE 24
# define XCPTCONTEXT_REGS 38 /* Size of the register state save array (in bytes) */
# define XCPTCONTEXT_REGS 39 /* Size of the register state save array (in bytes) */
# if defined(CONFIG_AVR_HAS_RAMPZ)
# define AVR_HAS_RAMPZ
# else
# error CONFIG_AVR_HAS_RAMPZ is supposed to be set for this chip
# endif
#else
#error "Unrecognized chip"

View file

@ -72,16 +72,24 @@
#define REG_R2 29
#define REG_R1 30 /* r1 - the "zero" register */
#define REG_R0 31 /* r0 */
#define REG_SREG 32 /* Status register */
#define REG_R25 33 /* r24-r25 */
#define REG_R24 34
#if defined(AVR_HAS_RAMPZ)
# define REG_RAMPZ 32 /* RAMPZ register for ELPM instruction */
# define REG_OFFSET_RAMPZ 1
#else
# define REG_OFFSET_RAMPZ 0 /* MCU does not have RAMPZ */
#endif
#define REG_SREG (32 + REG_OFFSET_RAMPZ) /* Status register */
#define REG_R25 (33 + REG_OFFSET_RAMPZ) /* r24-r25 */
#define REG_R24 (34 + REG_OFFSET_RAMPZ)
/* The program counter is automatically pushed when the interrupt occurs */
#define REG_PC0 35 /* PC */
#define REG_PC1 36
#define REG_PC0 (35 + REG_OFFSET_RAMPZ) /* PC */
#define REG_PC1 (36 + REG_OFFSET_RAMPZ)
#if AVR_PC_SIZE > 16
# define REG_PC2 37
# define REG_PC2 (37 + REG_OFFSET_RAMPZ)
#endif
#define XCPTCONTEXT_SIZE XCPTCONTEXT_REGS
@ -107,6 +115,9 @@ struct xcptcontext
uint8_t saved_pc0;
#if defined(REG_PC2)
uint8_t saved_pc2;
#endif
#if defined(REG_RAMPZ)
uint8_t saved_rampz;
#endif
uint8_t saved_sreg;

View file

@ -12,16 +12,19 @@ choice
config ARCH_CHIP_ATMEGA128
bool "ATMega128"
select AVR_HAS_RAMPZ
---help---
Atmel ATMega128 8-bit AVR.
config ARCH_CHIP_ATMEGA1284P
bool "ATMega1284P"
select AVR_HAS_RAMPZ
---help---
Atmel ATMega1284P 8-bit AVR.
config ARCH_CHIP_ATMEGA2560
bool "ATMega2560"
select AVR_HAS_RAMPZ
---help---
Atmel ATMega2560 8-bit AVR.

View file

@ -48,7 +48,9 @@
* - If RAMPZ is not present, support for LPMX is assumed
*/
#define HAVE_RAMPZ 1
#ifdef AVR_HAS_RAMPZ
# define HAVE_RAMPZ 1
#endif
/****************************************************************************
* External Symbols

View file

@ -73,4 +73,8 @@ config AVR_HAS_MEMX_PTR
of RAM needed to hold this static data.
endmenu # Atmel AVR Toolchain options
config AVR_HAS_RAMPZ
bool
endif # ARCH_FAMILY_AVR

View file

@ -107,6 +107,12 @@ void up_initial_state(struct tcb_s *tcb)
xcp->regs[REG_PC2] = (uint8_t)((uintptr_t)tcb->start & 0xff);
#endif
/* Set RAMPZ to zero, the default value (if the MCU has one) */
#if defined(REG_RAMPZ)
xcp->regs[REG_RAMPZ] = 0;
#endif
/* Enable or disable interrupts, based on user configuration */
#ifdef CONFIG_SUPPRESS_INTERRUPTS

View file

@ -91,5 +91,10 @@ void up_dump_register(void *dumpregs)
regs[REG_PC2], regs[REG_SPH],
regs[REG_SPL], regs[REG_SREG]);
#endif
#if defined(REG_RAMPZ)
_alert("RAMPZ: %02x\n",
regs[REG_RAMPZ]);
#endif
}
}

View file

@ -126,6 +126,9 @@ void up_schedule_sigaction(struct tcb_s *tcb)
tcb->xcp.saved_pc1 = up_current_regs()[REG_PC1];
#if defined(REG_PC2)
tcb->xcp.saved_pc2 = up_current_regs()[REG_PC2];
#endif
#if defined(REG_RAMPZ)
tcb->xcp.saved_rampz = up_current_regs()[REG_RAMPZ];
#endif
tcb->xcp.saved_sreg = up_current_regs()[REG_SREG];
@ -168,6 +171,9 @@ void up_schedule_sigaction(struct tcb_s *tcb)
tcb->xcp.saved_pc1 = tcb->xcp.regs[REG_PC1];
#if defined(REG_PC2)
tcb->xcp.saved_pc2 = tcb->xcp.regs[REG_PC2];
#endif
#if defined(REG_RAMPZ)
tcb->xcp.saved_rampz = tcb->xcp.regs[REG_RAMPZ];
#endif
tcb->xcp.saved_sreg = tcb->xcp.regs[REG_SREG];

View file

@ -103,6 +103,9 @@ void avr_sigdeliver(void)
regs[REG_PC1] = rtcb->xcp.saved_pc1;
#if defined(REG_PC2)
regs[REG_PC2] = rtcb->xcp.saved_pc2;
#endif
#if defined(REG_RAMPZ)
regs[REG_RAMPZ] = rtcb->xcp.saved_rampz;
#endif
regs[REG_SREG] = rtcb->xcp.saved_sreg;

View file

@ -148,6 +148,13 @@
ori r25, (1 << SREG_I) /* Interrupts re-enabled on restore */
push r25
/* Save RAMPZ if the MCU has it */
#ifdef AVR_HAS_RAMPZ
in r25, _SFR_IO_ADDR(RAMPZ)
push r25
#endif
/* Save R0 -- the scratch register and the zero register
* (which may not be zero). R1 must be zero for our purposes
*/
@ -296,6 +303,13 @@
pop r1
pop r0
/* Restore RAMPZ if the MCU has it */
#ifdef AVR_HAS_RAMPZ
pop r24
out _SFR_IO_ADDR(RAMPZ), r24
#endif
/* Restore the status register (probably enabling interrupts) */
pop r24 /* Restore the status register */
@ -392,6 +406,13 @@
adiw r26, 1
#ifdef AVR_HAS_RAMPZ
/* Save RAMPZ if the MCU has it */
in r0, _SFR_IO_ADDR(RAMPZ)
st X+, r0
#endif
/* Save the status register
* (probably not necessary since interrupts are disabled)
*/
@ -544,6 +565,13 @@
ld r0, x+
#ifdef AVR_HAS_RAMPZ
/* Restore RAMPZ if the MCU has it */
ld r24, X+
out _SFR_IO_ADDR(RAMPZ), r24
#endif
/* The following control flow split is required to eliminate non-atomic
* interrupt_enable - return sequence.
*