diff --git a/arch/avr/include/avr/irq.h b/arch/avr/include/avr/irq.h index 65abae20128..9e52dd16ef7 100644 --- a/arch/avr/include/avr/irq.h +++ b/arch/avr/include/avr/irq.h @@ -93,6 +93,9 @@ #define REG_PC0 35 /* PC */ #define REG_PC1 36 +#if ATMEGA_PC_SIZE > 16 +#define REG_PC2 37 +#endif /**************************************************************************** * Public Types diff --git a/arch/avr/src/avr/excptmacros.h b/arch/avr/src/avr/excptmacros.h index a4674bbe859..265297a4fff 100644 --- a/arch/avr/src/avr/excptmacros.h +++ b/arch/avr/src/avr/excptmacros.h @@ -335,8 +335,11 @@ /* Pop the return address from the stack (PC0 then PC1). R18:19 are Call-used */ - pop r19 /* r19=PC0 */ - pop r18 /* r18=PC1 */ +#if ATMEGA_PC_SIZE > 16 + pop r20 +#endif /* ATMEGA_PC_SIZE */ + pop r19 + pop r18 /* Save the current stack pointer as it would be after the return(SPH then SPL). */ @@ -398,9 +401,11 @@ adiw r26, 2 /* Two registers: r24-r25 */ /* Save the return address that we have saved in r18:19*/ - - st x+, r19 /* r19=PC0 */ - st x+, r18 /* r18=PC1 */ +#if ATMEGA_PC_SIZE > 16 + st x+, r20 +#endif /* ATMEGA_PC_SIZE */ + st x+, r19 + st x+, r18 .endm /******************************************************************************************** @@ -424,12 +429,16 @@ .macro TCB_RESTORE, regs - /* X [r36:27] points to the register save block. Get an offset pointer to the PC in + /* X [r26:27] points to the register save block. Get an offset pointer to the PC in * Y [r28:29] */ movw r28, r26 /* Get a pointer to the PC0/PC1 storage location */ +#if ATMEGA_PC_SIZE <= 16 adiw r28, REG_PC0 +#else + adiw r28, REG_PC2 +#endif /* Fetch and set the new stack pointer */ @@ -441,19 +450,33 @@ /* Fetch the return address and save it at the bottom of the new stack so * that we can iret to switch contexts. The new stack is now: * + * PC2 (for 24-bit PC arch) * PC1 * PC0 * --- <- SP */ +#if ATMEGA_PC_SIZE <= 16 ld r25, y+ /* Load PC0 (r25) then PC1 (r24) */ ld r24, y+ push r24 /* Push PC0 and PC1 on the stack (PC1 then PC0) */ push r25 +#else + ld r25, y /* Load PC2 (r25) */ + subi r28,1 + push r25 + ld r25, y /* Load PC1 (r25) */ + subi r28,1 + push r25 + ld r25, y /* Load PC0 (r25) */ + subi r28,1 + push r25 +#endif /* Then get value of X [r26:r27]. Save X on the new stack where we can * recover it later. The new stack is now: * + * PC2 (for 24-bit PC arch) * PC1 * PC0 * R26 diff --git a/arch/avr/src/avr/up_dumpstate.c b/arch/avr/src/avr/up_dumpstate.c index 383734323fb..5feaeabd6f5 100644 --- a/arch/avr/src/avr/up_dumpstate.c +++ b/arch/avr/src/avr/up_dumpstate.c @@ -151,10 +151,17 @@ static inline void up_registerdump(void) current_regs[REG_R28], current_regs[REG_R29], current_regs[REG_R30], current_regs[REG_R31]); +#if !defined(REG_PC2) lldbg("PC: %02x%02x SP: %02x%02x SREG: %02x\n", current_regs[REG_PC0], current_regs[REG_PC1], current_regs[REG_SPH], current_regs[REG_SPL], current_regs[REG_SREG]); +#else + lldbg("PC: %02x%02x%02x SP: %02x%02x SREG: %02x\n", + current_regs[REG_PC0], current_regs[REG_PC1], current_regs[REG_PC2], + current_regs[REG_SPH], current_regs[REG_SPL], + current_regs[REG_SREG]); +#endif } } diff --git a/arch/avr/src/avr/up_initialstate.c b/arch/avr/src/avr/up_initialstate.c index 3fbfc557987..2d0cf145b76 100644 --- a/arch/avr/src/avr/up_initialstate.c +++ b/arch/avr/src/avr/up_initialstate.c @@ -96,8 +96,14 @@ void up_initial_state(struct tcb_s *tcb) /* Save the task entry point */ +#if !defined(REG_PC2) xcp->regs[REG_PC0] = (uint8_t)((uint16_t)tcb->start >> 8); xcp->regs[REG_PC1] = (uint8_t)((uint16_t)tcb->start & 0xff); +#else + xcp->regs[REG_PC0] = (uint8_t)((uint32_t)tcb->start >> 16); + xcp->regs[REG_PC1] = (uint8_t)((uint32_t)tcb->start >> 8); + xcp->regs[REG_PC2] = (uint8_t)((uint32_t)tcb->start & 0xff); +#endif /* Enable or disable interrupts, based on user configuration */ diff --git a/arch/avr/src/avr/up_schedulesigaction.c b/arch/avr/src/avr/up_schedulesigaction.c index 78386076f6e..c9629c52c5c 100644 --- a/arch/avr/src/avr/up_schedulesigaction.c +++ b/arch/avr/src/avr/up_schedulesigaction.c @@ -154,16 +154,24 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = sigdeliver; - tcb->xcp.saved_pc1 = current_regs[REG_PCL]; - tcb->xcp.saved_pc0 = current_regs[REG_PCH]; + tcb->xcp.saved_pc0 = current_regs[REG_PC0]; + tcb->xcp.saved_pc1 = current_regs[REG_PC1]; +#if defined(REG_PC2) + tcb->xcp.saved_pc2 = current_regs[REG_PC2]; +#endif tcb->xcp.saved_sreg = current_regs[REG_SREG]; /* Then set up to vector to the trampoline with interrupts * disabled */ - - current_regs[REG_PC1] = (uint16_t)up_sigdeliver & 0xff; +#if !defined(REG_PC2) current_regs[REG_PC0] = (uint16_t)up_sigdeliver >> 8; + current_regs[REG_PC1] = (uint16_t)up_sigdeliver & 0xff; +#else + current_regs[REG_PC0] = (uint32_t)up_sigdeliver >> 16; + current_regs[REG_PC1] = (uint32_t)up_sigdeliver >> 8; + current_regs[REG_PC2] = (uint32_t)up_sigdeliver & 0xff; +#endif current_regs[REG_SREG] &= ~(1 << SREG_I); /* And make sure that the saved context in the TCB @@ -188,16 +196,26 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = sigdeliver; - tcb->xcp.saved_pc1 = tcb->xcp.regs[REG_PCL]; - tcb->xcp.saved_pc0 = tcb->xcp.regs[REG_PCH]; + tcb->xcp.saved_pc0 = tcb->xcp.regs[REG_PC0]; + tcb->xcp.saved_pc1 = tcb->xcp.regs[REG_PC1]; +#if defined(REG_PC2) + tcb->xcp.saved_pc2 = tcb->xcp.regs[REG_PC2]; +#endif tcb->xcp.saved_sreg = tcb->xcp.regs[REG_SREG]; /* Then set up to vector to the trampoline with interrupts * disabled */ - tcb->xcp.regs[REG_PC1] = (uint16_t)up_sigdeliver & 0xff; +#if !defined(REG_PC2) tcb->xcp.regs[REG_PC0] = (uint16_t)up_sigdeliver >> 8; + tcb->xcp.regs[REG_PC1] = (uint16_t)up_sigdeliver & 0xff; +#else + tcb->xcp.regs[REG_PC0] = (uint32_t)up_sigdeliver >> 16; + tcb->xcp.regs[REG_PC1] = (uint32_t)up_sigdeliver >> 8; + tcb->xcp.regs[REG_PC2] = (uint32_t)up_sigdeliver & 0xff; + +#endif tcb->xcp.regs[REG_SREG] &= ~(1 << SREG_I); } } diff --git a/arch/avr/src/avr/up_sigdeliver.c b/arch/avr/src/avr/up_sigdeliver.c index 1901cf420bd..6720e5c43c1 100644 --- a/arch/avr/src/avr/up_sigdeliver.c +++ b/arch/avr/src/avr/up_sigdeliver.c @@ -101,8 +101,11 @@ void up_sigdeliver(void) /* Save the real return state on the stack. */ up_copystate(regs, rtcb->xcp.regs); - regs[REG_PC1] = rtcb->xcp.saved_pcl; - regs[REG_PC0] = rtcb->xcp.saved_pch; + regs[REG_PC0] = rtcb->xcp.saved_pc0; + regs[REG_PC1] = rtcb->xcp.saved_pc1; +#if defined(REG_PC2) + regs[REG_PC2] = rtcb->xcp.saved_pc2; +#endif regs[REG_SREG] = rtcb->xcp.saved_sreg; /* Get a local copy of the sigdeliver function pointer. We do this so that diff --git a/arch/avr/src/avr/up_switchcontext.S b/arch/avr/src/avr/up_switchcontext.S index da5f45e6171..67587c7ac43 100755 --- a/arch/avr/src/avr/up_switchcontext.S +++ b/arch/avr/src/avr/up_switchcontext.S @@ -39,6 +39,8 @@ #include +#include + #include "excptmacros.h" /************************************************************************************