git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@586 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
gdisirio 2009-01-06 09:18:24 +00:00
parent a1f4ecfe08
commit fee14cb4ce
3 changed files with 399 additions and 352 deletions

View File

@ -1,180 +1,174 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <ch.h> /**
#include <nvic.h> * @addtogroup ARMCM3_CORE
* @{
/* */
* System idle thread loop.
*/ #include <ch.h>
__attribute__((weak)) #include <nvic.h>
void _idle(void *p) {
/**
while (TRUE) { * The default implementation of this function is void so no messages are
#if ENABLE_WFI_IDLE != 0 * actually printed.
asm volatile ("wfi"); * @note The function is declared as a weak symbol, it is possible to redefine
#endif * it in your application code.
} * @param msg pointer to the message string
} */
__attribute__((weak))
/* void sys_puts(char *msg) {
* System console message (not implemented). }
*/
__attribute__((weak)) void sys_halt(void) {
void chSysPuts(char *msg) {
} asm volatile ("cpsid i");
while(TRUE) {
/* }
* System halt. }
*/
__attribute__((naked, weak)) /**
void chSysHalt(void) { * Start a thread by invoking its work function.
* If the work function returns @p chThdExit() is automatically invoked. A call
asm volatile ("cpsid i"); * to @p chSysHalt() is added as failure check in the "impossible" case
while (TRUE) { * @p chThdExit() returns.
} */
} __attribute__((naked, weak))
void threadstart(void) {
/*
* Start a thread by invoking its work function. asm volatile ("blx r1 \n\t" \
* "bl chThdExit \n\t" \
* Start a thread by calling its work function. If the work function returns, "bl chSysHalt ");
* call chThdExit and chSysHalt. }
*/
__attribute__((naked, weak)) /**
void threadstart(void) { * System Timer vector.
* This interrupt is used as system tick.
asm volatile ("blx r1 \n\t" \ * @note The timer is initialized in the board setup code.
"bl chThdExit \n\t" \ */
"bl chSysHalt "); void SysTickVector(void) {
}
chSysIRQEnterI();
/* chSysLockI();
* System Timer vector. chSysTimerHandlerI();
*/ chSysUnlockI();
void SysTickVector(void) { chSysIRQExitI();
}
chSysIRQEnterI();
chSysLock(); /**
* The SVC vector is used for commanded context switch.
chSysTimerHandlerI(); */
__attribute__((naked))
chSysUnlock(); void SVCallVector(Thread *otp, Thread *ntp) {
chSysIRQExitI(); /* { r0 = otp, r1 = ntp } */
} /* get the BASEPRI in r3 */
/* get the PSP in r12 */
/* /* push the registers on the PSP stack */
* System invoked context switch. /* stores the modified PSP into the thread context */
*/ /* fetches the PSP position from the new thread context */
__attribute__((naked)) /* pop the registers from the PSP stack */
void SVCallVector(Thread *otp, Thread *ntp) { /* set the PSP from r12 */
/* { r0 = otp, r1 = ntp } */ /* set the BASEPRI from R3 */
/* get the BASEPRI in r3 */ #ifdef CH_CURRP_REGISTER_CACHE
/* get the PSP in r12 */ asm volatile ("mrs r3, BASEPRI \n\t" \
/* push the registers on the PSP stack */ "mrs r12, PSP \n\t" \
/* stores the modified PSP into the thread context */ "stmdb r12!, {r3-r6,r8-r11, lr} \n\t" \
/* fetches the PSP position from the new thread context */ "str r12, [r0, #16] \n\t" \
/* pop the registers from the PSP stack */ "ldr r12, [r1, #16] \n\t" \
/* set the PSP from r12 */ "ldmia r12!, {r3-r6,r8-r11, lr} \n\t" \
/* set the BASEPRI from R3 */ "msr PSP, r12 \n\t" \
#ifdef CH_CURRP_REGISTER_CACHE "msr BASEPRI, r3 \n\t" \
asm volatile ("mrs r3, BASEPRI \n\t" \ "bx lr ");
"mrs r12, PSP \n\t" \ #else
"stmdb r12!, {r3-r6,r8-r11, lr} \n\t" \ asm volatile ("mrs r3, BASEPRI \n\t" \
"str r12, [r0, #16] \n\t" \ "mrs r12, PSP \n\t" \
"ldr r12, [r1, #16] \n\t" \ "stmdb r12!, {r3-r11, lr} \n\t" \
"ldmia r12!, {r3-r6,r8-r11, lr} \n\t" \ "str r12, [r0, #16] \n\t" \
"msr PSP, r12 \n\t" \ "ldr r12, [r1, #16] \n\t" \
"msr BASEPRI, r3 \n\t" \ "ldmia r12!, {r3-r11, lr} \n\t" \
"bx lr "); "msr PSP, r12 \n\t" \
#else "msr BASEPRI, r3 \n\t" \
asm volatile ("mrs r3, BASEPRI \n\t" \ "bx lr ");
"mrs r12, PSP \n\t" \ #endif
"stmdb r12!, {r3-r11, lr} \n\t" \ }
"str r12, [r0, #16] \n\t" \
"ldr r12, [r1, #16] \n\t" \ #ifdef CH_CURRP_REGISTER_CACHE
"ldmia r12!, {r3-r11, lr} \n\t" \ #define PUSH_CONTEXT(sp) { \
"msr PSP, r12 \n\t" \ register uint32_t tmp asm ("r3") = BASEPRI_USER; \
"msr BASEPRI, r3 \n\t" \ asm volatile ("mrs %0, PSP \n\t" \
"bx lr "); "stmdb %0!, {r3-r6,r8-r11, lr}" : \
#endif "=r" (sp) : "r" (sp), "r" (tmp)); \
} }
#ifdef CH_CURRP_REGISTER_CACHE #define POP_CONTEXT(sp) { \
#define PUSH_CONTEXT(sp) { \ asm volatile ("ldmia %0!, {r3-r6,r8-r11, lr} \n\t" \
register uint32_t tmp asm ("r3") = BASEPRI_USER; \ "msr PSP, %0 \n\t" \
asm volatile ("mrs %0, PSP \n\t" \ "msr BASEPRI, r3 \n\t" \
"stmdb %0!, {r3-r6,r8-r11, lr}" : \ "bx lr" : "=r" (sp) : "r" (sp)); \
"=r" (sp) : "r" (sp), "r" (tmp)); \ }
} #else
#define PUSH_CONTEXT(sp) { \
#define POP_CONTEXT(sp) { \ register uint32_t tmp asm ("r3") = BASEPRI_USER; \
asm volatile ("ldmia %0!, {r3-r6,r8-r11, lr} \n\t" \ asm volatile ("mrs %0, PSP \n\t" \
"msr PSP, %0 \n\t" \ "stmdb %0!, {r3-r11,lr}" : \
"msr BASEPRI, r3 \n\t" \ "=r" (sp) : "r" (sp), "r" (tmp)); \
"bx lr" : "=r" (sp) : "r" (sp)); \ }
}
#else #define POP_CONTEXT(sp) { \
#define PUSH_CONTEXT(sp) { \ asm volatile ("ldmia %0!, {r3-r11, lr} \n\t" \
register uint32_t tmp asm ("r3") = BASEPRI_USER; \ "msr PSP, %0 \n\t" \
asm volatile ("mrs %0, PSP \n\t" \ "msr BASEPRI, r3 \n\t" \
"stmdb %0!, {r3-r11,lr}" : \ "bx lr" : "=r" (sp) : "r" (sp)); \
"=r" (sp) : "r" (sp), "r" (tmp)); \ }
} #endif
#define POP_CONTEXT(sp) { \ /**
asm volatile ("ldmia %0!, {r3-r11, lr} \n\t" \ * Preemption invoked context switch.
"msr PSP, %0 \n\t" \ */
"msr BASEPRI, r3 \n\t" \ __attribute__((naked))
"bx lr" : "=r" (sp) : "r" (sp)); \ void PendSVVector(void) {
} Thread *otp;
#endif register struct intctx *sp_thd asm("r12");
/* chSysLockI();
* Preemption invoked context switch. asm volatile ("push {lr}");
*/ if (!chSchRescRequiredI()) {
__attribute__((naked)) chSysUnlockI();
void PendSVVector(void) { asm volatile ("pop {pc}");
Thread *otp; }
register struct intctx *sp_thd asm("r12"); asm volatile ("pop {lr}");
chSysLock(); PUSH_CONTEXT(sp_thd);
asm volatile ("push {lr}");
if (!chSchRescRequiredI()) { (otp = currp)->p_ctx.r13 = sp_thd;
chSysUnlock(); (currp = fifo_remove((void *)&rlist))->p_state = PRCURR;
asm volatile ("pop {pc}"); chSchReadyI(otp);
} #ifdef CH_USE_ROUNDROBIN
asm volatile ("pop {lr}"); /* set the round-robin time quantum */
rlist.r_preempt = CH_TIME_QUANTUM;
PUSH_CONTEXT(sp_thd); #endif
#ifdef CH_USE_TRACE
(otp = currp)->p_ctx.r13 = sp_thd; chDbgTrace(otp, currp);
(currp = fifo_remove((void *)&rlist))->p_state = PRCURR; #endif
chSchReadyI(otp); sp_thd = currp->p_ctx.r13;
#ifdef CH_USE_ROUNDROBIN
/* set the round-robin time quantum */ POP_CONTEXT(sp_thd);
rlist.r_preempt = CH_TIME_QUANTUM; }
#endif
#ifdef CH_USE_TRACE /** @} */
chDbgTrace(otp, currp);
#endif
sp_thd = currp->p_ctx.r13;
POP_CONTEXT(sp_thd);
}

View File

@ -1,168 +1,218 @@
/* /*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT. This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful, ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _CHCORE_H_ /**
#define _CHCORE_H_ * @addtogroup ARMCM3_CORE
* @{
/* */
* Port-related configuration parameters.
*/ #ifndef _CHCORE_H_
#ifndef BASEPRI_USER #define _CHCORE_H_
#define BASEPRI_USER 0 /* User level BASEPRI, 0 = disabled. */
#endif /*
* Port-related configuration parameters.
#ifndef BASEPRI_KERNEL */
#define BASEPRI_KERNEL 0x10 /* BASEPRI level within kernel lock. */ #ifndef BASEPRI_USER
#endif #define BASEPRI_USER 0 /* User level BASEPRI, 0 = disabled. */
#endif
#ifndef ENABLE_WFI_IDLE
#define ENABLE_WFI_IDLE 0 /* Enables the use of the WFI ins. */ #ifndef BASEPRI_KERNEL
#endif #define BASEPRI_KERNEL 0x10 /* BASEPRI level within kernel lock. */
#endif
/*
* Macro defining the ARM Cortex-M3 architecture. #ifndef ENABLE_WFI_IDLE
*/ #define ENABLE_WFI_IDLE 0 /* Enables the use of the WFI ins. */
#define CH_ARCHITECTURE_ARMCM3 #endif
/* /**
* 32 bit stack alignment. * Macro defining the ARM Cortex-M3 architecture.
*/ */
typedef uint32_t stkalign_t; #define CH_ARCHITECTURE_ARMCM3
/* /**
* Generic ARM register. * 32 bit stack alignment.
*/ */
typedef void *regarm_t; typedef uint32_t stkalign_t;
/* /**
* Interrupt saved context, empty in this architecture. * Generic ARM register.
*/ */
struct extctx { typedef void *regarm_t;
};
/**
/* * Interrupt saved context, empty in this architecture.
* System saved context. */
*/ struct extctx {
struct intctx { };
regarm_t basepri;
regarm_t r4; /**
regarm_t r5; * System saved context.
regarm_t r6; * This structure represents the inner stack frame during a context switching.
#ifndef CH_CURRP_REGISTER_CACHE */
regarm_t r7; struct intctx {
#endif regarm_t basepri;
regarm_t r8; regarm_t r4;
regarm_t r9; regarm_t r5;
regarm_t r10; regarm_t r6;
regarm_t r11; #ifndef CH_CURRP_REGISTER_CACHE
regarm_t lr_exc; regarm_t r7;
regarm_t r0; #endif
regarm_t r1; regarm_t r8;
regarm_t r2; regarm_t r9;
regarm_t r3; regarm_t r10;
regarm_t r12; regarm_t r11;
regarm_t lr_thd; regarm_t lr_exc;
regarm_t pc; regarm_t r0;
regarm_t xpsr; regarm_t r1;
}; regarm_t r2;
regarm_t r3;
/* regarm_t r12;
* Port dependent part of the Thread structure, you may add fields in regarm_t lr_thd;
* this structure. regarm_t pc;
*/ regarm_t xpsr;
typedef struct { };
struct intctx *r13;
} Context; /**
* Cortex-M3 context structure.
/* */
* Platform dependent part of the \p chThdCreate() API. typedef struct {
* struct intctx *r13;
* The top of the workspace is used for the intctx datastructure. } Context;
*
*/ /**
#define SETUP_CONTEXT(workspace, wsize, pf, arg) { \ * Platform dependent part of the @p chThdInit() API.
tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \ * This code usually setup the context switching frame represented by a
wsize - \ * @p intctx structure.
sizeof(struct intctx)); \ */
tp->p_ctx.r13->basepri = BASEPRI_USER; \ #define SETUP_CONTEXT(workspace, wsize, pf, arg) { \
tp->p_ctx.r13->lr_exc = (regarm_t)0xFFFFFFFD; \ tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \
tp->p_ctx.r13->r0 = arg; \ wsize - \
tp->p_ctx.r13->r1 = pf; \ sizeof(struct intctx)); \
tp->p_ctx.r13->pc = threadstart; \ tp->p_ctx.r13->basepri = BASEPRI_USER; \
tp->p_ctx.r13->xpsr = (regarm_t)0x01000000; \ tp->p_ctx.r13->lr_exc = (regarm_t)0xFFFFFFFD; \
} tp->p_ctx.r13->r0 = arg; \
tp->p_ctx.r13->r1 = pf; \
#define chSysLock() { \ tp->p_ctx.r13->pc = threadstart; \
register uint32_t tmp asm ("r3") = BASEPRI_KERNEL; \ tp->p_ctx.r13->xpsr = (regarm_t)0x01000000; \
asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \ }
}
#define chSysUnlock() { \ /**
register uint32_t tmp asm ("r3") = BASEPRI_USER; \ * The default idle thread implementation requires no extra stack space in
asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \ * this port.
} */
#define chSysEnable() { \ #ifndef IDLE_THREAD_STACK_SIZE
register uint32_t tmp asm ("r3") = BASEPRI_USER; \ #define IDLE_THREAD_STACK_SIZE 0
asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \ #endif
}
#define chSysSwitchI(otp, ntp) { \ /**
register Thread *_otp asm ("r0") = (otp); \ * This port requires no extra stack space for interrupt handling.
register Thread *_ntp asm ("r1") = (ntp); \ */
asm volatile ("svc #0" : : "r" (_otp), "r" (_ntp)); \ #ifndef INT_REQUIRED_STACK
} #define INT_REQUIRED_STACK 0
#endif
#ifndef INT_REQUIRED_STACK
#define INT_REQUIRED_STACK 0 /* NOTE: Always safe for this port. */ /**
#endif * Enforces a correct alignment for a stack area size value.
*/
/* #define STACK_ALIGN(n) ((((n) - 1) | sizeof(stkalign_t)) + 1)
* Enforces a 32 bit alignment for a stack area size value.
*/ /**
#define STACK_ALIGN(n) ((((n) - 1) | sizeof(stkalign_t)) + 1) * Computes the thread working area global size.
*/
#define THD_WA_SIZE(n) STACK_ALIGN(sizeof(Thread) + \ #define THD_WA_SIZE(n) StackAlign(sizeof(Thread) + \
sizeof(struct intctx) + \ sizeof(struct intctx) + \
sizeof(struct extctx) + \ sizeof(struct extctx) + \
(n) + \ (n) + (INT_REQUIRED_STACK))
INT_REQUIRED_STACK)
/**
#define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)]; * Macro used to allocate a thread working area aligned as both position and
* size.
/* called on each interrupt entry, currently nothing is done */ */
#define chSysIRQEnterI() #define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)];
/* called on each interrupt exit, pends a supervisor handler for /**
* execution after all higher priority interrupts; PendSVVector() */ * IRQ prologue code, inserted at the start of all IRQ handlers enabled to
#define chSysIRQExitI() { \ * invoke system APIs.
SCB_ICSR = ICSR_PENDSVSET; \ */
} #define SYS_IRQ_PROLOGUE()
#define IDLE_THREAD_STACK_SIZE 0 /**
* IRQ epilogue code, inserted at the end of all IRQ handlers enabled to
#ifdef __cplusplus * invoke system APIs.
extern "C" { */
#endif #define SYS_IRQ_EPILOGUE() { \
void _idle(void *p) __attribute__((weak, noreturn)); SCB_ICSR = ICSR_PENDSVSET; \
void chSysHalt(void); }
void chSysPuts(char *msg);
void threadstart(void); /**
#ifdef __cplusplus * This port function is implemented as inlined code for performance reasons.
} */
#endif #define sys_disable() { \
register uint32_t tmp asm ("r3") = BASEPRI_KERNEL; \
#endif /* _CHCORE_H_ */ asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \
}
/**
* This port function is implemented as inlined code for performance reasons.
*/
#define sys_enable() { \
register uint32_t tmp asm ("r3") = BASEPRI_USER; \
asm volatile ("msr BASEPRI, %0" : : "r" (tmp)); \
}
/**
* This port function is implemented as inlined code for performance reasons.
*/
#define sys_disable_from_isr() sys_disable()
/**
* This port function is implemented as inlined code for performance reasons.
*/
#define sys_enable_from_isr() sys_enable()
#define sys_wait_for_interrupt() { \
asm volatile ("wfi"); \
}
/**
* This port function is implemented as inlined code for performance reasons.
*/
#define sys_switch(otp, ntp) { \
register Thread *_otp asm ("r0") = (otp); \
register Thread *_ntp asm ("r1") = (ntp); \
asm volatile ("svc #0" : : "r" (_otp), "r" (_ntp)); \
}
/**
* IRQ handler function modifier.
*/
#define SYS_IRQ_HANDLER
#ifdef __cplusplus
extern "C" {
#endif
void sys_puts(char *msg);
void sys_halt(void);
#ifdef __cplusplus
}
#endif
#endif /* _CHCORE_H_ */
/** @} */

View File

@ -62,12 +62,11 @@ typedef struct {
} Context; } Context;
/** /**
* Platform dependent part of the \p chThdCreate() API. * Platform dependent part of the @p chThdCreate() API.
* This code usually setup the context switching frame represented by a * This code usually setup the context switching frame represented by a
* @p intctx structure. * @p intctx structure.
*/ */
#define SETUP_CONTEXT(workspace, wsize, pf, arg) \ #define SETUP_CONTEXT(workspace, wsize, pf, arg) { \
{ \
} }
/** /**
@ -76,7 +75,9 @@ typedef struct {
* thread should take no more space than those reserved * thread should take no more space than those reserved
* by @p INT_REQUIRED_STACK. * by @p INT_REQUIRED_STACK.
*/ */
#ifndef IDLE_THREAD_STACK_SIZE
#define IDLE_THREAD_STACK_SIZE 0 #define IDLE_THREAD_STACK_SIZE 0
#endif
/** /**
* Per-thread stack overhead for interrupts servicing, it is used in the * Per-thread stack overhead for interrupts servicing, it is used in the
@ -85,7 +86,9 @@ typedef struct {
* interrupt stack and the stack space between @p intctx and @p extctx is * interrupt stack and the stack space between @p intctx and @p extctx is
* known to be zero. * known to be zero.
*/ */
#ifndef INT_REQUIRED_STACK
#define INT_REQUIRED_STACK 0 #define INT_REQUIRED_STACK 0
#endif
/** /**
* Enforces a correct alignment for a stack area size value. * Enforces a correct alignment for a stack area size value.
@ -113,7 +116,7 @@ typedef struct {
#define SYS_IRQ_PROLOGUE() #define SYS_IRQ_PROLOGUE()
/** /**
* IRQ epilogue code, inserted at the start of all IRQ handlers enabled to * IRQ epilogue code, inserted at the end of all IRQ handlers enabled to
* invoke system APIs. * invoke system APIs.
*/ */
#define SYS_IRQ_EPILOGUE() #define SYS_IRQ_EPILOGUE()