This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 88a66f18e67af40f19355ba8d27b469484fb33da Author: Kerogit <kr....@kerogit.eu> AuthorDate: Mon Mar 17 12:20:35 2025 +0100 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. --- arch/avr/include/atmega/irq.h | 24 +++++++++++++++++++++--- arch/avr/include/avr/irq.h | 23 +++++++++++++++++------ arch/avr/src/atmega/Kconfig | 3 +++ arch/avr/src/atmega/atmega_head.S | 4 +++- arch/avr/src/avr/Kconfig | 4 ++++ arch/avr/src/avr/avr_initialstate.c | 6 ++++++ arch/avr/src/avr/avr_registerdump.c | 5 +++++ arch/avr/src/avr/avr_schedulesigaction.c | 6 ++++++ arch/avr/src/avr/avr_sigdeliver.c | 3 +++ arch/avr/src/avr/excptmacros.h | 28 ++++++++++++++++++++++++++++ 10 files changed, 96 insertions(+), 10 deletions(-) diff --git a/arch/avr/include/atmega/irq.h b/arch/avr/include/atmega/irq.h index 9f41801799..f68482af13 100644 --- a/arch/avr/include/atmega/irq.h +++ b/arch/avr/include/atmega/irq.h @@ -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" diff --git a/arch/avr/include/avr/irq.h b/arch/avr/include/avr/irq.h index cde36c1d04..bdf164638f 100644 --- a/arch/avr/include/avr/irq.h +++ b/arch/avr/include/avr/irq.h @@ -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; diff --git a/arch/avr/src/atmega/Kconfig b/arch/avr/src/atmega/Kconfig index 1079d13128..376701d36b 100644 --- a/arch/avr/src/atmega/Kconfig +++ b/arch/avr/src/atmega/Kconfig @@ -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. diff --git a/arch/avr/src/atmega/atmega_head.S b/arch/avr/src/atmega/atmega_head.S index fb219948ab..c06f10dfc1 100644 --- a/arch/avr/src/atmega/atmega_head.S +++ b/arch/avr/src/atmega/atmega_head.S @@ -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 diff --git a/arch/avr/src/avr/Kconfig b/arch/avr/src/avr/Kconfig index a05c7773d4..9e07f174ba 100644 --- a/arch/avr/src/avr/Kconfig +++ b/arch/avr/src/avr/Kconfig @@ -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 diff --git a/arch/avr/src/avr/avr_initialstate.c b/arch/avr/src/avr/avr_initialstate.c index 31fb00dad7..002472b4ca 100644 --- a/arch/avr/src/avr/avr_initialstate.c +++ b/arch/avr/src/avr/avr_initialstate.c @@ -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 diff --git a/arch/avr/src/avr/avr_registerdump.c b/arch/avr/src/avr/avr_registerdump.c index b7297eedb5..8b71718294 100644 --- a/arch/avr/src/avr/avr_registerdump.c +++ b/arch/avr/src/avr/avr_registerdump.c @@ -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 } } diff --git a/arch/avr/src/avr/avr_schedulesigaction.c b/arch/avr/src/avr/avr_schedulesigaction.c index 4d035dc3fc..cfc0685f18 100644 --- a/arch/avr/src/avr/avr_schedulesigaction.c +++ b/arch/avr/src/avr/avr_schedulesigaction.c @@ -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]; diff --git a/arch/avr/src/avr/avr_sigdeliver.c b/arch/avr/src/avr/avr_sigdeliver.c index d9915a7a6a..89f1597222 100644 --- a/arch/avr/src/avr/avr_sigdeliver.c +++ b/arch/avr/src/avr/avr_sigdeliver.c @@ -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; diff --git a/arch/avr/src/avr/excptmacros.h b/arch/avr/src/avr/excptmacros.h index 4aad75bda1..dcfa8c4e54 100644 --- a/arch/avr/src/avr/excptmacros.h +++ b/arch/avr/src/avr/excptmacros.h @@ -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. *