From b3969170d5762962ad65b7769c1a45e35e595028 Mon Sep 17 00:00:00 2001 From: patacongo Date: Fri, 15 Feb 2008 14:28:54 +0000 Subject: [PATCH] Flesh out Z8Encore\! interrupt context switches git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@685 42af7a65-404d-4744-a932-0658087f49c3 --- arch/z80/include/z8/irq.h | 18 +-- arch/z80/src/common/up_sigdeliver.c | 2 +- arch/z80/src/z8/z8_initialstate.c | 8 +- arch/z80/src/z8/z8_restorecontext.S | 25 ++-- arch/z80/src/z8/z8_vector.S | 170 +++++++++++++++++++++++----- arch/z80/src/z80/z80_sigsetup.c | 2 +- 6 files changed, 171 insertions(+), 54 deletions(-) diff --git a/arch/z80/include/z8/irq.h b/arch/z80/include/z8/irq.h index 25d6d3ef4a..962ed5662a 100644 --- a/arch/z80/include/z8/irq.h +++ b/arch/z80/include/z8/irq.h @@ -245,7 +245,7 @@ /* Byte offsets: */ -#define XCPT_R0_OFFS (2*XCPT_RR0) /* Offset 0-15: R0-R15 */ +#define XCPT_R0_OFFS (2*XCPT_RR0) /* Offset 0-15: R0-R15 */ #define XCPT_R1_OFFS (2*XCPT_RR0+1) #define XCPT_R2_OFFS (2*XCPT_RR2) #define XCPT_R3_OFFS (2*XCPT_RR2+1) @@ -261,14 +261,14 @@ #define XCPT_R13_OFFS (2*XCPT_RR12+1) #define XCPT_R14_OFFS (2*XCPT_R1R4) #define XCPT_R15_OFFS (2*XCPT_R1R4+1) -#define XCPT_UNUSED_OFFS (2*XCPT_IRQCTL) /* Offset 16: Unused (zero) */ -#define XCPT_IRQCTL_OFFS (2*XCPT_IRQCTL+1) /* offset 17: IRQCTL register */ -#define XCPT_SPH_OFFS (2*XCPT_SP) /* Offset 18: SP[8:15] */ -#define XCPT_SPL_OFFS (2*XCPT_SP+1) /* Offset 19: SP[0:7] */ -#define XCPT_RP_OFFS (2*XCPT_I) /* Offset 20: Register pointer */ -#define XCPT_FLAGS_OFFS (2*XCPT_I+1) /* Offset 21: FLAGS */ -#define XCPT_PCH_OFFS (2*XCPT_PC) /* Offset 22: PC[8:15] */ -#define XCPT_PCL_OFFS (2*XCPT_PC+1) /* Offset 23: PC[0:7] */ +#define XCPT_UNUSED_OFFS (2*XCPT_IRQCTL) /* Offset 16: Unused (zero) */ +#define XCPT_IRQCTL_OFFS (2*XCPT_IRQCTL+1) /* offset 17: IRQCTL register */ +#define XCPT_SPH_OFFS (2*XCPT_SP) /* Offset 18: SP[8:15] */ +#define XCPT_SPL_OFFS (2*XCPT_SP+1) /* Offset 19: SP[0:7] */ +#define XCPT_RP_OFFS (2*XCPT_RPFLAGS) /* Offset 20: Register pointer */ +#define XCPT_FLAGS_OFFS (2*XCPT_RPFLAGS+1) /* Offset 21: FLAGS */ +#define XCPT_PCH_OFFS (2*XCPT_PC) /* Offset 22: PC[8:15] */ +#define XCPT_PCL_OFFS (2*XCPT_PC+1) /* Offset 23: PC[0:7] */ #define XCPTCONTEXT_SIZE (2*XCPTCONTEXT_REGS) diff --git a/arch/z80/src/common/up_sigdeliver.c b/arch/z80/src/common/up_sigdeliver.c index 9ab8f84470..80fcb4e5c7 100644 --- a/arch/z80/src/common/up_sigdeliver.c +++ b/arch/z80/src/common/up_sigdeliver.c @@ -83,7 +83,7 @@ void up_sigdeliver(void) { #ifndef CONFIG_DISABLE_SIGNALS FAR _TCB *rtcb = (_TCB*)g_readytorun.head; - uint16 regs[XCPTCONTEXT_REGS]; + chipret_t regs[XCPTCONTEXT_REGS]; sig_deliver_t sigdeliver; /* Save the errno. This must be preserved throughout the signal handling diff --git a/arch/z80/src/z8/z8_initialstate.c b/arch/z80/src/z8/z8_initialstate.c index 4d7ef4c176..57df5c7353 100644 --- a/arch/z80/src/z8/z8_initialstate.c +++ b/arch/z80/src/z8/z8_initialstate.c @@ -41,7 +41,9 @@ #include #include + #include +#include #include "chip/chip.h" #include "up_internal.h" @@ -77,7 +79,7 @@ * ****************************************************************************/ -void up_initial_state(_TCB *tcb) +void up_initial_state(FAR _TCB *tcb) { struct xcptcontext *xcp = &tcb->xcp; @@ -85,9 +87,9 @@ void up_initial_state(_TCB *tcb) memset(xcp, 0, sizeof(struct xcptcontext)); #ifndef CONFIG_SUPPRESS_INTERRUPTS - xcp->regs[XCPT_IRQCTL] = %0080; /* IRQE bit will enable interrupts */ + xcp->regs[XCPT_IRQCTL] = 0x0080; /* IRQE bit will enable interrupts */ #endif - xcp->regs[XCPT_RPFLAGS] = %e000; /* RP=%e0 */ + xcp->regs[XCPT_RPFLAGS] = 0xe000; /* RP=%e0 */ xcp->regs[XCPT_SP] = (chipreg_t)tcb->adj_stack_ptr; xcp->regs[XCPT_PC] = (chipreg_t)tcb->start; } diff --git a/arch/z80/src/z8/z8_restorecontext.S b/arch/z80/src/z8/z8_restorecontext.S index 2f614556eb..ef22b10e46 100755 --- a/arch/z80/src/z8/z8_restorecontext.S +++ b/arch/z80/src/z8/z8_restorecontext.S @@ -101,23 +101,21 @@ _z8_restorecontext: * address */ - ld r1, #%e0 /* r1 = destination address */ + clr r0 /* rr0 = destination address */ + ldx r1, XCPT_RP_OFFS(rr6) ld r2, r6 /* rr2 = source address */ ld r3, r7 ld r4, #16 /* r4 = number of bytes to copy */ - cp r2, #0 - jr z, _z8_restore2 -_z8_restore1: - ldx r0, @rr2 - ld @r1, r0 - inc r1 +_z8_restore: + ldx r5, @rr2 + ldx @rr0, r5 + incw rr0 incw rr2 - djnz r4, _z8_restore1 + djnz r4, _z8_restore /* Set the new stack pointer */ -_z8_restore2: ldx r0, XCPT_SPH_OFFS(rr6) ldx r1, XCPT_SPL_OFFS(rr6) ldx sph, r0 @@ -130,9 +128,10 @@ _z8_restore2: push r1 push r0 - /* Recover the flags settings.. but don't restore the flags yet */ + /* Recover the flags and RP settings.. but don't restore them yet */ - ldx r1, XCPT_FLAGS_OFFS(rr6) + ldx r1, XCPT_FLAGS_OFFS(rr0) + ldx r2, XCPT_RP_OFFS(rr0) /* Determine whether interrupts must be enabled on return. This * would be nicer to do below, but later we will need to preserve @@ -149,7 +148,7 @@ _z8_restore2: /* Restore the user register page and return with interrupts disabled */ - srp #%e0 /* Does not effect flags */ + ldx rp, r2 /* Does not effect flags */ ret /* Does not effect flags */ _z8_returnenabled: @@ -159,7 +158,7 @@ _z8_returnenabled: /* Restore the user register page, re-enable interrupts and return */ - srp #%e0 /* Does not effect flags */ + ldx rp, r2 /* Does not effect flags */ ei /* Does not effect flags */ ret /* Does not effect flags */ diff --git a/arch/z80/src/z8/z8_vector.S b/arch/z80/src/z8/z8_vector.S index aa25e5a892..186f59b595 100755 --- a/arch/z80/src/z8/z8_vector.S +++ b/arch/z80/src/z8/z8_vector.S @@ -52,50 +52,52 @@ * External References / External Definitions **************************************************************************/ + xref _up_doirq:ROM + #if defined(ENCORE_VECTORS) - xdef _z8_wdt_handler - xdef _z8_trap_handler + xdef _z8_wdt_handler + xdef _z8_trap_handler if EZ8_TIMER3=1 - xdef _z8_timer2_handler + xdef _z8_timer2_handler endif - xdef _z8_timer1_handler - xdef _z8_timer0_handler + xdef _z8_timer1_handler + xdef _z8_timer0_handler if EZ8_UART0=1 - xdef _z8_uart0rx_handler - xdef _z8_uart0tx_handler + xdef _z8_uart0rx_handler + xdef _z8_uart0tx_handler endif if EZ8_I2C=1 - xdef _z8_i2c_handler + xdef _z8_i2c_handler endif if EZ8_SPI=1 - xdef _z8_spi_handler + xdef _z8_spi_handler endif if EZ8_ADC=1 - xdef _z8_adc_handler + xdef _z8_adc_handler endif - xdef _z8_p7ad_handler - xdef _z8_p6ad_handler - xdef _z8_p5ad_handler - xdef _z8_p4ad_handler - xdef _z8_p3ad_handler - xdef _z8_p2ad_handler - xdef _z8_p1ad_handler - xdef _z8_p0ad_handler + xdef _z8_p7ad_handler + xdef _z8_p6ad_handler + xdef _z8_p5ad_handler + xdef _z8_p4ad_handler + xdef _z8_p3ad_handler + xdef _z8_p2ad_handler + xdef _z8_p1ad_handler + xdef _z8_p0ad_handler if EZ8_TIMER4=1 - xdef _z8_timer3_handler + xdef _z8_timer3_handler endif if EZ8_UART1=1 - xdef _z8_uart1rx_handler - xdef _z8_uart1tx_handler + xdef _z8_uart1rx_handler + xdef _z8_uart1tx_handler endif if EZ8_DMA=1 - xdef _z8_dma_handler + xdef _z8_dma_handler endif if EZ8_PORT1=0 - xdef _z8_c3_handler - xdef _z8_c2_handler - xdef _z8_c1_handler - xdef _z8_c0_handler + xdef _z8_c3_handler + xdef _z8_c2_handler + xdef _z8_c1_handler + xdef _z8_c0_handler endif /**************************************************************************/ @@ -233,13 +235,14 @@ endif **************************************************************************/ ENTER : MACRO val + pushx rp /* Save the current RP value in the stack */ srp #%f0 /* Load the interrupt register pointer */ ld r0, #val /* Pass the new value in r0 jr _z8_common_handler /* The rest of the handling is common */ ENDMAC ENTER LEAVE : MACRO - srp #%e0 /* Restore the user register pointer */ + popx rp /* Restore the user register pointer */ iret /* And return from interrupt */ ENDMAC LEAVE @@ -738,6 +741,119 @@ _z8_wotrap_handler: **************************************************************************/ _z8_common_handler: + /* Pass the address of the IRQ stack frame */ + + ldx r2, sph /* rr2 = stack pointer */ + ldx r3, spl + push r3 /* Pass as a parameter */ + push r2 + + /* Pass the IRQ number */ + + push r0 + + /* Process the interrupt */ + + call _up_doirq /* Call the IRQ handler */ + + /* Release arguments from the stack */ + + pop r4 /* Discard the IRQ argument */ + pop r2 /* Recover the stack pointer parameter */ + pop r3 + + /* If a interrupt level context switch occurred, then the + * return value will be the same as the input value + */ + + cp r0, r2 /* Same as the return value? */ + jr nz, _z8_switch + cp r1, r3 + jr z, _z8_noswitch + + /* A context switch occurs. Restore the use context. + * rr0 = pointer to context structgure. + */ + +_z8_switch: + + /* Destroy the interrupt return information on the stack */ + + pop r4 /* Destroy saved RP */ + pop r4 /* Destroy saved flags */ + pop r4 /* Destroy saved return address */ + pop r4 + + /* Copy all registers into the user register area. */ + + clr r2 /* rr2 = destination address */ + ldx r3, XCPT_RP_OFFS(rr0) + ld r4, r0 /* rr4 = source address */ + ld r5, r1 + ld r6, #16 /* r6 = number of bytes to copy */ + +_z8_restore: + ldx r7, @rr4 + ldx @rr2, r7 + incw rr2 + incw rr4 + djnz r6, _z8_restore + + /* Set the new stack pointer */ + + ldx r2, XCPT_SPH_OFFS(rr0) + ldx r3, XCPT_SPL_OFFS(rr0) + ldx sph, r2 + ldx spl, r3 + + /* Push the return address onto the stack */ + + ldx r2, XCPT_PCH_OFFS(rr0) + ldx r3, XCPT_PCL_OFFS(rr0) + push r3 + push r2 + + /* Recover the flags and RP settings.. but don't restore them yet */ + + ldx r3, XCPT_FLAGS_OFFS(rr0) + ldx r4, XCPT_RP_OFFS(rr0) + + /* Determine whether interrupts must be enabled on return. This + * would be nicer to do below, but later we will need to preserve + * the condition codes in the flags. + */ + + ldx r2, XCPT_IRQCTL_OFFS(rr0) + tm r2, #%80 + jr nz, _z8_returnenabled + + /* Restore the flag settings */ + + ldx flags, r3 + + /* Restore the user register page and return with interrupts disabled. + * Note that we cannot use the iret instruction because it unconditionally + * re-enabled interrupts + */ + + ldx rp, r4 /* Does not effect flags */ + ret /* Does not effect flags */ + +_z8_returnenabled: + /* Restore the flag settings */ + + ldx flags, r1 + + /* Restore the user register page, re-enable interrupts and return. + * Note that we cannot use the iret instruction because it unconditionally + * re-enabled interrupts + */ + + ldx rp, r4 /* Does not effect flags */ + ei /* Does not effect flags */ + ret /* Does not effect flags */ + +_z8_noswitch: LEAVE /************************************************************************** diff --git a/arch/z80/src/z80/z80_sigsetup.c b/arch/z80/src/z80/z80_sigsetup.c index 351745cd7f..504f3ce192 100644 --- a/arch/z80/src/z80/z80_sigsetup.c +++ b/arch/z80/src/z80/z80_sigsetup.c @@ -79,7 +79,7 @@ void z80_sigsetup(FAR _TCB *tcb, sig_deliver_t sigdeliver, FAR chipreg_t *regs) /* Then set up to vector to the trampoline with interrupts disabled */ - regs[XCPT_PC] = (uint16)up_sigdeliver; + regs[XCPT_PC] = (chipreg_t)up_sigdeliver; regs[XCPT_I] = 0; }