Performance optimization (not complete yet).

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1739 35acf78f-673a-0410-8e92-d51de3d6d3f4
master
gdisirio 2010-03-14 09:13:21 +00:00
parent f1bb1a01ca
commit 075b89133e
18 changed files with 366 additions and 264 deletions

View File

@ -1,6 +1,6 @@
<ApplicationBuild Header="ch" Extern=".\ch.rapp" Path=".\ch.rapp" OutputFile="..\STM8S-STM8S208-RC/bin\ch.aof" sate="98" >
<Group Header="kernel" Marker="-1" OutputFile="" sate="0" >
<ApplicationBuild Header="ch" Extern=".\ch.rapp" Path=".\ch.rapp" OutputFile="..\STM8S-STM8S208-RC/bin\ch.aof" sate="2" >
<Group Header="kernel" Marker="-1" OutputFile="" sate="96" >
<NodeC Path="..\..\os\kernel\src\chcond.c" Header="chcond.c" Marker="-1" OutputFile="..\STM8S-STM8S208-RC/bin\chcond.obj" sate="0" />
<NodeC Path="..\..\os\kernel\src\chdebug.c" Header="chdebug.c" Marker="-1" OutputFile="..\STM8S-STM8S208-RC/bin\chdebug.obj" sate="0" />
<NodeC Path="..\..\os\kernel\src\chevents.c" Header="chevents.c" Marker="-1" OutputFile="..\STM8S-STM8S208-RC/bin\chevents.obj" sate="0" />

View File

@ -1,4 +1,4 @@
<Project Header="Project 'ch'" Path=".\ch.rprj" Project="Yes" OutputFile="" sate="96" ActiveApp="ch" >
<ApplicationBuild Header="ch" Extern=".\ch.rapp" Path=".\ch.rapp" OutputFile="..\STM8S-STM8S208-RC/bin\ch.aof" sate="98" />
<ApplicationBuild Header="ch" Extern=".\ch.rapp" Path=".\ch.rapp" OutputFile="..\STM8S-STM8S208-RC/bin\ch.aof" sate="2" />
</Project>

View File

@ -5,9 +5,12 @@ Settings: CCLK=48, MAMCR=2, MAMTIM=3 (3 wait states)
*** ChibiOS/RT test suite
***
*** Kernel: 1.3.8unstable
*** Architecture: ARM7TDMI
*** Kernel: 1.5.4unstable
*** GCC Version: 4.4.2
*** Architecture: ARM
*** Core Variant: ARM7TDMI
*** Platform: LPC214x
*** Test Board: Olimex LCP-P2148
----------------------------------------------------------------------------
--- Test Case 1.1 (Threads, enqueuing test #1)
@ -89,31 +92,31 @@ Settings: CCLK=48, MAMCR=2, MAMTIM=3 (3 wait states)
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.1 (Benchmark, messages #1)
--- Score : 144506 msgs/S, 289012 ctxswc/S
--- Score : 148086 msgs/S, 296172 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.2 (Benchmark, messages #2)
--- Score : 114706 msgs/S, 229412 ctxswc/S
--- Score : 116100 msgs/S, 232200 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.3 (Benchmark, messages #3)
--- Score : 114706 msgs/S, 229412 ctxswc/S
--- Score : 116100 msgs/S, 232200 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.4 (Benchmark, context switch)
--- Score : 501520 ctxswc/S
--- Score : 509520 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.5 (Benchmark, threads, full cycle)
--- Score : 107731 threads/S
--- Score : 87287 threads/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.6 (Benchmark, threads, create only)
--- Score : 150417 threads/S
--- Score : 122334 threads/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.7 (Benchmark, mass reschedulation, 5 threads)
--- Score : 36514 reschedulations/S, 219084 ctxswc/S
--- Score : 36238 reschedulations/S, 217428 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.8 (Benchmark, round robin context switching)
@ -121,7 +124,7 @@ Settings: CCLK=48, MAMCR=2, MAMTIM=3 (3 wait states)
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.9 (Benchmark, I/O Queues throughput)
--- Score : 357308 bytes/S
--- Score : 357312 bytes/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.10 (Benchmark, virtual timers set/reset)
@ -133,12 +136,12 @@ Settings: CCLK=48, MAMCR=2, MAMTIM=3 (3 wait states)
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.12 (Benchmark, mutexes lock/unlock)
--- Score : 380408 lock+unlock/S
--- Score : 383452 lock+unlock/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.13 (Benchmark, RAM footprint)
--- System: 324 bytes
--- Thread: 60 bytes
--- System: 356 bytes
--- Thread: 68 bytes
--- Timer : 20 bytes
--- Semaph: 12 bytes
--- EventS: 4 bytes

View File

@ -5,9 +5,12 @@ Settings: CCLK=48, MAMCR=2, MAMTIM=3 (3 wait states)
*** ChibiOS/RT test suite
***
*** Kernel: 1.3.5unstable
*** Architecture: ARM7TDMI
*** Kernel: 1.5.4unstable
*** GCC Version: 4.4.2
*** Architecture: ARM
*** Core Variant: ARM7TDMI
*** Platform: LPC214x
*** Test Board: Olimex LCP-P2148
----------------------------------------------------------------------------
--- Test Case 1.1 (Threads, enqueuing test #1)
@ -89,56 +92,56 @@ Settings: CCLK=48, MAMCR=2, MAMTIM=3 (3 wait states)
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.1 (Benchmark, messages #1)
--- Score : 104991 msgs/S, 209982 ctxswc/S
--- Score : 106455 msgs/S, 212910 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.2 (Benchmark, messages #2)
--- Score : 87494 msgs/S, 174988 ctxswc/S
--- Score : 88190 msgs/S, 176380 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.3 (Benchmark, messages #3)
--- Score : 87494 msgs/S, 174988 ctxswc/S
--- Score : 88190 msgs/S, 176380 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.4 (Benchmark, context switch)
--- Score : 410488 ctxswc/S
--- Score : 412496 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.5 (Benchmark, threads, full cycle)
--- Score : 87176 threads/S
--- Score : 67800 threads/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.6 (Benchmark, threads, create only)
--- Score : 120330 threads/S
--- Score : 100842 threads/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.7 (Benchmark, mass reschedulation, 5 threads)
--- Score : 29561 reschedulations/S, 177366 ctxswc/S
--- Score : 29488 reschedulations/S, 176928 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.8 (Benchmark, round robin context switching)
--- Score : 257160 reschedulations/S, 257160 ctxswc/S
--- Score : 257308 reschedulations/S, 257308 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.9 (Benchmark, I/O Queues throughput)
--- Score : 265328 bytes/S
--- Score : 265488 bytes/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.10 (Benchmark, virtual timers set/reset)
--- Score : 303348 timers/S
--- Score : 326324 timers/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.11 (Benchmark, semaphores wait/signal)
--- Score : 353248 wait+signal/S
--- Score : 353452 wait+signal/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.12 (Benchmark, mutexes lock/unlock)
--- Score : 249168 lock+unlock/S
--- Score : 255980 lock+unlock/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.13 (Benchmark, RAM footprint)
--- System: 324 bytes
--- Thread: 60 bytes
--- System: 356 bytes
--- Thread: 68 bytes
--- Timer : 20 bytes
--- Semaph: 12 bytes
--- EventS: 4 bytes

View File

@ -5,7 +5,7 @@ Settings: SYSCLK=72, ACR=0x12 (2 wait states)
*** ChibiOS/RT test suite
***
*** Kernel: 1.5.3unstable
*** Kernel: 1.5.4unstable
*** GCC Version: 4.4.2
*** Architecture: ARM
*** Core Variant: Cortex-M3
@ -92,31 +92,31 @@ Settings: SYSCLK=72, ACR=0x12 (2 wait states)
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.1 (Benchmark, messages #1)
--- Score : 223892 msgs/S, 447784 ctxswc/S
--- Score : 226004 msgs/S, 452008 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.2 (Benchmark, messages #2)
--- Score : 187652 msgs/S, 375304 ctxswc/S
--- Score : 188141 msgs/S, 376282 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.3 (Benchmark, messages #3)
--- Score : 187652 msgs/S, 375304 ctxswc/S
--- Score : 188141 msgs/S, 376282 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.4 (Benchmark, context switch)
--- Score : 696944 ctxswc/S
--- Score : 707232 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.5 (Benchmark, threads, full cycle)
--- Score : 146984 threads/S
--- Score : 147284 threads/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.6 (Benchmark, threads, create only)
--- Score : 203030 threads/S
--- Score : 204767 threads/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.7 (Benchmark, mass reschedulation, 5 threads)
--- Score : 56954 reschedulations/S, 341724 ctxswc/S
--- Score : 57181 reschedulations/S, 343086 ctxswc/S
--- Result: SUCCESS
----------------------------------------------------------------------------
--- Test Case 11.8 (Benchmark, round robin context switching)

View File

@ -147,7 +147,7 @@ extern "C" {
#if CH_DBG_ENABLE_TRACE
extern TraceBuffer trace_buffer;
void trace_init(void);
void chDbgTrace(Thread *otp, Thread *ntp);
void chDbgTrace(Thread *ntp, Thread *otp);
#endif
#if CH_DBG_ENABLE_ASSERTS || CH_DBG_ENABLE_CHECKS || CH_DBG_ENABLE_STACK_CHECK
extern char *panic_msg;

View File

@ -40,10 +40,10 @@
/**
* @brief Performs a context switch.
*
* @param[in] otp the thread to be switched out
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
#define chSysSwitchI(otp, ntp) port_switch(otp, ntp)
#define chSysSwitchI(ntp, otp) port_switch(ntp, otp)
/**
* @brief Raises the system interrupt priority mask to the maximum level.

View File

@ -45,10 +45,10 @@ void trace_init(void) {
/**
* @brief Inserts in the circular debug trace buffer a context switch record.
*
* @param[in] otp the thread being switched out
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread being switched out
*/
void chDbgTrace(Thread *otp, Thread *ntp) {
void chDbgTrace(Thread *ntp, Thread *otp) {
trace_buffer.tb_ptr->cse_wtobjp = otp->p_u.wtobjp;
trace_buffer.tb_ptr->cse_time = chTimeNow();

View File

@ -90,8 +90,8 @@ void chSchGoSleepS(tstate_t newstate) {
#if CH_TIME_QUANTUM > 0
rlist.r_preempt = CH_TIME_QUANTUM;
#endif
chDbgTrace(otp, currp);
chSysSwitchI(otp, currp);
chDbgTrace(currp, otp);
chSysSwitchI(currp, otp);
}
/*
@ -185,8 +185,8 @@ void chSchWakeupS(Thread *ntp, msg_t msg) {
rlist.r_preempt = CH_TIME_QUANTUM;
#endif
(currp = ntp)->p_state = THD_STATE_CURRENT;
chDbgTrace(otp, ntp);
chSysSwitchI(otp, ntp);
chDbgTrace(ntp, otp);
chSysSwitchI(ntp, otp);
}
}
@ -204,8 +204,8 @@ void chSchDoRescheduleI(void) {
#if CH_TIME_QUANTUM > 0
rlist.r_preempt = CH_TIME_QUANTUM;
#endif
chDbgTrace(otp, currp);
chSysSwitchI(otp, currp);
chDbgTrace(currp, otp);
chSysSwitchI(currp, otp);
}
/**
@ -272,8 +272,8 @@ void chSchDoYieldS(void) {
#if CH_TIME_QUANTUM > 0
rlist.r_preempt = CH_TIME_QUANTUM;
#endif
chDbgTrace(otp, currp);
chSysSwitchI(otp, currp);
chDbgTrace(currp, otp);
chSysSwitchI(currp, otp);
}
}

View File

@ -80,8 +80,8 @@ void port_disable(void) {
}
/**
* @brief Disables the interrupt sources that are not supposed to preempt
* the kernel.
* @brief Disables the interrupt sources below kernel-level priority.
* @note Interrupt sources above kernel level remains enabled.
*/
void port_suspend(void) {
}
@ -93,7 +93,7 @@ void port_enable(void) {
}
/**
* @brief Enters an architecture-dependent halt mode.
* @brief Enters an architecture-dependent IRQ-waiting mode.
* @details The function is meant to return when an interrupt becomes pending.
* The simplest implementation is an empty function or macro but this
* would not take advantage of architecture-specific power saving
@ -123,10 +123,10 @@ void port_halt(void) {
* @note The implementation of this code affects <b>directly</b> the context
* switch performance so optimize here as much as you can.
*
* @param otp the thread to be switched out
* @param ntp the thread to be switched in
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
void port_switch(Thread *otp, Thread *ntp) {
void port_switch(Thread *ntp, Thread *otp) {
}
/** @} */

View File

@ -159,7 +159,7 @@ extern "C" {
void port_enable(void);
void port_wait_for_interrupt(void);
void port_halt(void);
void port_switch(Thread *otp, Thread *ntp);
void port_switch(Thread *ntp, Thread *otp);
#ifdef __cplusplus
}
#endif

View File

@ -20,6 +20,7 @@
/**
* @file ARM7/chcore.h
* @brief ARM7 architecture port macros and structures.
*
* @addtogroup ARM7_CORE
* @{
*/
@ -28,7 +29,7 @@
#define _CHCORE_H_
/**
* If enabled allows the idle thread to enter a low power mode.
* @brief If enabled allows the idle thread to enter a low power mode.
*/
#ifndef ENABLE_WFI_IDLE
#define ENABLE_WFI_IDLE 0
@ -36,12 +37,12 @@
#include <wfi.h>
/**
* Macro defining the ARM7 architecture.
* @brief Macro defining the ARM7 architecture.
*/
#define CH_ARCHITECTURE_ARM7
/**
* Name of the implemented architecture.
* @brief Name of the implemented architecture.
*/
#define CH_ARCHITECTURE_NAME "ARM"
@ -51,19 +52,20 @@
#define CH_CORE_VARIANT_NAME "ARM7TDMI"
/**
* 32 bit stack alignment.
* @brief 32 bit stack and memory alignment enforcement.
*/
typedef uint32_t stkalign_t;
/**
* Generic ARM register.
* @brief Generic ARM register.
*/
typedef void *regarm_t;
/** @cond never */
#if !defined(__DOXYGEN__)
/**
* This structure represents the stack frame saved during a preemption-capable
* interrupt handler.
* @brief Interrupt saved context.
* @details This structure represents the stack frame saved during a
* preemption-capable interrupt handler.
*/
struct extctx {
regarm_t spsr_irq;
@ -75,11 +77,13 @@ struct extctx {
regarm_t r12;
regarm_t lr_usr;
};
/** @endcond */
#endif
/** @cond never */
#if !defined(__DOXYGEN__)
/**
* This structure represents the inner stack frame during a context switching.
* @brief System saved context.
* @details This structure represents the inner stack frame during a context
* switching.
*/
struct intctx {
regarm_t r4;
@ -94,20 +98,21 @@ struct intctx {
regarm_t r11;
regarm_t lr;
};
/** @endcond */
#endif
/** @cond never */
#if !defined(__DOXYGEN__)
/**
* In the ARM7 port this structure contains just the copy of the user mode
* stack pointer.
* @brief ATM7 port context structure.
*/
struct context {
struct intctx *r13;
};
/** @endcond */
#endif
/**
* Platform dependent part of the @p chThdInit() API.
* @brief Platform dependent part of the @p chThdInit() API.
* @details This code usually setup the context switching frame represented
* by an @p intctx structure.
*/
#define SETUP_CONTEXT(workspace, wsize, pf, arg) { \
tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \
@ -119,29 +124,38 @@ struct context {
}
/**
* Stack size for the system idle thread.
* @brief Stack size for the system idle thread.
* @details This size depends on the idle thread implementation, usually
* the idle thread should take no more space than those reserved
* by @p INT_REQUIRED_STACK.
* @note In this port it is set to 4 because the idle thread does have
* a stack frame when compiling without optimizations.
*/
#ifndef IDLE_THREAD_STACK_SIZE
#define IDLE_THREAD_STACK_SIZE 0
#define IDLE_THREAD_STACK_SIZE 4
#endif
/**
* Per-thread stack overhead for interrupts servicing, it is used in the
* calculation of the correct working area size.
* In this port 0x10 is a safe value, it can be reduced after careful generated
* code analysis.
* @brief Per-thread stack overhead for interrupts servicing.
* @details This constant is used in the calculation of the correct working
* area size.
* This value can be zero on those architecture where there is a
* separate interrupt stack and the stack space between @p intctx and
* @p extctx is known to be zero.
* @note In this port 0x10 is a safe value, it can be reduced after careful
* analysis of the generated code.
*/
#ifndef INT_REQUIRED_STACK
#define INT_REQUIRED_STACK 0x10
#endif
/**
* Enforces a correct alignment for a stack area size value.
* @brief Enforces a correct alignment for a stack area size value.
*/
#define STACK_ALIGN(n) ((((n) - 1) | (sizeof(stkalign_t) - 1)) + 1)
/**
* Computes the thread working area global size.
* @brief Computes the thread working area global size.
*/
#define THD_WA_SIZE(n) STACK_ALIGN(sizeof(Thread) + \
sizeof(struct intctx) + \
@ -149,14 +163,16 @@ struct context {
(n) + (INT_REQUIRED_STACK))
/**
* Macro used to allocate a thread working area aligned as both position and
* size.
* @brief Static working area allocation.
* @details This macro is used to allocate a static thread working area
* aligned as both position and size.
*/
#define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)];
/**
* IRQ prologue code, inserted at the start of all IRQ handlers enabled to
* invoke system APIs.
* @brief IRQ prologue code.
* @details This macro must be inserted at the start of all IRQ handlers
* enabled to invoke system APIs.
* @note This macro has a different implementation depending if compiled in
* ARM or THUMB mode.
* @note The THUMB implementation starts with ARM code because interrupt
@ -179,8 +195,9 @@ struct context {
#endif /* !THUMB */
/**
* IRQ epilogue code, inserted at the end of all IRQ handlers enabled to
* invoke system APIs.
* @brief IRQ epilogue code.
* @details This macro must be inserted at the end of all IRQ handlers
* enabled to invoke system APIs.
* @note This macro has a different implementation depending if compiled in
* ARM or THUMB mode.
*/
@ -196,20 +213,26 @@ struct context {
#endif /* !THUMB */
/**
* IRQ handler function declaration.
* @brief IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_IRQ_HANDLER(id) __attribute__((naked)) void id(void)
/**
* This function is empty in this port.
* @brief Port-related initialization code.
* @note This function is empty in this port.
*/
#define port_init()
/**
* Disables the IRQ sources and keeps the FIQ sources enabled.
* @brief Kernel-lock action.
* @details Usually this function just disables interrupts but may perform
* more actions.
* @note In this port it disables the IRQ sources and keeps FIQ sources
* enabled.
*/
#ifdef THUMB
//#define port_lock() _port_lock_thumb()
#define port_lock() { \
asm volatile ("bl _port_lock_thumb" : : : "r3", "lr"); \
}
@ -218,10 +241,12 @@ struct context {
#endif /* !THUMB */
/**
* Enables both the IRQ and FIQ sources.
* @brief Kernel-unlock action.
* @details Usually this function just disables interrupts but may perform
* more actions.
* @note In this port it enables both the IRQ and FIQ sources.
*/
#ifdef THUMB
//#define port_unlock() _port_unlock_thumb()
#define port_unlock() { \
asm volatile ("bl _port_unlock_thumb" : : : "r3", "lr"); \
}
@ -230,22 +255,31 @@ struct context {
#endif /* !THUMB */
/**
* This function is empty in this port.
* @brief Kernel-lock action from an interrupt handler.
* @details This function is invoked before invoking I-class APIs from
* interrupt handlers. The implementation is architecture dependent,
* in its simplest form it is void.
* @note Empty in this port.
*/
#define port_lock_from_isr()
/**
* This function is empty in this port.
* @brief Kernel-unlock action from an interrupt handler.
* @details This function is invoked after invoking I-class APIs from interrupt
* handlers. The implementation is architecture dependent, in its
* simplest form it is void.
* @note Empty in this port.
*/
#define port_unlock_from_isr()
/**
* Disables both the IRQ and FIQ sources.
* @brief Disables all the interrupt sources.
* @note Of course non maskable interrupt sources are not included.
* @note In this port it disables both the IRQ and FIQ sources.
* @note Implements a workaround for spurious interrupts taken from the NXP
* LPC214x datasheet.
*/
#ifdef THUMB
//#define port_disable() _port_disable_thumb()
#define port_disable() { \
asm volatile ("bl _port_disable_thumb" : : : "r3", "lr"); \
}
@ -260,7 +294,10 @@ struct context {
#endif /* !THUMB */
/**
* Disables the IRQ sources and enables the FIQ sources.
* @brief Disables the interrupt sources below kernel-level priority.
* @note Interrupt sources above kernel level remains enabled.
* @note In this port it disables the IRQ sources and enables the
* FIQ sources.
*/
#ifdef THUMB
#define port_suspend() { \
@ -271,7 +308,8 @@ struct context {
#endif /* !THUMB */
/**
* Enables both the IRQ and FIQ sources.
* @brief Enables all the interrupt sources.
* @note In this port it enables both the IRQ and FIQ sources.
*/
#ifdef THUMB
#define port_enable() { \
@ -282,38 +320,44 @@ struct context {
#endif /* !THUMB */
/**
* Performs a context switch between two threads.
* @param otp the thread to be switched out
* @param ntp the thread to be switched in
* @brief Performs a context switch between two threads.
* @details This is the most critical code in any port, this function
* is responsible for the context switch between 2 threads.
* @note The implementation of this code affects <b>directly</b> the context
* switch performance so optimize here as much as you can.
* @note Implemented as inlined code for performance reasons.
*
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
#ifdef THUMB
#if CH_DBG_ENABLE_STACK_CHECK
#define port_switch(otp, ntp) { \
register Thread *_otp asm ("r0") = (otp); \
register Thread *_ntp asm ("r1") = (ntp); \
#define port_switch(ntp, otp) { \
register Thread *_ntp asm ("r0") = (ntp); \
register Thread *_otp asm ("r1") = (otp); \
register char *sp asm ("sp"); \
if (sp - sizeof(struct intctx) - sizeof(Thread) < (char *)_otp) \
asm volatile ("mov r0, #0 \n\t" \
"ldr r1, =chDbgPanic \n\t" \
"bx r1"); \
_port_switch_thumb(_otp, _ntp); \
_port_switch_thumb(_ntp, _otp); \
}
#else /* !CH_DBG_ENABLE_STACK_CHECK */
#define port_switch(otp, ntp) _port_switch_thumb(otp, ntp)
#define port_switch(ntp, otp) _port_switch_thumb(ntp, otp)
#endif /* !CH_DBG_ENABLE_STACK_CHECK */
#else /* !THUMB */
#if CH_DBG_ENABLE_STACK_CHECK
#define port_switch(otp, ntp) { \
register Thread *_otp asm ("r0") = (otp); \
register Thread *_ntp asm ("r1") = (ntp); \
#define port_switch(ntp, otp) { \
register Thread *_ntp asm ("r0") = (ntp); \
register Thread *_otp asm ("r1") = (otp); \
register char *sp asm ("sp"); \
if (sp - sizeof(struct intctx) - sizeof(Thread) < (char *)_otp) \
asm volatile ("mov r0, #0 \n\t" \
"b chDbgPanic"); \
_port_switch_arm(_otp, _ntp); \
_port_switch_arm(_ntp, _otp); \
}
#else /* !CH_DBG_ENABLE_STACK_CHECK */
#define port_switch(otp, ntp) _port_switch_arm(otp, ntp)
#define port_switch(ntp, otp) _port_switch_arm(ntp, otp)
#endif /* !CH_DBG_ENABLE_STACK_CHECK */
#endif /* !THUMB */
@ -322,9 +366,9 @@ extern "C" {
#endif
void port_halt(void);
#ifdef THUMB
void _port_switch_thumb(Thread *otp, Thread *ntp);
void _port_switch_thumb(Thread *ntp, Thread *otp);
#else /* !THUMB */
void _port_switch_arm(Thread *otp, Thread *ntp);
void _port_switch_arm(Thread *ntp, Thread *otp);
#endif /* !THUMB */
void _port_thread_start(void);
#ifdef __cplusplus

View File

@ -105,8 +105,8 @@ _port_switch_thumb:
_port_switch_arm:
#ifdef CH_CURRP_REGISTER_CACHE
stmfd sp!, {r4, r5, r6, r8, r9, r10, r11, lr}
str sp, [r0, #16]
ldr sp, [r1, #16]
str sp, [r1, #16]
ldr sp, [r0, #16]
#ifdef THUMB_PRESENT
ldmfd sp!, {r4, r5, r6, r8, r9, r10, r11, lr}
bx lr
@ -115,8 +115,8 @@ _port_switch_arm:
#endif /* !THUMB_PRESENT */
#else /* !CH_CURRP_REGISTER_CACHE */
stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
str sp, [r0, #12]
ldr sp, [r1, #12]
str sp, [r1, #12]
ldr sp, [r0, #12]
#ifdef THUMB_PRESENT
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
bx lr

View File

@ -20,6 +20,7 @@
/**
* @file ARMCM3/chcore.c
* @brief ARM Cortex-M3 architecture port code.
*
* @addtogroup ARMCM3_CORE
* @{
*/
@ -29,12 +30,12 @@
/**
* @brief Halts the system.
* @note The function is declared as a weak symbol, it is possible to redefine
* it in your application code.
* @note The function is declared as a weak symbol, it is possible
* to redefine it in your application code.
*/
/** @cond never */
#if !defined(__DOXYGEN__)
__attribute__((weak))
/** @endcond */
#endif
void port_halt(void) {
port_disable();
@ -57,7 +58,7 @@ void _port_unlock(void) {
/**
* @brief System Timer vector.
* @details This interrupt is used as system tick.
* @note The timer is initialized in the board setup code.
* @note The timer must be initialized in the startup code.
*/
void SysTickVector(void) {
@ -74,21 +75,21 @@ void SysTickVector(void) {
* @p intctx are saved and restored from the process stacks of the
* switched threads.
*
* @param otp the thread to be switched out
* @param ntp the thread to be switched it
* @param[in] ntp the thread to be switched it
* @param[in] otp the thread to be switched out
*/
#if !defined(__DOXYGEN__)
__attribute__((naked))
#endif
void SVCallVector(Thread *otp, Thread *ntp) {
void SVCallVector(Thread *ntp, Thread *otp) {
(void)otp;
(void)ntp;
#ifdef CH_CURRP_REGISTER_CACHE
asm volatile ("mrs r3, BASEPRI \n\t" \
"mrs r12, PSP \n\t" \
"stmdb r12!, {r3-r6,r8-r11, lr} \n\t" \
"str r12, [r0, #12] \n\t" \
"ldr r12, [r1, #12] \n\t" \
"str r12, [r1, #12] \n\t" \
"ldr r12, [r0, #12] \n\t" \
"ldmia r12!, {r3-r6,r8-r11, lr} \n\t" \
"msr PSP, r12 \n\t" \
"msr BASEPRI, r3 \n\t" \
@ -97,8 +98,8 @@ void SVCallVector(Thread *otp, Thread *ntp) {
asm volatile ("mrs r3, BASEPRI \n\t" \
"mrs r12, PSP \n\t" \
"stmdb r12!, {r3-r11, lr} \n\t" \
"str r12, [r0, #12] \n\t" \
"ldr r12, [r1, #12] \n\t" \
"str r12, [r1, #12] \n\t" \
"ldr r12, [r0, #12] \n\t" \
"ldmia r12!, {r3-r11, lr} \n\t" \
"msr PSP, r12 \n\t" \
"msr BASEPRI, r3 \n\t" \
@ -139,7 +140,7 @@ void SVCallVector(Thread *otp, Thread *ntp) {
/**
* @brief Preemption code.
*/
#ifndef __DOXYGEN__
#if !defined(__DOXYGEN__)
__attribute__((naked))
#endif
void PendSVVector(void) {

View File

@ -20,6 +20,7 @@
/**
* @file ARMCM3/chcore.h
* @brief ARM Cortex-M3 architecture port macros and structures.
*
* @addtogroup ARMCM3_CORE
* @{
*/
@ -32,49 +33,51 @@
*/
/**
* Enables the use of the WFI ins.
* @brief Enables the use of the WFI ins.
*/
#ifndef ENABLE_WFI_IDLE
#define ENABLE_WFI_IDLE 0
#endif
/**
* BASEPRI user level, 0 = disabled.
* @brief BASEPRI user level, 0 = disabled.
*/
#ifndef BASEPRI_USER
#define BASEPRI_USER 0
#endif
/**
* BASEPRI level within kernel lock.
* Priority levels higher than this one (lower values) are unaffected by
* the OS activity and can be classified as fast interrupt sources, see
* @ref interrupt_classes.
* @brief BASEPRI level within kernel lock.
* @details Priority levels higher than this one (lower values) are unaffected
* by the OS activity and can be classified as fast interrupt sources,
* see @ref interrupt_classes.
*/
#ifndef BASEPRI_KERNEL
#define BASEPRI_KERNEL 0x40
#endif
/**
* SVCALL handler priority.
* @brief SVCALL handler priority.
* @note This priority must always be one level above the @p BASEPRI_KERNEL
* value.
* @note It is recommended to leave this priority level for this handler alone.
* @note It is recommended, but not mandatory, to leave this priority level
* for this handler alone.
*/
#ifndef PRIORITY_SVCALL
#define PRIORITY_SVCALL (BASEPRI_KERNEL - 0x10)
#endif
/**
* SYSTICK handler priority.
* @brief SYSTICK handler priority.
*/
#ifndef PRIORITY_SYSTICK
#define PRIORITY_SYSTICK 0x80
#endif
/**
* PENDSV handler priority.
* @note It is recommended to leave this priority level for this handler alone.
* @brief PENDSV handler priority.
* @note It is recommended to leave this priority level for this handler
* alone.
* @note This is a reserved handler and its priority must always be the
* lowest priority in the system in order to be always executed last
* in the interrupt servicing chain.
@ -84,12 +87,12 @@
#endif
/**
* Macro defining the ARM Cortex-M3 architecture.
* @brief Macro defining the ARM Cortex-M3 architecture.
*/
#define CH_ARCHITECTURE_ARMCM3
/**
* Name of the implemented architecture.
* @brief Name of the implemented architecture.
*/
#define CH_ARCHITECTURE_NAME "ARM"
@ -99,26 +102,31 @@
#define CH_CORE_VARIANT_NAME "Cortex-M3"
/**
* 32 bit stack alignment.
* @brief 32 bit stack and memory alignment enforcement.
*/
typedef uint32_t stkalign_t;
/**
* Generic ARM register.
* @brief Generic ARM register.
*/
typedef void *regarm_t;
/** @cond never */
#if !defined(__DOXYGEN__)
/**
* Interrupt saved context, empty in this architecture.
* @brief Interrupt saved context.
* @details This structure represents the stack frame saved during a
* preemption-capable interrupt handler.
* @note This structure is empty in this port.
*/
struct extctx {
};
/** @endcond */
#endif
/** @cond never */
#if !defined(__DOXYGEN__)
/**
* This structure represents the inner stack frame during a context switching.
* @brief System saved context.
* @details This structure represents the inner stack frame during a context
* switching.
*/
struct intctx {
regarm_t basepri;
@ -142,21 +150,21 @@ struct intctx {
regarm_t pc;
regarm_t xpsr;
};
/** @endcond */
#endif
/** @cond never */
#if !defined(__DOXYGEN__)
/**
* Cortex-M3 context structure.
* @brief Cortex-M3 port context structure.
*/
struct context {
struct intctx *r13;
};
/** @endcond */
#endif
/**
* Platform dependent part of the @p chThdInit() API.
* This code usually setup the context switching frame represented by a
* @p intctx structure.
* @brief Platform dependent part of the @p chThdInit() API.
* @details This code usually setup the context switching frame represented
* by an @p intctx structure.
*/
#define SETUP_CONTEXT(workspace, wsize, pf, arg) { \
tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \
@ -171,28 +179,37 @@ struct context {
}
/**
* The default idle thread implementation requires no extra stack space in
* this port but it is set to 4 because the idle thread does have a stack
* frame when compiling without optimizations.
* @brief Stack size for the system idle thread.
* @details This size depends on the idle thread implementation, usually
* the idle thread should take no more space than those reserved
* by @p INT_REQUIRED_STACK.
* @note In this port it is set to 4 because the idle thread does have
* a stack frame when compiling without optimizations.
*/
#ifndef IDLE_THREAD_STACK_SIZE
#define IDLE_THREAD_STACK_SIZE 4
#endif
/**
* This port requires no extra stack space for interrupt handling.
* @brief Per-thread stack overhead for interrupts servicing.
* @details This constant is used in the calculation of the correct working
* area size.
* This value can be zero on those architecture where there is a
* separate interrupt stack and the stack space between @p intctx and
* @p extctx is known to be zero.
* @note This port requires no extra stack space for interrupt handling.
*/
#ifndef INT_REQUIRED_STACK
#define INT_REQUIRED_STACK 0
#endif
/**
* Enforces a correct alignment for a stack area size value.
* @brief Enforces a correct alignment for a stack area size value.
*/
#define STACK_ALIGN(n) ((((n) - 1) | (sizeof(stkalign_t) - 1)) + 1)
/**
* Computes the thread working area global size.
* @brief Computes the thread working area global size.
*/
#define THD_WA_SIZE(n) STACK_ALIGN(sizeof(Thread) + \
sizeof(struct intctx) + \
@ -200,20 +217,23 @@ struct context {
(n) + (INT_REQUIRED_STACK))
/**
* Macro used to allocate a thread working area aligned as both position and
* size.
* @brief Static working area allocation.
* @details This macro is used to allocate a static thread working area
* aligned as both position and size.
*/
#define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)];
/**
* IRQ prologue code, inserted at the start of all IRQ handlers enabled to
* invoke system APIs.
* @brief IRQ prologue code.
* @details This macro must be inserted at the start of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_PROLOGUE()
/**
* IRQ epilogue code, inserted at the end of all IRQ handlers enabled to
* invoke system APIs.
* @brief IRQ epilogue code.
* @details This macro must be inserted at the end of all IRQ handlers
* enabled to invoke system APIs.
*/
#define PORT_IRQ_EPILOGUE() { \
chSysLockFromIsr(); \
@ -223,17 +243,23 @@ struct context {
}
/**
* IRQ handler function declaration.
* @brief IRQ handler function declaration.
* @note @p id can be a function name or a vector number depending on the
* port implementation.
*/
#define PORT_IRQ_HANDLER(id) void id(void)
/**
* This function is empty in this port.
* @brief Port-related initialization code.
* @note This function is empty in this port.
*/
#define port_init()
/**
* Raises the base priority to kernel level.
* @brief Kernel-lock action.
* @details Usually this function just disables interrupts but may perform
* more actions.
* @note In this port this it raises the base priority to kernel level.
*/
#if CH_OPTIMIZE_SPEED
#define port_lock() { \
@ -247,7 +273,10 @@ struct context {
#endif
/**
* Lowers the base priority to user level.
* @brief Kernel-unlock action.
* @details Usually this function just disables interrupts but may perform
* more actions.
* @note In this port this it lowers the base priority to kernel level.
*/
#if CH_OPTIMIZE_SPEED
#define port_unlock() { \
@ -261,22 +290,35 @@ struct context {
#endif
/**
* Same as @p port_lock() in this port.
* @brief Kernel-lock action from an interrupt handler.
* @details This function is invoked before invoking I-class APIs from
* interrupt handlers. The implementation is architecture dependent,
* in its simplest form it is void.
* @note Same as @p port_lock() in this port.
*/
#define port_lock_from_isr() port_lock()
/**
* Same as @p port_unlock() in this port.
* @brief Kernel-unlock action from an interrupt handler.
* @details This function is invoked after invoking I-class APIs from interrupt
* handlers. The implementation is architecture dependent, in its
* simplest form it is void.
* @note Same as @p port_unlock() in this port.
*/
#define port_unlock_from_isr() port_unlock()
/**
* Disables all the interrupt sources by raising the priority mask to level 0.
* @brief Disables all the interrupt sources.
* @note Of course non maskable interrupt sources are not included.
* @note In this port it disables all the interrupt sources by raising
* the priority mask to level 0.
*/
#define port_disable() asm volatile ("cpsid i")
/**
* Raises/lowers the base priority to kernel level.
* @brief Disables the interrupt sources below kernel-level priority.
* @note Interrupt sources above kernel level remains enabled.
* @note In this port it raises/lowers the base priority to kernel level.
*/
#define port_suspend() { \
register uint32_t tmp asm ("r3") = BASEPRI_KERNEL; \
@ -285,7 +327,8 @@ struct context {
}
/**
* Lowers the base priority to user level.
* @brief Enables all the interrupt sources.
* @note In this port it lowers the base priority to user level.
*/
#define port_enable() { \
register uint32_t tmp asm ("r3") = BASEPRI_USER; \
@ -294,7 +337,12 @@ struct context {
}
/**
* This port function is implemented as inlined code for performance reasons.
* @brief Enters an architecture-dependent IRQ-waiting mode.
* @details The function is meant to return when an interrupt becomes pending.
* The simplest implementation is an empty function or macro but this
* would not take advantage of architecture-specific power saving
* modes.
* @note Implemented as an inlined @p WFI instruction.
*/
#if ENABLE_WFI_IDLE || defined(__DOXYGEN__)
#define port_wait_for_interrupt() { \
@ -305,25 +353,28 @@ struct context {
#endif
/**
* This port function is implemented as inlined code for performance reasons.
* @brief Performs a context switch between two threads.
* @details This is the most critical code in any port, this function
* is responsible for the context switch between 2 threads.
* @note The implementation of this code affects <b>directly</b> the context
* switch performance so optimize here as much as you can.
* @note Implemented as inlined code for performance reasons.
*
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
static INLINE Thread *port_switch(Thread *ntp, Thread *otp) {
register Thread *_ntp asm ("r0") = (ntp);
register Thread *_otp asm ("r1") = (otp);
#if CH_DBG_ENABLE_STACK_CHECK
#define port_switch(otp, ntp) { \
register Thread *_otp asm ("r0") = (otp); \
register Thread *_ntp asm ("r1") = (ntp); \
register char *sp asm ("sp"); \
if (sp - sizeof(struct intctx) - sizeof(Thread) < (char *)_otp) \
asm volatile ("movs r0, #0 \n\t" \
"b chDbgPanic"); \
asm volatile ("svc #0" : : "r" (_otp), "r" (_ntp) : "memory"); \
register char *sp asm ("sp");
if (sp - sizeof(struct intctx) - sizeof(Thread) < (char *)_otp)
asm volatile ("movs r0, #0 \n\t"
"b chDbgPanic");
#endif /* CH_DBG_ENABLE_STACK_CHECK */
asm volatile ("svc #0" : : "r" (_otp), "r" (_ntp) : "memory");
return _otp;
}
#else /* !CH_DBG_ENABLE_STACK_CHECK */
#define port_switch(otp, ntp) { \
register Thread *_otp asm ("r0") = (otp); \
register Thread *_ntp asm ("r1") = (ntp); \
asm volatile ("svc #0" : : "r" (_otp), "r" (_ntp) : "memory"); \
}
#endif /* !CH_DBG_ENABLE_STACK_CHECK */
#ifdef __cplusplus
extern "C" {

View File

@ -48,10 +48,10 @@ void port_halt(void) {
* @note The implementation of this code affects <b>directly</b> the context
* switch performance so optimize here as much as you can.
*
* @param[in] otp the thread to be switched out
* @param[in] ntp the thread to be switched in
* @param[in] otp the thread to be switched out
*/
void port_switch(Thread *otp, Thread *ntp) {
void port_switch(Thread *ntp, Thread *otp) {
(void)otp;
(void)ntp;
@ -63,8 +63,8 @@ void port_switch(Thread *otp, Thread *ntp) {
asm ("stw %r0, 0(%sp)"); /* CR. */
asm ("stmw %r14, 4(%sp)"); /* GPR14...GPR31. */
asm ("stw %sp, 12(%r3)"); /* Store swapped-out stack. */
asm ("lwz %sp, 12(%r4)"); /* Load swapped-in stack. */
asm ("stw %sp, 12(%r4)"); /* Store swapped-out stack. */
asm ("lwz %sp, 12(%r3)"); /* Load swapped-in stack. */
asm ("lmw %r14, 4(%sp)"); /* GPR14...GPR31. */
asm ("lwz %r0, 0(%sp)"); /* CR. */

View File

@ -308,7 +308,7 @@ struct context {
extern "C" {
#endif
void port_halt(void);
void port_switch(Thread *otp, Thread *ntp);
void port_switch(Thread *ntp, Thread *otp);
void _port_thread_start(void);
#ifdef __cplusplus
}

View File

@ -252,10 +252,10 @@ struct context {
* is responsible for the context switch between 2 threads.
* @note Implemented as a call to a low level assembler routine.
*
* @param otp the thread to be switched out
* @param ntp the thread to be switched in
* @param otp the thread to be switched out
*/
#define port_switch(otp, ntp) _port_switch(otp)
#define port_switch(ntp, otp) _port_switch(otp)
#ifdef __cplusplus
extern "C" {