From 3cc5ac6d9a6555ba70ea83c9eb9cae1bb1f44fd9 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Sun, 6 Mar 2011 08:02:26 +0000 Subject: [PATCH] Improved preemption for Cortex-M0 port. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2797 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- docs/reports/LPC1114-48-GCC.txt | 2 +- os/ports/GCC/ARMCMx/chcore_v6m.c | 54 ++++++++++++++------------------ os/ports/GCC/ARMCMx/chcore_v6m.h | 30 +++++++----------- readme.txt | 3 ++ 4 files changed, 39 insertions(+), 50 deletions(-) diff --git a/docs/reports/LPC1114-48-GCC.txt b/docs/reports/LPC1114-48-GCC.txt index 87dd7dbbe..32ea4154e 100644 --- a/docs/reports/LPC1114-48-GCC.txt +++ b/docs/reports/LPC1114-48-GCC.txt @@ -126,7 +126,7 @@ Settings: CLK=48, (2 wait states) --- Result: SUCCESS ---------------------------------------------------------------------------- --- Test Case 11.8 (Benchmark, round robin context switching) ---- Score : 253328 ctxswc/S +--- Score : 253332 ctxswc/S --- Result: SUCCESS ---------------------------------------------------------------------------- --- Test Case 11.9 (Benchmark, I/O Queues throughput) diff --git a/os/ports/GCC/ARMCMx/chcore_v6m.c b/os/ports/GCC/ARMCMx/chcore_v6m.c index 4e49e6256..5004b2256 100644 --- a/os/ports/GCC/ARMCMx/chcore_v6m.c +++ b/os/ports/GCC/ARMCMx/chcore_v6m.c @@ -27,11 +27,6 @@ #include "ch.h" -/** - * @brief PC register temporary storage. - */ -regarm_t _port_saved_pc; - /** * @brief System Timer vector. * @details This interrupt is used as system tick. @@ -48,40 +43,39 @@ CH_IRQ_HANDLER(SysTickVector) { CH_IRQ_EPILOGUE(); } +/** + * @brief NMI vector. + * @details The NMI vector is used for exception mode re-entering after a + * context switch. + */ +void NMIVector(void) { + register struct extctx *ctxp; + + /* Discarding the current exception context and positioning the stack to + point to the real one.*/ + asm volatile ("mrs %0, PSP" : "=r" (ctxp) : : "memory"); + ctxp++; + asm volatile ("msr PSP, %0" : : "r" (ctxp) : "memory"); + port_unlock_from_isr(); +} + /** * @brief Post-IRQ switch code. - * @details On entry the stack and the registers are restored by the exception - * return, the PC value is stored in @p _port_saved_pc, the interrupts - * are disabled. + * @details The switch is performed in thread context then an NMI exception + * is enforced in order to return to the exact point before the + * preemption. */ #if !defined(__DOXYGEN__) __attribute__((naked)) #endif void _port_switch_from_isr(void) { - /* Note, saves r4 to make space for the PC.*/ - asm volatile ("push {r0, r1, r2, r3, r4} \n\t" - "mrs r0, APSR \n\t" - "mov r1, r12 \n\t" - "push {r0, r1, lr} \n\t" - "ldr r0, =_port_saved_pc \n\t" - "ldr r0, [r0] \n\t" - "add r0, r0, #1 \n\t" - "str r0, [sp, #28]" : : : "memory"); chSchDoRescheduleI(); - - /* Note, the last register is restored alone after re-enabling the - interrupts in order to minimize the (very remote and unlikely) - possibility that the stack is filled by continuous and saturating - interrupts that would not allow that last words to be pulled out of - the stack.*/ - asm volatile ("pop {r0, r1, r2} \n\t" - "mov r12, r1 \n\t" - "msr APSR, r0 \n\t" - "mov lr, r2 \n\t" - "pop {r0, r1, r2, r3} \n\t" - "cpsie i \n\t" - "pop {pc}" : : : "memory"); + SCB_ICSR = ICSR_NMIPENDSET; + /* The following loop should never be executed, the NMI will kick in + immediately.*/ + while (TRUE) + ; } #define PUSH_CONTEXT(sp) { \ diff --git a/os/ports/GCC/ARMCMx/chcore_v6m.h b/os/ports/GCC/ARMCMx/chcore_v6m.h index bb20cb4be..89fbdbec6 100644 --- a/os/ports/GCC/ARMCMx/chcore_v6m.h +++ b/os/ports/GCC/ARMCMx/chcore_v6m.h @@ -32,10 +32,8 @@ /* Port implementation part. */ /*===========================================================================*/ -/** - * @brief Cortex-Mx exception context. - */ -struct cmxctx { +#if !defined(__DOXYGEN__) +struct extctx { regarm_t r0; regarm_t r1; regarm_t r2; @@ -46,18 +44,6 @@ struct cmxctx { regarm_t xpsr; }; -#if !defined(__DOXYGEN__) -struct extctx { - regarm_t xpsr; - regarm_t r12; - regarm_t lr; - regarm_t r0; - regarm_t r1; - regarm_t r2; - regarm_t r3; - regarm_t pc; -}; - struct intctx { regarm_t r8; regarm_t r9; @@ -131,11 +117,17 @@ struct intctx { if (_saved_lr != (regarm_t)0xFFFFFFF1) { \ port_lock_from_isr(); \ if (chSchIsRescRequiredExI()) { \ - register struct cmxctx *ctxp; \ + register struct extctx *ctxp; \ \ - asm volatile ("mrs %0, PSP" : "=r" (ctxp) : ); \ - _port_saved_pc = ctxp->pc; \ + /* Adding an artificial exception return context, there is no need to \ + populate it fully.*/ \ + asm volatile ("mrs %0, PSP" : "=r" (ctxp) : : "memory"); \ + ctxp--; \ + asm volatile ("msr PSP, %0" : : "r" (ctxp) : "memory"); \ ctxp->pc = _port_switch_from_isr; \ + ctxp->xpsr = (regarm_t)0x01000000; \ + /* Note, returning without unlocking is intentional, this is done in \ + order to keep the rest of the context switching atomic.*/ \ return; \ } \ port_unlock_from_isr(); \ diff --git a/readme.txt b/readme.txt index a8486d91b..c0754c136 100644 --- a/readme.txt +++ b/readme.txt @@ -84,6 +84,9 @@ 2.2.1). - FIX: Error in MAC driver (bug 3179783)(backported to 2.2.1). - FIX: Fixed wrong serial driver macros (bug 3173336)(backported to 2.2.1). +- NEW: Inproved preemption implementation for the Cortex-M0, now it uses + the NMI vector in order to restore the original context. The change makes + IRQ handling faster and also saves some RAM/ROM space (backported to 2.2.3). - NEW: Added "IRQ STORM" long duration tests for the STM32 and LPC11xx. The test demonstrates the system stability in a thread-intensive, progressively CPU-saturating, IRQ-intensive long duration test.