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.
    *

Reply via email to