8051 integration

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@59 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2007-03-13 14:08:18 +00:00
parent d2b2a82171
commit b1598a0052
19 changed files with 728 additions and 162 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

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

View File

@ -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

View File

@ -38,6 +38,7 @@
************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include "up_internal.h"
/************************************************************

View File

@ -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

View File

@ -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
}

View File

@ -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
************************************************************/

View File

@ -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;
}

View File

@ -41,6 +41,7 @@
**************************************************************************/
#include <nuttx/config.h>
#include <arch/irq.h>
#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)

View File

@ -43,6 +43,8 @@
#include <8052.h>
#include "up_internal.h"
#include <debug.h>
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];
}
}

View File

@ -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 */

View File

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

View File

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

View File

@ -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;

View File

@ -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);
}

View File

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

View File

@ -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;