mirror of
https://github.com/apache/nuttx.git
synced 2026-06-08 01:42:58 +08:00
AVR: Add support for AVR chips with 24-bit Program Counter register
The main challenge is to change the context switch code to be aware of the extra byte that is saved on stack during call and intterupt. This relates also to the task startup and signal handling.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include "excptmacros.h"
|
||||
|
||||
/************************************************************************************
|
||||
|
||||
Reference in New Issue
Block a user