diff --git a/arch/pjrc-8051/defconfig b/arch/pjrc-8051/defconfig index 28044f43f8..54bab70ead 100644 --- a/arch/pjrc-8051/defconfig +++ b/arch/pjrc-8051/defconfig @@ -42,7 +42,7 @@ CONFIG_ARCH=pjrc-8051 CONFIG_ARCH_8052=y CONFIG_ARCH_PJRC=y -CONFIG_8051_LEDS=n +CONFIG_8051_LEDS=y # # General OS setup diff --git a/arch/pjrc-8051/include/irq.h b/arch/pjrc-8051/include/irq.h index 819a73df7e..45891986a1 100644 --- a/arch/pjrc-8051/include/irq.h +++ b/arch/pjrc-8051/include/irq.h @@ -90,28 +90,52 @@ #define FRAME_RETLS 0 #define FRAME_RETMS 1 -/* Then a full context save area which can be indexed with - * the following definitions (relative to the beginning of - * the initial frame. +/* Then a partial context context save area that can be + * indexed with the following definitions (relative to the + * beginning of the initial frame. */ #define FRAME_ACC 2 #define FRAME_IE 3 #define FRAME_DPL 4 #define FRAME_DPH 5 -#define FRAME_B 6 -#define FRAME_R2 7 -#define FRAME_R3 8 -#define FRAME_R4 9 -#define FRAME_R5 10 -#define FRAME_R6 11 -#define FRAME_R7 12 -#define FRAME_R0 13 -#define FRAME_R1 14 -#define FRAME_PSW 15 -#define FRAME_BP 16 -#define FRAME_SIZE 17 +#define FRAME_SIZE 6 + +/* The remaining registers are not saved on the stack (due + * to the limited stack size of the 8051/2) but in an array + * in the TCB: + */ + +#define REGS_B 0 +#define REGS_R2 1 +#define REGS_R3 2 +#define REGS_R4 3 +#define REGS_R5 4 +#define REGS_R6 5 +#define REGS_R7 6 +#define REGS_R0 7 +#define REGS_R1 8 +#define REGS_PSW 9 +#define REGS_BP 10 + +#define REGS_SIZE 11 + +/* Note that the stack pointer is not saved. Rather, the + * size of the saved stack frame is saved in the 'nbytes' + * field. Since that stack begins at a fixed location, the + * top-of-stack pointer can be derived from the saved size. + */ + +/* These are offsets into struct xcptcontext that can be + * used from assembly language to access the structure. + */ + +#define XCPT_NBYTES 0 +#define XCPT_STACK 1 +#define XCPT_REGS (STACK_SIZE+1) + +#define XCPT_SIZE (STACK_SIZE+REGS_SIZE+1) /************************************************************ * Public Types @@ -122,8 +146,26 @@ #ifndef __ASSEMBLY__ struct xcptcontext { + /* This is the number of valid bytes currently saved in + * stack[]. Since that stack begins at a fixed location, + * the top-of-stack pointer can be derived from this size. + */ + ubyte nbytes; + + /* This is the saved stack. Space is allocated for the + * entire 256 byte IRAM (minus register and bit usage at + * the beginning). + */ + ubyte stack[STACK_SIZE]; + + /* These are save 8051/2 registers. These are saved + * separately from the stack to increase the effective + * stack size. + */ + + ubyte regs[REGS_SIZE]; }; #endif /* __ASSEMBLY */ diff --git a/arch/pjrc-8051/src/pjrc.h b/arch/pjrc-8051/src/pjrc.h index 41f5a7e21f..fd875d3883 100644 --- a/arch/pjrc-8051/src/pjrc.h +++ b/arch/pjrc-8051/src/pjrc.h @@ -150,7 +150,7 @@ xdata at 0xF903 ubyte p82c55_def_config; #define LED_STARTED 0 #define LED_HEAPALLOCATE 1 #define LED_IRQSENABLED 2 -#define LED_UNUSED1 3 +#define LED_IDLE 3 #define LED_UNUSED2 4 #define LED_INIRQ 5 #define LED_ASSERTION 6 diff --git a/arch/pjrc-8051/src/up_blocktask.c b/arch/pjrc-8051/src/up_blocktask.c index e8ea555230..9d9094a775 100644 --- a/arch/pjrc-8051/src/up_blocktask.c +++ b/arch/pjrc-8051/src/up_blocktask.c @@ -131,7 +131,7 @@ void up_block_task(FAR _TCB *tcb, tstate_t task_state) * Just copy the current registers into the OLD rtcb. */ - up_savestack(&tcb->xcp, g_irqtos); + up_saveirqcontext(&tcb->xcp); /* Restore the exception context of the rtcb at the (new) head * of the g_readytorun task list. diff --git a/arch/pjrc-8051/src/up_debug.c b/arch/pjrc-8051/src/up_debug.c index 6f1485aaa4..3ca2acae7d 100644 --- a/arch/pjrc-8051/src/up_debug.c +++ b/arch/pjrc-8051/src/up_debug.c @@ -80,7 +80,7 @@ static void _up_putcolon(void) __naked { _asm mov a, #0x3a - lcall PM2_ENTRY_COUT + ljmp PM2_ENTRY_COUT _endasm; } @@ -126,7 +126,7 @@ static void _up_dump8(__code char *ptr, ubyte b) #ifdef CONFIG_FRAME_DUMP void up_dumpstack(void) { - NEAR ubyte *start = (NEAR ubyte *)(UP_STACK_BASE & 0xf0); + NEAR ubyte *start = (NEAR ubyte *)(STACK_BASE & 0xf0); NEAR ubyte *end = (NEAR ubyte *)SP; ubyte i; @@ -138,7 +138,16 @@ void up_dumpstack(void) for (i = 0; i < 8; i++) { _up_putspace(); - _up_puthex(*start); + if (start < (NEAR ubyte *)(STACK_BASE) || + start > end) + { + _up_putspace(); + _up_putspace(); + } + else + { + _up_puthex(*start); + } start++; } _up_putnl(); @@ -153,11 +162,52 @@ void up_dumpstack(void) #ifdef CONFIG_FRAME_DUMP void up_dumpframe(FAR struct xcptcontext *context) { - FAR ubyte *start = &context->stack[context->nbytes - FRAME_SIZE]; - _up_dump16(" RET ", start[FRAME_RETMS], start[FRAME_RETLS]); - _up_dump8(" IE ", start[FRAME_IE]); - _up_dump16(" DPTR ", start[FRAME_DPH], start[FRAME_DPL]); - _up_dump8(" PSW ", start[FRAME_PSW]); +#ifdef CONFIG_FRAME_DUMP_SHORT + FAR ubyte *stack = &context->stack[context->nbytes - FRAME_SIZE]; + FAR ubyte *regs = context->regs; + + _up_dump16(" RET ", stack[FRAME_RETMS], stack[FRAME_RETLS]); + _up_dump8 (" IE ", stack[FRAME_IE]); + _up_dump16(" DPTR ", stack[FRAME_DPH], stack[FRAME_DPL]); + _up_dump8 (" PSW ", regs[REGS_PSW]); + _up_dump8 (" SP ", context->nbytes + (STACK_BASE-1)); +#else + FAR ubyte *stack = &context->stack[context->nbytes - FRAME_SIZE]; + FAR ubyte *regs = context->regs; + ubyte i, j, k; + + _up_dump8 (" NBYTES ", context->nbytes); + + for (i = 0; i < context->nbytes; i += 8) + { + _up_puthex(i); + _up_putcolon(); + + for (j = 0; j < 8; j++) + { + k = i + j; + _up_putspace(); + if (k >= context->nbytes) + { + _up_putspace(); + _up_putspace(); + } + else + { + _up_puthex(context->stack[k]); + } + } + _up_putnl(); + } + + _up_puts(" REGS:"); + for (i = 0; i < REGS_SIZE; i++) + { + _up_putspace(); + _up_puthex(context->regs[i]); + } + _up_putnl(); +#endif } #endif diff --git a/arch/pjrc-8051/src/up_delay.c b/arch/pjrc-8051/src/up_delay.c index 7b682033f6..111d2c0dfe 100644 --- a/arch/pjrc-8051/src/up_delay.c +++ b/arch/pjrc-8051/src/up_delay.c @@ -38,6 +38,7 @@ ************************************************************/ #include +#include #include "up_internal.h" /************************************************************ diff --git a/arch/pjrc-8051/src/up_head.S b/arch/pjrc-8051/src/up_head.S index 33d9db3ddf..1981e5dd8c 100644 --- a/arch/pjrc-8051/src/up_head.S +++ b/arch/pjrc-8051/src/up_head.S @@ -57,12 +57,14 @@ .globl _g_irqtos .globl _g_irqcontext + .globl _g_irqregs /************************************************************ * Public Functions ************************************************************/ .globl _irq_dispatch + .globl _up_restoreregisters /************************************************************ * Program entry points @@ -157,33 +159,31 @@ _up_interrupt: push ie clr ea - /* Now push the remaining registers with interrupt disabled */ + /* Save the remaining registers with interrupts disabled + * + * a, ie, and dptr go on the stack. + */ push dpl push dph - push b - push ar2 - push ar3 - push ar4 - push ar5 - push ar6 - push ar7 - push ar0 - push ar1 - push psw - clr psw - push _bp - /* Save the IRQ number in r3 */ + /* Other registers go into the IRQ register save area */ + + push acc + mov dptr, #_g_irqregs + lcall _up_saveregisters + + /* Show interrupt status on the LEDs */ #ifdef CONFIG_8051_LEDS - push acc mov dpl, #LED_INIRQ lcall _up_ledon - pop ar2 -#else - mov r2, a #endif + + /* Save the IRQ number in r2 */ + + pop ar2 + /* Mark that we are in an interrupt and provide the top * of stack pointer to the context switching logic. */ @@ -197,7 +197,7 @@ _up_interrupt: * structure. */ - mov dptr,#_g_irqcontext + mov dptr, #_g_irqcontext clr a movx @dptr,a inc dptr @@ -238,8 +238,17 @@ _up_interrupt: movx a, @dptr mov r3, a - orl a, r2 - jz 00003$ + orl a, r2 + jnz 00001$ + + /* No context switch is pending. Restore registers + * from the interrupt register save area. + */ + + mov dptr, #_g_irqregs + sjmp 00004$ + +00001$: /****************************************************/ /* A context switch is pending, clear g_irqcontext */ @@ -285,6 +294,8 @@ _up_interrupt: /* Save r2-3 = &context->stack */ inc dptr + push dpl + push dph mov r2, dpl mov r3, dph @@ -293,9 +304,10 @@ _up_interrupt: mov r0, #STACK_BASE /* Top of the copy loop */ -00001$: - dec r4 - jz 00002$ +00002$: + mov a, r4 /* a = bytes left to transfer */ + dec r4 /* (for next time through the loop) */ + jz 00003$ /* Jump if a = 0 (done) */ /* Fetch the next byte from context->stack */ @@ -316,38 +328,69 @@ _up_interrupt: /* Increment the IRAM pointer */ inc r0 - sjmp 00001$ + sjmp 00002$ - /* Set the new stack pointer */ - -00002$: - mov sp, r5 - -#ifdef CONFIG_INTERRUPT_FRAME_DUMP - lcall _up_dumpstack -#endif - /* Then restore the context from the stack and return - * from the interrupt + /* The entire stack has been copied from XRAM into + * IRAM. Set the new stack pointer */ 00003$: -#ifdef CONFIG_8051_LEDS - mov dpl, #LED_INIRQ - lcall _up_ledoff -#endif - pop _bp - pop psw - pop ar1 - pop ar0 - pop ar7 - pop ar6 - pop ar5 - pop ar4 - pop ar3 - pop ar2 - pop b pop dph pop dpl - pop ie + mov sp, r5 + +#ifdef CONFIG_INTERRUPT_FRAME_DUMP + push dpl + push dph + lcall _up_dumpstack + pop dpl + pop dph +#endif + /* Get the pointer to the register save area */ + + mov a, #FRAME_SIZE + add a, dpl + mov dpl, a + clr a + addc a, dph + mov dph, a + +00004$: /****************************************************/ + + /* Restore the context from the register save area + * and return from the interrupt. At this point, dptr + * holds the pointer to the memory region that holds + * the register save area. This could be either + * g_irqregs (no context switch) or &g_irqcontext->regs + * (context switch). + */ + +#ifdef CONFIG_8051_LEDS + push dpl + push dph + mov dpl, #LED_INIRQ + lcall _up_ledoff + pop dpl + pop dph +#endif + /* Restore registers from the register save area */ + + lcall _up_restoreregisters + + /* Restore registers from the stack and return */ + + pop dph + pop dpl + + /* Restore the interrupt state per the stored IE value */ + + pop acc + jb acc.7,00005$ + clr ie.7 + sjmp 00006$ +00005$: + setb ie.7 + +00006$: pop acc reti diff --git a/arch/pjrc-8051/src/up_idle.c b/arch/pjrc-8051/src/up_idle.c index fcc89ed9b7..c413c3f413 100644 --- a/arch/pjrc-8051/src/up_idle.c +++ b/arch/pjrc-8051/src/up_idle.c @@ -50,6 +50,10 @@ * Private Data ************************************************************/ +#if defined(CONFIG_8051_LEDS) && defined(CONFIG_8051_BRINGUP) +static ubyte g_ledtoggle = 0; +#endif + /************************************************************ * Private Functions ************************************************************/ @@ -75,5 +79,16 @@ void up_idle(void) { +#if defined(CONFIG_8051_LEDS) && defined(CONFIG_8051_BRINGUP) + g_ledtoggle++; + if (g_ledtoggle == 0x80) + { + up_ledon(LED_IDLE); + } + else if (g_ledtoggle == 0x00) + { + up_ledoff(LED_IDLE); + } +#endif } diff --git a/arch/pjrc-8051/src/up_initialize.c b/arch/pjrc-8051/src/up_initialize.c index d0680b6cf3..4d988501b6 100644 --- a/arch/pjrc-8051/src/up_initialize.c +++ b/arch/pjrc-8051/src/up_initialize.c @@ -60,6 +60,16 @@ ubyte g_irqtos; +/* Registers are saved in the following global array during + * interrupt processing. If a context switch is performed + * during the interrupt handling, these registers will be + * copied into the TCB again (NOTE: We could save a copy + * if the interrupt handling logic saved the registers + * directly into (_TCB*)g_readytorun.head->xcp.regs). + */ + +ubyte g_irqregs[REGS_SIZE]; + /* If during execution of an interrup handler, a context * switch must be performed, the follwing will be set to * to that address of the relevant context structure. The @@ -69,6 +79,13 @@ ubyte g_irqtos; FAR struct xcptcontext *g_irqcontext; +/* It is faster to look up 8-bit shifts in this table than + * to comput them. + */ + +const ubyte g_ntobit[8] = + { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; + /************************************************************ * Private Functions ************************************************************/ diff --git a/arch/pjrc-8051/src/up_initialstate.c b/arch/pjrc-8051/src/up_initialstate.c index 1eae39fa9f..7fc0ddc390 100644 --- a/arch/pjrc-8051/src/up_initialstate.c +++ b/arch/pjrc-8051/src/up_initialstate.c @@ -75,6 +75,7 @@ void up_initial_state(FAR _TCB *tcb) { FAR ubyte *frame = tcb->xcp.stack; + FAR ubyte *regs = tcb->xcp.regs; /* This is the form of initial stack frame * @@ -96,10 +97,21 @@ void up_initial_state(FAR _TCB *tcb) frame[FRAME_RETLS] = (((uint16)tcb->start) & 0xff); frame[FRAME_RETMS] = (((uint16)tcb->start) >> 8); - /* The context save area follows the return address. */ + /* The context save area for registers a, ie, and dpstr + * follows the return address in the stack frame. + */ - frame[FRAME_IE] = 0x80; - frame[FRAME_PSW] = 0; + frame[FRAME_IE] = 0x80; - tcb->xcp.nbytes = FRAME_SIZE; + /* Save the number of bytes in the frame (which will be used + * to intialize the stack pointer when the task is started). + */ + + tcb->xcp.nbytes = FRAME_SIZE; + + /* Initialize the remaining register save area which is + * outside of the stack save area. + */ + + tcb->xcp.regs[REGS_PSW] = 0; } diff --git a/arch/pjrc-8051/src/up_internal.h b/arch/pjrc-8051/src/up_internal.h index 19c628f5cf..6348030541 100644 --- a/arch/pjrc-8051/src/up_internal.h +++ b/arch/pjrc-8051/src/up_internal.h @@ -41,6 +41,7 @@ **************************************************************************/ #include +#include #ifdef CONFIG_ARCH_PJRC # include "pjrc.h" #endif @@ -51,10 +52,13 @@ /* Bring-up debug configurations */ -#define CONFIG_FRAME_DUMP 1 /* Enabled stack/frame dumping logic */ -#define CONFIG_SUPPRESS_INTERRUPTS 1 /* Do not enable interrupts */ -#define CONFIG_SWITCH_FRAME_DUMP 1 /* Dump frames from normal switches */ +#define CONFIG_8051_BRINGUP 1 /* Enables some bringup features */ +#define CONFIG_FRAME_DUMP 1 /* Enable stack/frame dumping logic */ +#undef CONFIG_FRAME_DUMP_SHORT /* Terse frame dump output */ +#define CONFIG_SUPPRESS_INTERRUPTS 1 /* Do not enable interrupts */ +#define CONFIG_SWITCH_FRAME_DUMP 1 /* Dump frames from normal switches */ #undef CONFIG_INTERRUPT_FRAME_DUMP /* Dump frames from interrupt switches */ +#define CONFIG_LED_DEBUG 1 /* Enabled debug output from LED logic */ /************************************************************************** * Public Types @@ -75,6 +79,16 @@ extern ubyte g_irqtos; +/* Registers are saved in the following global array during + * interrupt processing. If a context switch is performed + * during the interrupt handling, these registers will be + * copied into the TCB again (NOTE: We could save a copy + * if the interrupt handling logic saved the registers + * directly into (_TCB*)g_readytorun.head->xcp.regs). + */ + +extern ubyte g_irqregs[REGS_SIZE]; + /* If during execution of an interrup handler, a context * switch must be performed, the follwing will be set to * to that address of the relevant context structure. The @@ -84,6 +98,12 @@ extern ubyte g_irqtos; extern FAR struct xcptcontext *g_irqcontext; +/* It is faster to look up 8-bit shifts in this table than + * to comput them. + */ + +extern const ubyte g_ntobit[8]; + #endif /* __ASSEMBLY */ /************************************************************************** @@ -95,11 +115,13 @@ extern FAR struct xcptcontext *g_irqcontext; #if CONFIG_MM_REGIONS > 1 extern void up_addregion(void); #endif -extern void up_delay(ubyte milliseconds) __naked; +extern void up_delay(ubyte milliseconds) __naked; extern void up_irqinitialize(void); extern void up_restorecontext(FAR struct xcptcontext *context) _naked; +extern void up_restoreregisters(FAR ubyte *regs) _naked; extern ubyte up_savecontext(FAR struct xcptcontext *context) __naked; -extern void up_savestack(FAR struct xcptcontext *context, ubyte tos); +extern void up_saveregisters(FAR ubyte *regs) _naked; +extern void up_saveirqcontext(FAR struct xcptcontext *context); extern void up_timerinit(void); /* Defined in up_assert.c */ @@ -116,8 +138,8 @@ extern void up_dumpframe(FAR struct xcptcontext *context); #ifdef CONFIG_8051_LEDS extern void up_ledinit(void); -extern void up_ledon(int led); -extern void up_ledoff(int led); +extern void up_ledon(ubyte led); +extern void up_ledoff(ubyte led); #else # define up_ledinit() # define up_ledon(led) diff --git a/arch/pjrc-8051/src/up_irq.c b/arch/pjrc-8051/src/up_irq.c index 8d024ca3a5..bf76b25a86 100644 --- a/arch/pjrc-8051/src/up_irq.c +++ b/arch/pjrc-8051/src/up_irq.c @@ -43,6 +43,8 @@ #include <8052.h> #include "up_internal.h" +#include +extern int g_nints; /************************************************************ * Definitions ************************************************************/ @@ -69,7 +71,7 @@ void up_irqinitialize(void) { -#ifndef CONFIG_SUPPRESS_INTERRUPTS +#ifdef CONFIG_SUPPRESS_INTERRUPTS /* Disable all interrupts */ IE = 0; @@ -122,7 +124,7 @@ void up_disable_irq(int irq) { if ((unsigned)irq < NR_IRQS) { - IE |= (1 << irq); + IE &= ~(g_ntobit[irq]); } } @@ -138,6 +140,6 @@ void up_enable_irq(int irq) { if ((unsigned)irq < NR_IRQS) { - IE &= ~(1 << irq); + IE |= g_ntobit[irq]; } } diff --git a/arch/pjrc-8051/src/up_leds.c b/arch/pjrc-8051/src/up_leds.c index 2c12436016..41d8ac8fa1 100644 --- a/arch/pjrc-8051/src/up_leds.c +++ b/arch/pjrc-8051/src/up_leds.c @@ -45,16 +45,75 @@ * Definitions ************************************************************/ +#define RESET_KLUDGE_NEEDED 1 + /************************************************************ * Private Data ************************************************************/ -static uint32 g_ledstate; +static ubyte g_ledstate; /************************************************************ * Private Functions ************************************************************/ +#if defined(CONFIG_LED_DEBUG) && defined(CONFIG_8051_LEDS) +static void _up_puthex(ubyte hex) __naked +{ + hex; /* To avoid unreferenced argument warning */ + _asm + mov a, dpl + ljmp PM2_ENTRY_PHEX + _endasm; +} + +static void _up_putch(ubyte ch) __naked +{ + _asm + mov a, dpl + ljmp PM2_ENTRY_COUT + _endasm; +} + +static void _up_putnl(void) __naked +{ + _asm + ljmp PM2_ENTRY_NEWLINE + _endasm; +} + +# define _up_showledinit() \ + _up_putch('I'); \ + _up_puthex(g_ledstate); _up_putch(':'); \ + _up_puthex(p82c55_port_e); _up_putnl(); + +# define _up_showledreset() \ + _up_putch('R'); \ + _up_puthex(led); _up_putch(':'); \ + _up_puthex(g_ledstate); _up_putch(':'); \ + _up_puthex(p82c55_port_e); _up_putnl(); + +# define _up_showledon() \ + _up_putch('+'); \ + _up_puthex(led); _up_putch(':'); \ + _up_puthex(g_ledstate); _up_putch(':'); \ + _up_puthex(p82c55_port_e); _up_putnl(); + +# define _up_showledoff() \ + _up_putch('-'); \ + _up_puthex(led); _up_putch(':'); \ + _up_puthex(g_ledstate); _up_putch(':'); \ + _up_puthex(p82c55_port_e); _up_putnl(); + +#else + +# define _up_showledinit() +# define _up_showledreset() +# define _up_showledon() +# define _up_showledoff() + +#endif + /************************************************************ * Public Funtions ************************************************************/ @@ -68,38 +127,71 @@ void up_ledinit(void) { /* Set all ports as outputs */ - p82c55_abc_config = 128; p82c55_def_config = 128; /* Turn LED 1-7 off; turn LED 0 on */ - g_ledstate = 0x000000fe; + g_ledstate = 0xfe; p82c55_port_e = g_ledstate; + + _up_showledinit(); } /************************************************************ * Name: up_ledon ************************************************************/ -void up_ledon(int led) +void up_ledon(ubyte led) { +#ifdef RESET_KLUDGE_NEEDED + /* I don't understand why this happens yet, but sometimes + * it is necessary to reconfigure port E. + */ + + if (g_ledstate != p82c55_port_e) + { + _up_showledreset(); + p82c55_def_config = 128; + } +#endif + + /* Clear the bit in port E corresponding to LED to turn it on */ + if (led < 8) { - g_ledstate &= ~(1 << led); + g_ledstate &= ~(g_ntobit[led]); p82c55_port_e = g_ledstate; } + + _up_showledon(); } /************************************************************ * Name: up_ledoff ************************************************************/ -void up_ledoff(int led) +void up_ledoff(ubyte led) { +#ifdef RESET_KLUDGE_NEEDED + /* I don't understand why this happens yet, but sometimes + * it is necessary to reconfigure port E. + */ + + if (g_ledstate != p82c55_port_e) + { + _up_showledreset(); + p82c55_def_config = 128; + } +#endif + + /* Set the bit in port E corresponding to LED to turn it off */ + if (led < 8) { - g_ledstate |= (1 << led); + g_ledstate |= g_ntobit[led]; p82c55_port_e = g_ledstate; } + + _up_showledoff(); } #endif /* CONFIG_8051_LEDS */ diff --git a/arch/pjrc-8051/src/up_releasepending.c b/arch/pjrc-8051/src/up_releasepending.c index dfab2ecb57..8a58da9e65 100644 --- a/arch/pjrc-8051/src/up_releasepending.c +++ b/arch/pjrc-8051/src/up_releasepending.c @@ -94,7 +94,7 @@ void up_release_pending(void) * Just copy the current registers into the OLD rtcb. */ - up_savestack(&rtcb->xcp, g_irqtos); + up_saveirqcontext(&rtcb->xcp); /* Restore the exception context of the rtcb at the (new) head * of the g_readytorun task list. diff --git a/arch/pjrc-8051/src/up_reprioritizertr.c b/arch/pjrc-8051/src/up_reprioritizertr.c index 6aa1da68ad..1b8a3adbfc 100644 --- a/arch/pjrc-8051/src/up_reprioritizertr.c +++ b/arch/pjrc-8051/src/up_reprioritizertr.c @@ -142,7 +142,7 @@ void up_reprioritize_rtr(FAR _TCB *tcb, ubyte priority) * Just copy the current registers into the OLD rtcb. */ - up_savestack(&tcb->xcp, g_irqtos); + up_saveirqcontext(&tcb->xcp); /* Restore the exception context of the rtcb at the (new) head * of the g_readytorun task list. diff --git a/arch/pjrc-8051/src/up_restorecontext.c b/arch/pjrc-8051/src/up_restorecontext.c index ce5735db99..bdb2fea241 100644 --- a/arch/pjrc-8051/src/up_restorecontext.c +++ b/arch/pjrc-8051/src/up_restorecontext.c @@ -68,6 +68,66 @@ * Public Functions **************************************************************************/ +/************************************************************************** + * Name: up_restoreregisters + * + * Description: + * Restore the saved registers from the context save area. This function + * is called from up_restorecontext (below) and also from interrupt + * handling logic. + * + * Note that this function does not restore: + * a, dptr, ie - these are saved in the stack area + * sp - this can be inferred from g_irqtos or struct xcptontext.nbytes. + * + * Inputs: + * context - the context register array from which to restore the + * register values + * + * Return: + * None + * + **************************************************************************/ + +void up_restoreregisters(FAR ubyte *regs) _naked +{ + _asm + movx a, @dptr + mov b, a + inc dptr + movx a, @dptr + mov r2, a + inc dptr + movx a, @dptr + mov r3, a + inc dptr + movx a, @dptr + mov r4, a + inc dptr + movx a, @dptr + mov r5, a + inc dptr + movx a, @dptr + mov r6, a + inc dptr + movx a, @dptr + mov r7, a + inc dptr + movx a, @dptr + mov r0, a + inc dptr + movx a, @dptr + mov r1, a + inc dptr + movx a, @dptr + mov psw, a + inc dptr + movx a, @dptr + mov _bp, a + ret + _endasm; +} + /************************************************************************** * Name: up_restorecontext * @@ -95,6 +155,10 @@ void up_restorecontext(FAR struct xcptcontext *context) __naked ar0 = 0x00 ar1 = 0x01 + /* Dump the contents of the saved frame before it is copied back + * to memory/registers. + */ + #ifdef CONFIG_SWITCH_FRAME_DUMP push dpl push dph @@ -109,14 +173,17 @@ void up_restorecontext(FAR struct xcptcontext *context) __naked clr ea - /* Register usage in the following: + /* The following logic will copy the stack from the + * context save structure into IRAM. We cannot use + * the stack in anyway during this copy. Instead, + * we will use registers as follows: * - * R0 - Holds working the 8-bit IRAM pointer + * R0 - Holds the working 8-bit IRAM pointer * R1 - Not used * R2-3 - Holds the working 16-bit XRAM pointer * R4 - Holds the working byte count * R5 - Holds the new stack pointer - * R6-7 - Not used + * R6-7 - Saved context pointer */ /* Fetch r4 = context->nbytes */ @@ -129,26 +196,32 @@ void up_restorecontext(FAR struct xcptcontext *context) __naked add a, #(STACK_BASE-1) mov r5, a - /* Save r2-3 = &context->stack */ + /* Save r2-3 and r6-r7 = &context->stack */ inc dptr mov r2, dpl mov r3, dph + mov r6, dpl + mov r7, dph /* Set r0 = stack base address */ mov r0, #STACK_BASE - /* Top of the copy loop */ + /* Top of the copy loop -- we cannot use the stack + * again until we finish the copy and set the new + * stack pointer (saved in r5) + */ 00001$: - dec r4 - jz 00002$ + mov a, r4 /* a = bytes left to transfer */ + dec r4 /* (for next time through the loop) */ + jz 00002$ /* Jump if a = 0 (done) */ /* Fetch the next byte from context->stack */ mov dpl, r2 mov dph, r3 - movx a,@dptr + movx a, @dptr /* Increment the XRAM pointer */ @@ -166,26 +239,40 @@ void up_restorecontext(FAR struct xcptcontext *context) __naked sjmp 00001$ 00002$: - /* Set the new stack pointer */ + /* Set the new stack pointer and recover the + * context->stack pointer. + */ mov sp, r5 + mov dpl, r6 + mov dph, r7 + + /* Dump the stack contents after they have + * been restored to IRAM + */ #ifdef CONFIG_SWITCH_FRAME_DUMP + push dpl + push dph lcall _up_dumpstack + pop dph + pop dpl #endif - /* Then restore the context from the stack */ + /* Get the pointer to the register save area */ + + mov a, #FRAME_SIZE + add a, dpl + mov dpl, a + clr a + addc a, dph + mov dph, a + + /* Restore registers from the register save area */ + + lcall _up_restoreregisters + + /* Restore registers from the new stack */ - pop _bp - pop psw - pop ar1 - pop ar0 - pop ar7 - pop ar6 - pop ar5 - pop ar4 - pop ar3 - pop ar2 - pop b pop dph pop dpl @@ -197,8 +284,8 @@ void up_restorecontext(FAR struct xcptcontext *context) __naked sjmp 00004$ 00003$: setb ie.7 - 00004$: + 00004$: pop acc ret _endasm; diff --git a/arch/pjrc-8051/src/up_savecontext.c b/arch/pjrc-8051/src/up_savecontext.c index 9631c2a11f..346f9271d6 100644 --- a/arch/pjrc-8051/src/up_savecontext.c +++ b/arch/pjrc-8051/src/up_savecontext.c @@ -65,10 +65,134 @@ * Private Functions **************************************************************************/ +/************************************************************************** + * Name: up_savestack + * + * Description: + * Save the entire interrupt stack contents in the provided context + * structure. + * + * Inputs: + * context - the context structure in which to save the stack info + * + * Return: + * None + * + * Assumptions: + * - Interrupts are disabled + * + **************************************************************************/ + +static void up_savestack(FAR struct xcptcontext *context, ubyte tos) +{ + /* Copy the current stack frame from internal RAM to XRAM. */ + + ubyte nbytes = tos - (STACK_BASE-1); + NEAR ubyte *src = (NEAR ubyte*)STACK_BASE; + FAR ubyte *dest = context->stack; + + context->nbytes = nbytes; + while (nbytes--) + { + *dest++ = *src++; + } +} + +/************************************************************************** + * Name: up_saveregs + * + * Description: + * Save the interrupt registers into the TCB. + * + * Inputs: + * context - the context structure in which to save the register info + * + * Return: + * None + * + * Assumptions: + * - Interrupts are disabled + * + **************************************************************************/ + +static void up_saveregs(FAR struct xcptcontext *context, ubyte tos) +{ + /* Copy the irq register save area into the TCB */ + + FAR ubyte *src = g_irqregs; + FAR ubyte *dest = context->regs; + ubyte nbytes = REGS_SIZE; + + while (nbytes--) + { + *dest++ = *src++; + } +} + /************************************************************************** * Public Functions **************************************************************************/ +/************************************************************************** + * Name: up_saveregisters + * + * Description: + * Save the current registers in the context save area. This function + * is called from up_savecontext (below) and also from interrupt + * handling logic. + * + * Note that this function does not save: + * a, dptr, ie - these are saved in the stack area + * sp - this can be inferred from g_irqtos or struct xcptontext.nbytes. + * + * Inputs: + * regs - the context register array in which to save the register info + * + * Return: + * None + * + **************************************************************************/ + +void up_saveregisters(FAR ubyte *regs) _naked +{ + _asm + mov a, b + movx @dptr, a + inc dptr + mov a, r2 + movx @dptr, a + inc dptr + mov a, r3 + movx @dptr, a + inc dptr + mov a, r4 + movx @dptr, a + inc dptr + mov a, r5 + movx @dptr, a + inc dptr + mov a, r6 + movx @dptr, a + inc dptr + mov a, r7 + movx @dptr, a + inc dptr + mov a, r0 + movx @dptr, a + inc dptr + mov a, r1 + movx @dptr, a + inc dptr + mov a, psw + movx @dptr, a + clr psw + inc dptr + mov a, _bp + movx @dptr, a + ret + _endasm; +} + /************************************************************************** * Name: up_savecontext * @@ -89,8 +213,14 @@ ubyte up_savecontext(FAR struct xcptcontext *context) _naked { _asm /* Create the stack frame that we want when it is time to restore - * this* context. The return address will be the return address + * this context. The return address will be the return address * of this function, the return value will be zero. + * + * ... + * return address (2 bytes, already on the stack) + * register a=0 (1 byte) + * register ie (1 byte) + * register dptr (2 bytes) */ clr a @@ -100,42 +230,95 @@ ubyte up_savecontext(FAR struct xcptcontext *context) _naked push acc /* DPL = 1 */ clr a push acc /* DPH = 0 */ - push b - push ar2 - push ar3 - push ar4 - push ar5 - push ar6 - push ar7 - push ar0 - push ar1 - push psw - clr psw - push _bp - /* Disable interrupts while we create a snapshot of the stack */ + /* Dump the stack contents before they are occupied into XRAM */ + +#ifdef CONFIG_SWITCH_FRAME_DUMP + push dpl + push dph + lcall _up_dumpstack + pop dph + pop dpl +#endif + /* Disable interrupts while we create a snapshot of the stack + * and registers. At this point, we have 5 bytes on the stack + * to account for. + */ push ie mov ea, 0 - /* Now copy the current stack frame (including the saved execution - * context) from internal RAM to XRAM. + /* Save the registers in the context save area */ + + push dpl + push dph + mov a, #XCPT_REGS + add a, dpl + mov dpl, a + clr a + addc a, dph + mov dph, a + lcall _up_saveregisters + pop dph + pop dpl + +#ifdef CONFIG_SWITCH_FRAME_DUMP + /* Save the address of the context structure. We will + * need this later to dump the saved frame. Now we have + * 7 bytes on the stack to account for. */ - push sp + push dpl + push dph + + /* Push the top of frame stack pointer. We need to + * decrement the current SP value by three to account + * for dpst+IE on the stack above the end of the frame. + */ + + mov a, sp + subb a, #3 +#else + /* Push the top of frame stack pointer. We need to + * decrement the current stack pointer by one to account + * for IE that we saved on the stack. + */ + + mov a, sp + dec a +#endif + push acc + + /* Copy the current stack frame from internal RAM to XRAM. */ + lcall _up_savestack pop acc + /* Dump the contents of the saved frame after it has been + * copied from memory/registers. + */ + +#ifdef CONFIG_SWITCH_FRAME_DUMP + pop dph + pop dpl + push dpl + push dph + lcall _up_dumpframe + pop dph + pop dpl + lcall _up_dumpstack +#endif + /* Restore the interrupt state */ pop ie /* Now that we have a snapshot of the desired stack frame saved, - * restore the correct stackpointer. + * we can release the stack frame (all but the return address) */ mov a, sp - subb a, #15 + subb a, #4 mov sp, a mov dpl,#0 ret @@ -143,14 +326,16 @@ ubyte up_savecontext(FAR struct xcptcontext *context) _naked } /************************************************************************** - * Name: up_savestack + * Name: up_saveirqcontext * * Description: - * Save the entire interrupt stack contents in the provided context - * structure. + * The interrupt context was saved in g_irqtos and g_irqregs when the + * interrupt was taken. If a context switch from the interrupted task + * will be made at the interrupt level, then these saved values must be + * copied into the TCB. * * Inputs: - * context - the context structure in which to save the stack info + * context - the structure in which to save the context info * * Return: * None @@ -160,19 +345,17 @@ ubyte up_savecontext(FAR struct xcptcontext *context) _naked * **************************************************************************/ -void up_savestack(FAR struct xcptcontext *context, ubyte tos) +void up_saveirqcontext(FAR struct xcptcontext *context) { - /* Now copy the current stack frame (including the saved execution - * context) from internal RAM to XRAM. - */ + /* Save the number of bytes in the stack */ - ubyte nbytes = tos - (STACK_BASE-1); - NEAR ubyte *src = (NEAR ubyte*)STACK_BASE; - FAR ubyte *dest = context->stack; + context->nbytes = g_irqtos - (STACK_BASE-1); - context->nbytes = nbytes; - while (nbytes--) - { - *dest++ = *src++; - } + /* Copy the current stack frame from internal RAM to XRAM. */ + + up_savestack(context, g_irqtos); + + /* Copy the saved registers into the TCB */ + + up_saveregisters(context->regs); } diff --git a/arch/pjrc-8051/src/up_unblocktask.c b/arch/pjrc-8051/src/up_unblocktask.c index 3f09d7ce5a..005e74e545 100644 --- a/arch/pjrc-8051/src/up_unblocktask.c +++ b/arch/pjrc-8051/src/up_unblocktask.c @@ -122,7 +122,7 @@ void up_unblock_task(FAR _TCB *tcb) * Just copy the current stack into the OLD rtcb. */ - up_savestack(&rtcb->xcp, g_irqtos); + up_saveirqcontext(&rtcb->xcp); /* Restore the exception context of the rtcb at the (new) head * of the g_readytorun task list. diff --git a/sched/task_setup.c b/sched/task_setup.c index 3573e72d9f..744f5fbf48 100644 --- a/sched/task_setup.c +++ b/sched/task_setup.c @@ -64,7 +64,7 @@ /* This is the name for un-named tasks */ -static FAR char g_noname[] = "no name"; +static const char g_noname[] = "no name"; /************************************************************ * Private Function Prototypes @@ -247,7 +247,7 @@ STATUS task_argsetup(FAR _TCB *tcb, const char *name, if (!name) { - name = g_noname; + name = (char *)g_noname; } /* copy the name into the TCB */ @@ -260,7 +260,7 @@ STATUS task_argsetup(FAR _TCB *tcb, const char *name, #if CONFIG_TASK_NAME_SIZE > 0 tcb->argv[0] = tcb->name; #else - tcb->argv[0] = g_noname; + tcb->argv[0] = (char *)g_noname; #endif /* For pthreads, args are strictly pass-by-value; the char* @@ -294,7 +294,7 @@ STATUS task_argsetup(FAR _TCB *tcb, const char *name, /* And just copy the argument. For pthreads, there * is really only a single argument, argv[0]. It is - * copy as a value -- NOT duplicated. + * copied as a value -- NOT duplicated. */ i = 2;