diff --git a/.gitignore b/.gitignore index 766bd174..e8e84a25 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ *.log *.chm *.zip +*.pdb *.ncb *.suo *.chw @@ -29,7 +30,7 @@ *.avrsuo *.Debug *.Release -lint*.out +lint*.txt *.Miro *.bak @@ -40,6 +41,7 @@ dbg/ rel/ spy/ settings/ +.settings/ Debug/ Release/ diff --git a/3rd_party/ek-tm4c123gxl/iar/startup_TM4C123GH6PM.s b/3rd_party/ek-tm4c123gxl/iar/startup_TM4C123GH6PM.s index 70ad419f..657a69a5 100644 --- a/3rd_party/ek-tm4c123gxl/iar/startup_TM4C123GH6PM.s +++ b/3rd_party/ek-tm4c123gxl/iar/startup_TM4C123GH6PM.s @@ -2,7 +2,7 @@ ; * @file startup_TM4C123GH6PM.s for IAR ARM assembler ; * @brief CMSIS Cortex-M4F Core Device Startup File for TM4C123GH6PM ; * @version CMSIS 4.3.0 -; * @date 20 August 2015 +; * @date 24 April 2016 ; * ; * @description ; * Created from the CMSIS template for the specified device @@ -521,11 +521,10 @@ PWM1Gen2_IRQHandler PWM1Gen3_IRQHandler PWM1Fault_IRQHandler MOVS r0,#0 - MOVS r1,#-1 ; 0xFFFFFFF + MOVS r1,#0xFF B assert_failed -;****************************************************************************** -; +;***************************************************************************** ; The function assert_failed defines the error/assertion handling policy ; for the application. After making sure that the stack is OK, this function ; calls Q_onAssert, which should NOT return (typically reset the CPU). @@ -535,11 +534,12 @@ PWM1Fault_IRQHandler ; The C proptotype of the assert_failed() and Q_onAssert() functions are: ; void assert_failed(char const *file, int line); ; void Q_onAssert (char const *file, int line); -;****************************************************************************** +;***************************************************************************** PUBLIC assert_failed EXTERN Q_onAssert assert_failed - LDR sp,=sfe(CSTACK) ; re-set the SP in case of stack overflow + LDR r2,=sfe(CSTACK) ; load the original top of stack + MOV sp,r2 ; re-set the SP in case of stack overflow BL Q_onAssert ; call the application-specific handler B . ; should not be reached, but just in case... diff --git a/doxygen/Doxyfile b/doxygen/Doxyfile index 27fe8a9f..ebcad8b3 100644 --- a/doxygen/Doxyfile +++ b/doxygen/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "QP/C++" -PROJECT_NUMBER = "5.6.3" +PROJECT_NUMBER = "5.6.4" PROJECT_BRIEF = PROJECT_LOGO = images/header_logo_ql.png OUTPUT_DIRECTORY = diff --git a/doxygen/Doxyfile-CHM b/doxygen/Doxyfile-CHM index 6cce482d..f27a9d75 100644 --- a/doxygen/Doxyfile-CHM +++ b/doxygen/Doxyfile-CHM @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "QP/C++" -PROJECT_NUMBER = "5.6.3" +PROJECT_NUMBER = "5.6.4" PROJECT_BRIEF = PROJECT_LOGO = images/header_logo_ql.png OUTPUT_DIRECTORY = diff --git a/doxygen/history.dox b/doxygen/history.dox index 553d6e05..a055e7bf 100644 --- a/doxygen/history.dox +++ b/doxygen/history.dox @@ -1,8 +1,12 @@ namespace QP { /** @page history Revision History - +@section qpcpp_5_6_4 Version 5.6.4, 2016-04-25 +This release fixes a serious Bug #128 (https://sourceforge.net/p/qpc/bugs/128 ) in the QK port to ARM Cortex-M introduced back in QP 5.6.1 + + +------------------------------------------------------------------------------ @section qpcpp_5_6_3 Version 5.6.3, 2016-04-12 This release fixes a serious Bug #127 (https://sourceforge.net/p/qpc/bugs/127 ) in the QK preemptive scheduler introduced in QP 5.6.2. diff --git a/doxygen/make.bat b/doxygen/make.bat index 9cd0304a..4e8accc2 100644 --- a/doxygen/make.bat +++ b/doxygen/make.bat @@ -1,8 +1,8 @@ @echo off :: ========================================================================== :: Product: QP/C++ script for generating Doxygen documentation -:: Last Updated for Version: 5.6.3 -:: Date of the Last Update: 2016-04-12 +:: Last Updated for Version: 5.6.4 +:: Date of the Last Update: 2016-04-24 :: :: Q u a n t u m L e a P s :: --------------------------- @@ -38,7 +38,7 @@ echo usage: echo make echo make -CHM -set VERSION=5.6.3 +set VERSION=5.6.4 :: Generate Resource Standard Metrics for QP/C++ ............................. set DOXHOME="C:\tools\doxygen\bin" diff --git a/doxygen/metrics.dox b/doxygen/metrics.dox index 664af31f..17318c31 100644 --- a/doxygen/metrics.dox +++ b/doxygen/metrics.dox @@ -1,7 +1,7 @@ /** @page metrics Code Metrics @code - Standard Code Metrics for QP/C++ 5.6.3 + Standard Code Metrics for QP/C++ 5.6.4 Resource Standard Metrics (TM) for C, C++, C# and Java Version 7.75 - mSquaredTechnologies.com @@ -9,7 +9,7 @@ License Type: Windows Single User License Licensed To : Quantum Leaps, LLC License No. : WS2975 License Date: Dec 15, 2013 - Build Date : Sep 2 2009 Run Date: Apr 12, 2016 + Build Date : Sep 2 2009 Run Date: Apr 24, 2016 (C)1996-2009 M Squared Technologies LLC ________________________________________________________________________ diff --git a/examples/arm-cm/dpp_ek-tm4c123gxl/lint/lint_out.txt b/examples/arm-cm/dpp_ek-tm4c123gxl/lint/lint_out.txt index cae5eb65..8e0dcaa3 100644 --- a/examples/arm-cm/dpp_ek-tm4c123gxl/lint/lint_out.txt +++ b/examples/arm-cm/dpp_ek-tm4c123gxl/lint/lint_out.txt @@ -8,7 +8,6 @@ "C:\qp\qpcpp\ports\arm-cm\qk\gnu\qk_port.h" 48 19 Warning 530: Symbol 'regIPSR' (line 46) not initialized [MISRA C++ Rule 8-5-1] "C:\qp\qpcpp\ports\arm-cm\qk\gnu\qk_port.h" 46 1 Info 830: Location cited in prior message "C:\qp\qpcpp\ports\arm-cm\qk\gnu\qk_port.h" 52 32 Note 1923: macro 'QK_ISR_ENTRY' could become const variable [MISRA C++ Rule 16-2-2] -"C:\qp\qpcpp\ports\arm-cm\qk\gnu\qk_port.h" 65 33 Note 1960: Violates MISRA C++ 2008 Required Rule 7-3-1, Global declaration of symbol 'QK_nextPrio_' "C:\qp\qpcpp\include\qpset.h" 128 58 Note 1960: Violates MISRA C++ 2008 Required Rule 5-0-8, Cast of integer cvalue expression to larger type "C:\qp\qpcpp\include\qpset.h" 221 21 Note 1960: Violates MISRA C++ 2008 Required Rule 5-0-8, Cast of integer cvalue expression to larger type "C:\qp\qpcpp\include\qpset.h" 224 21 Note 1960: Violates MISRA C++ 2008 Required Rule 5-0-8, Cast of integer cvalue expression to larger type @@ -57,7 +56,6 @@ "C:\qp\qpcpp\ports\arm-cm\qk\gnu\qk_port.h" 48 19 Warning 530: Symbol 'regIPSR' (line 46) not initialized [MISRA C++ Rule 8-5-1] "C:\qp\qpcpp\ports\arm-cm\qk\gnu\qk_port.h" 46 1 Info 830: Location cited in prior message "C:\qp\qpcpp\ports\arm-cm\qk\gnu\qk_port.h" 52 32 Note 1923: macro 'QK_ISR_ENTRY' could become const variable [MISRA C++ Rule 16-2-2] -"C:\qp\qpcpp\ports\arm-cm\qk\gnu\qk_port.h" 65 33 Note 1960: Violates MISRA C++ 2008 Required Rule 7-3-1, Global declaration of symbol 'QK_nextPrio_' "C:\qp\qpcpp\ports\arm-cm\qk\gnu\qs_port.h" 51 10 Warning 537: Repeated include file 'C:\qp\qpcpp\ports\arm-cm\qk\gnu\qf_port.h' "C:\qp\qpcpp\include\qs.h" 61 9 Note 1960: Violates MISRA C++ 2008 Required Rule 16-0-4, Function-like macro defined: 'QS_PTR_AT_' "C:\qp\qpcpp\include\qs.h" 61 37 Note 1960: Violates MISRA C++ 2008 Required Rule 16-0-6, unparenthesized macro parameter in definition of macro: 'QS_PTR_AT_' @@ -476,4 +474,4 @@ Count Type Number Text 2 Note 963 Qualifier const or volatile ___ a type; use ___ to reverse the test 1 Note 1914 Default constructor '___' (___) not referenced 2 Note 1923 macro '___' could become const variable -27 Note 1960 Violates MISRA C++ 2008 Required Rule ___, ___ +25 Note 1960 Violates MISRA C++ 2008 Required Rule ___, ___ diff --git a/examples/arm-cm/dpp_ek-tm4c123gxl/qk/ti/startup_TM4C123GH6PM.c b/examples/arm-cm/dpp_ek-tm4c123gxl/qk/ti/startup_TM4C123GH6PM.c index 28c2b8b1..acb79c09 100644 --- a/examples/arm-cm/dpp_ek-tm4c123gxl/qk/ti/startup_TM4C123GH6PM.c +++ b/examples/arm-cm/dpp_ek-tm4c123gxl/qk/ti/startup_TM4C123GH6PM.c @@ -2,7 +2,7 @@ * Purpose: startup file for TM4C123GH6PM Cortex-M4 device. * Should be used with TI CCS-ARM Compiler * Version: CMSIS 4.3.0 - * Date: 2015-Nov-10 + * Date: 2016-Apr-22 * * Created from the CMSIS template for the specified device * Quantum Leaps, www.state-machine.com @@ -373,6 +373,7 @@ void Default_Handler(void) { ); } /*..........................................................................*/ +/* defined in QK port void NMI_Handler(void) { __asm( " .global assert_failed\n\r" @@ -381,6 +382,7 @@ void NMI_Handler(void) { " b.w assert_failed\n\r" ); } +*/ /*..........................................................................*/ void MemManage_Handler(void) { __asm( diff --git a/examples/arm-cm/dpp_ek-tm4c123gxl/qk/ti/tm4c123gh6pm.cmd b/examples/arm-cm/dpp_ek-tm4c123gxl/qk/ti/tm4c123gh6pm.cmd deleted file mode 100644 index f2a35023..00000000 --- a/examples/arm-cm/dpp_ek-tm4c123gxl/qk/ti/tm4c123gh6pm.cmd +++ /dev/null @@ -1,45 +0,0 @@ -/****************************************************************************** - * - * Default Linker Command file for the Texas Instruments TM4C123GH6PM - * - * This is derived from revision 14351 of the TivaWare Library. - * - *****************************************************************************/ - ---retain=g_pfnVectors - -MEMORY -{ - FLASH (RX) : origin = 0x00000000, length = 0x00040000 - SRAM (RWX) : origin = 0x20000000, length = 0x00008000 -} - -/* The following command line options are set as part of the CCS project. */ -/* If you are building using the command line, or for some reason want to */ -/* define them here, you can uncomment and modify these lines as needed. */ -/* If you are using CCS for building, it is probably better to make any such */ -/* modifications in your CCS project and leave this file alone. */ -/* */ -/* --heap_size=0 */ -/* --stack_size=256 */ -/* --library=rtsv7M4_T_le_eabi.lib */ - -/* Section allocation in memory */ - -SECTIONS -{ - .intvecs: > 0x00000000 - .text : > FLASH - .const : > FLASH - .cinit : > FLASH - .pinit : > FLASH - .init_array : > FLASH - - .vtable : > 0x20000000 - .data : > SRAM - .bss : > SRAM - .sysmem : > SRAM - .stack : > SRAM -} - -__STACK_TOP = __stack + 512; diff --git a/examples/arm-cm/dpp_ek-tm4c123gxl/qv/ti/tm4c123gh6pm.cmd b/examples/arm-cm/dpp_ek-tm4c123gxl/qv/ti/tm4c123gh6pm.cmd deleted file mode 100644 index f2a35023..00000000 --- a/examples/arm-cm/dpp_ek-tm4c123gxl/qv/ti/tm4c123gh6pm.cmd +++ /dev/null @@ -1,45 +0,0 @@ -/****************************************************************************** - * - * Default Linker Command file for the Texas Instruments TM4C123GH6PM - * - * This is derived from revision 14351 of the TivaWare Library. - * - *****************************************************************************/ - ---retain=g_pfnVectors - -MEMORY -{ - FLASH (RX) : origin = 0x00000000, length = 0x00040000 - SRAM (RWX) : origin = 0x20000000, length = 0x00008000 -} - -/* The following command line options are set as part of the CCS project. */ -/* If you are building using the command line, or for some reason want to */ -/* define them here, you can uncomment and modify these lines as needed. */ -/* If you are using CCS for building, it is probably better to make any such */ -/* modifications in your CCS project and leave this file alone. */ -/* */ -/* --heap_size=0 */ -/* --stack_size=256 */ -/* --library=rtsv7M4_T_le_eabi.lib */ - -/* Section allocation in memory */ - -SECTIONS -{ - .intvecs: > 0x00000000 - .text : > FLASH - .const : > FLASH - .cinit : > FLASH - .pinit : > FLASH - .init_array : > FLASH - - .vtable : > 0x20000000 - .data : > SRAM - .bss : > SRAM - .sysmem : > SRAM - .stack : > SRAM -} - -__STACK_TOP = __stack + 512; diff --git a/examples/arm-cm/dpp_ek-tm4c123gxl/qxk/ti/tm4c123gh6pm.cmd b/examples/arm-cm/dpp_ek-tm4c123gxl/qxk/ti/tm4c123gh6pm.cmd deleted file mode 100644 index f2a35023..00000000 --- a/examples/arm-cm/dpp_ek-tm4c123gxl/qxk/ti/tm4c123gh6pm.cmd +++ /dev/null @@ -1,45 +0,0 @@ -/****************************************************************************** - * - * Default Linker Command file for the Texas Instruments TM4C123GH6PM - * - * This is derived from revision 14351 of the TivaWare Library. - * - *****************************************************************************/ - ---retain=g_pfnVectors - -MEMORY -{ - FLASH (RX) : origin = 0x00000000, length = 0x00040000 - SRAM (RWX) : origin = 0x20000000, length = 0x00008000 -} - -/* The following command line options are set as part of the CCS project. */ -/* If you are building using the command line, or for some reason want to */ -/* define them here, you can uncomment and modify these lines as needed. */ -/* If you are using CCS for building, it is probably better to make any such */ -/* modifications in your CCS project and leave this file alone. */ -/* */ -/* --heap_size=0 */ -/* --stack_size=256 */ -/* --library=rtsv7M4_T_le_eabi.lib */ - -/* Section allocation in memory */ - -SECTIONS -{ - .intvecs: > 0x00000000 - .text : > FLASH - .const : > FLASH - .cinit : > FLASH - .pinit : > FLASH - .init_array : > FLASH - - .vtable : > 0x20000000 - .data : > SRAM - .bss : > SRAM - .sysmem : > SRAM - .stack : > SRAM -} - -__STACK_TOP = __stack + 512; diff --git a/ports/arm-cm/qk/arm/qk_port.h b/ports/arm-cm/qk/arm/qk_port.h index 6822abe7..15b6233a 100644 --- a/ports/arm-cm/qk/arm/qk_port.h +++ b/ports/arm-cm/qk/arm/qk_port.h @@ -2,14 +2,14 @@ /// @brief QK/C++ port to ARM Cortex-M, ARM-KEIL toolset /// @cond ///*************************************************************************** -/// Last updated for version 5.5.2 -/// Last updated on 2015-11-11 +/// Last updated for version 5.6.4 +/// Last updated on 2016-04-25 /// /// Q u a n t u m L e a P s /// --------------------------- /// innovating embedded systems /// -/// Copyright (C) Quantum Leaps, www.state-machine.com. +/// Copyright (C) Quantum Leaps, LLC. All rights reserved. /// /// This program is open source software: you can redistribute it and/or /// modify it under the terms of the GNU General Public License as published @@ -30,7 +30,7 @@ /// along with this program. If not, see . /// /// Contact information: -/// http:// www.state-machine.com +/// http://www.state-machine.com /// mailto:info@state-machine.com ///*************************************************************************** /// @endcond @@ -49,19 +49,9 @@ static __inline uint32_t QK_get_IPSR(void) { // QK interrupt entry and exit #define QK_ISR_ENTRY() ((void)0) - -#define QK_ISR_EXIT() do { \ - QF_INT_DISABLE(); \ - uint_fast8_t nextPrio_ = QK_schedPrio_(); \ - if (nextPrio_ != static_cast(0)) { \ - QK_nextPrio_ = nextPrio_; \ - (*Q_UINT2PTR_CAST(uint32_t, 0xE000ED04U) \ - = static_cast(1U << 28)); \ - } \ - QF_INT_ENABLE(); \ -} while (false) - -extern uint_fast8_t QK_nextPrio_; // priority of the next task to execute +#define QK_ISR_EXIT() \ + ((*Q_UINT2PTR_CAST(uint32_t, 0xE000ED04U) = \ + static_cast(1U << 28))) #include "qk.h" // QK platform-independent public interface diff --git a/ports/arm-cm/qk/arm/qk_port.s b/ports/arm-cm/qk/arm/qk_port.s index 5f027c0c..65c79782 100644 --- a/ports/arm-cm/qk/arm/qk_port.s +++ b/ports/arm-cm/qk/arm/qk_port.s @@ -1,7 +1,7 @@ ;***************************************************************************** ; Product: QK port to ARM Cortex-M (M0,M0+,M1,M3,M4,M7), ARM-Keil assembler -; Last Updated for Version: 5.6.0 -; Date of the Last Update: 2015-12-14 +; Last Updated for Version: 5.6.4 +; Date of the Last Update: 2016-04-21 ; ; Q u a n t u m L e a P s ; --------------------------- @@ -34,7 +34,7 @@ EXPORT QK_init EXPORT PendSV_Handler ; CMSIS-compliant PendSV exception name - EXPORT QK_nextPrio_ ; priority of the next task to execute + EXPORT NMI_Handler ; CMSIS-compliant NMI exception name IMPORT QK_schedPrio_ ; external reference IMPORT QK_sched_ ; external reference @@ -42,14 +42,6 @@ ; NOTE: keep in synch with QF_BASEPRI value defined in "qf_port.h" !!! QF_BASEPRI EQU (0xFF:SHR:2) - AREA |.data|, DATA, READWRITE -;***************************************************************************** -; Global priority of the next task to execute or zero to indicate return -; to the preempted task -;***************************************************************************** -QK_nextPrio_ - DCD 0 - AREA |.text|, CODE, READONLY THUMB @@ -105,14 +97,15 @@ PendSV_Handler ENDIF ; M3/M4/M7 ISB ; reset the instruction pipeline - LDR r0,=QK_nextPrio_ - LDR r0,[r0] - CMP r0,#0 - BNE.N PendSV_sched ; if QK_nextPrio_ != 0, branch to scheduler + IF {TARGET_FPU_VFP} == {TRUE} ; if VFP available... + PUSH {r0,lr} ; push lr (EXC_RETURN) plus stack "aligner" + ENDIF ; VFP available - ; QK_nextPrio_ == 0: return to the preempted task... - ADD sp,sp,#(8*4) ; remove one 8-register exception frame + BL QK_schedPrio_ ; call QK_schedPrio_() + CMP r0,#0 ; is the returned next prio 0? + BNE.N PendSV_sched ; if next prio != 0, branch to scheduler +PendSV_ret IF {TARGET_ARCH_THUMB} == 3 ; Cortex-M0/M0+/M1 (v6-M, v6S-M)? CPSIE i ; enable interrupts (clear PRIMASK) MOVS r0,#6 @@ -130,18 +123,20 @@ PendSV_Handler ENDIF ; no VFP ENDIF ; M3/M4/M7 -PendSV_sched - IF {TARGET_FPU_VFP} == {TRUE} ; if VFP available... - PUSH {r0,lr} ; push lr (EXC_RETURN) plus stack "aligner" - ENDIF ; VFP available - +PendSV_sched ; call the QK scheduler... + ; NOTE: The QK scheduler must be called in a task context, while + ; we are still in the PendSV exception context. The switch to the + ; task context is accomplished by returning from PendSV using a + ; fabricated exception stack frame, where the return address is + ; the QK scheduler. + ; NOTE: the QK scheduler is called with interrupts DISABLED. MOVS r3,#1 LSLS r3,r3,#24 ; r3:=(1 << 24), set the T bit (new xpsr) LDR r2,=QK_sched_ ; address of the QK scheduler (new pc) LDR r1,=PendSV_sched_ret ; return address after the call (new lr) SUB sp,sp,#8*4 ; reserve space for exception stack frame - STR r0,[sp] ; save the prio argument (new r0) + STR r0,[sp] ; save the prio argument (new r0) ADD r0,sp,#5*4 ; r0 := 5 registers below the top of stack STM r0!,{r1-r3} ; save xpsr,pc,lr @@ -150,28 +145,53 @@ PendSV_sched BX r0 ; exception-return to the QK scheduler PendSV_sched_ret - LDR r0,=QK_nextPrio_ - MOVS r1,#0 - STR r1,[r0] ; QK_nextPrio_ = 0; + ; NOTE: After the QK scheduler returns, we need to resume the preempted + ; task. However, this must be accomplished by a return-from-exception, + ; while we are still in the task context. The switch to the exception + ; contex is accomplished by triggering the NMI exception. + ; NOTE: The NMI exception is triggered with nterrupts DISABLED, + ; because QK scheduler disables interrutps before return. - IF {TARGET_ARCH_THUMB} == 3 ; Cortex-M0/M0+/M1 (v6-M, v6S-M)? - CPSIE i ; enable interrupts (clear PRIMASK) - ELSE ; M3/M4/M7 + ; before triggering the NMI exception, make sure that the + ; VFP stack frame will NOT be used... IF {TARGET_FPU_VFP} == {TRUE} ; if VFP available... MRS r0,CONTROL ; r0 := CONTROL BICS r0,r0,#4 ; r0 := r0 & ~4 (FPCA bit) MSR CONTROL,r0 ; CONTROL := r0 (clear CONTROL[2] FPCA bit) ENDIF ; VFP available - MOVS r0,#0 - MSR BASEPRI,r0 ; enable interrupts (clear BASEPRI) - ENDIF ; M3/M4/M7 - ; trigger PendSV to return to preempted task... + ; trigger NMI to return to preempted task... LDR r0,=0xE000ED04 ; Interrupt Control and State Register MOVS r1,#1 - LSLS r1,r1,#28 ; r0 := (1 << 28) (PENDSVSET bit) - STR r1,[r0] ; ICSR[28] := 1 (pend PendSV) - B . ; wait for preemption by PendSV + LSLS r1,r1,#31 ; r0 := (1 << 31) (NMI bit) + STR r1,[r0] ; ICSR[31] := 1 (pend NMI) + B . ; wait for preemption by NMI + + +;***************************************************************************** +; The NMI_Handler exception handler is used for returning back to the +; interrupted task. The NMI exception simply removes its own interrupt +; stack frame from the stack and returns to the preempted task using the +; interrupt stack frame that must be at the top of the stack. +; +; NOTE: The NMI exception is entered with interrupts DISABLED, so it needs +; to re-enable interrupts before it returns to the preempted task. +;***************************************************************************** +NMI_Handler + ADD sp,sp,#(8*4) ; remove one 8-register exception frame + + IF {TARGET_ARCH_THUMB} == 3 ; Cortex-M0/M0+/M1 (v6-M, v6S-M)? + CPSIE i ; enable interrupts (clear PRIMASK) + BX lr ; return to the preempted task + ELSE ; M3/M4/M7 + MOVS r0,#0 + MSR BASEPRI,r0 ; enable interrupts (clear BASEPRI) + IF {TARGET_FPU_VFP} == {TRUE} ; if VFP available... + POP {r0,pc} ; pop stack "aligner" and EXC_RETURN to PC + ELSE ; no VFP + BX lr ; return to the preempted task + ENDIF ; no VFP + ENDIF ; M3/M4/M7 ALIGN ; make sure the END is properly aligned diff --git a/ports/arm-cm/qk/gnu/qk_port.h b/ports/arm-cm/qk/gnu/qk_port.h index 5ed73577..580c9586 100644 --- a/ports/arm-cm/qk/gnu/qk_port.h +++ b/ports/arm-cm/qk/gnu/qk_port.h @@ -2,14 +2,14 @@ /// @brief QK/C++ port to ARM Cortex-M, preemptive QK kernel, GNU-ARM toolset /// @cond ///*************************************************************************** -/// Last updated for version 5.5.2 -/// Last updated on 2015-11-11 +/// Last updated for version 5.6.4 +/// Last updated on 2016-04-25 /// /// Q u a n t u m L e a P s /// --------------------------- /// innovating embedded systems /// -/// Copyright (C) Quantum Leaps, www.state-machine.com. +/// Copyright (C) Quantum Leaps, LLC. All rights reserved. /// /// This program is open source software: you can redistribute it and/or /// modify it under the terms of the GNU General Public License as published @@ -50,19 +50,9 @@ static inline uint32_t QK_get_IPSR(void) { // QK interrupt entry and exit #define QK_ISR_ENTRY() ((void)0) - -#define QK_ISR_EXIT() do { \ - QF_INT_DISABLE(); \ - uint_fast8_t nextPrio_ = QK_schedPrio_(); \ - if (nextPrio_ != static_cast(0)) { \ - QK_nextPrio_ = nextPrio_; \ - (*Q_UINT2PTR_CAST(uint32_t, 0xE000ED04U) \ - = static_cast(1U << 28)); \ - } \ - QF_INT_ENABLE(); \ -} while (false) - -extern uint_fast8_t QK_nextPrio_; // priority of the next task to execute +#define QK_ISR_EXIT() \ + ((*Q_UINT2PTR_CAST(uint32_t, 0xE000ED04U) = \ + static_cast(1U << 28))) #include "qk.h" // QK platform-independent public interface diff --git a/ports/arm-cm/qk/gnu/qk_port.s b/ports/arm-cm/qk/gnu/qk_port.s index 845df4ee..83be1c3e 100644 --- a/ports/arm-cm/qk/gnu/qk_port.s +++ b/ports/arm-cm/qk/gnu/qk_port.s @@ -1,7 +1,7 @@ /***************************************************************************** * Product: QK port to ARM Cortex-M (M0,M0+,M1,M3,M4,M7), GNU-ARM assembler -* Last Updated for Version: 5.6.0 -* Date of the Last Update: 2015-12-14 +* Last Updated for Version: 5.6.4 +* Date of the Last Update: 2016-04-22 * * Q u a n t u m L e a P s * --------------------------- @@ -33,21 +33,12 @@ *****************************************************************************/ .syntax unified + .thumb /* NOTE: keep in synch with QF_BASEPRI value defined in "qf_port.h" !!! */ .equ QF_BASEPRI,(0xFF >> 2) - .section .data -/***************************************************************************** -* Global priority of the next task to execute or zero to indicate return -* to the preempted task -*****************************************************************************/ -QK_nextPrio_: - .global QK_nextPrio_ - .word 0 - - /***************************************************************************** * The QK_init function sets the priorities of PendSV to 0xFF (lowest). * The priority is set within a critical section. @@ -55,7 +46,6 @@ QK_nextPrio_: .section .text.QK_init .global QK_init .type QK_init, %function - .thumb QK_init: MRS r0,PRIMASK /* store the state of the PRIMASK in r0 */ @@ -103,20 +93,20 @@ PendSV_Handler: .if __ARM_ARCH == 6 /* Cortex-M0/M0+/M1 (v6-M, v6S-M)? */ CPSID i /* disable interrupts at processor level */ .else /* M3/M4/M7 */ - MOVS r0,#QF_BASEPRI MSR BASEPRI,r0 /* selectively disable interrupts */ .endif /* M3/M4/M7 */ ISB /* reset the instruction pipeline */ - LDR r0,=QK_nextPrio_ - LDR r0,[r0] - CMP r0,#0 - BNE.N PendSV_sched /* if QK_nextPrio_ != 0, branch to scheduler */ + .ifdef __FPU_PRESENT /* if VFP available... */ + PUSH {r0,lr} /* push lr (EXC_RETURN) plus stack "aligner" */ + .endif /* VFP available */ - /* QK_nextPrio_ == 0: return to the preempted task... */ - ADD sp,sp,#(8*4) /* remove one 8-register exception frame */ + BL QK_schedPrio_ /* call QK_schedPrio_() */ + CMP r0,#0 /* is the returned next prio 0? */ + BNE.N PendSV_sched /* if next prio != 0, branch to scheduler */ +PendSV_ret: .if __ARM_ARCH == 6 /* Cortex-M0/M0+/M1 (v6-M, v6S-M)? */ CPSIE i /* enable interrupts (clear PRIMASK) */ MOVS r0,#6 @@ -134,10 +124,14 @@ PendSV_Handler: .endif /* VFP available */ .endif /* M3/M4/M7 */ -PendSV_sched: - .ifdef __FPU_PRESENT /* if VFP available... */ - PUSH {r0,lr} /* push lr (EXC_RETURN) plus stack "aligner" */ - .endif /* VFP available */ +PendSV_sched: /* call the QK scheduler... */ + /* NOTE: The QK scheduler must be called in a task context, while + * we are still in the PendSV exception context. The switch to the + * task context is accomplished by returning from PendSV using a + * fabricated exception stack frame, where the return address is + * the QK scheduler. + * NOTE: the QK scheduler is called with interrupts DISABLED. + */ MOVS r3,#1 LSLS r3,r3,#24 /* r3:=(1 << 24), set the T bit (new xpsr) */ LDR r2,=QK_sched_ /* address of the QK scheduler (new pc) */ @@ -153,28 +147,59 @@ PendSV_sched: BX r0 /* exception-return to the QK scheduler */ PendSV_sched_ret: - LDR r0,=QK_nextPrio_ - MOVS r1,#0 - STR r1,[r0] /* QK_nextPrio_ = 0; */ - - .if __ARM_ARCH == 6 /* Cortex-M0/M0+/M1 (v6-M, v6S-M)? */ - CPSIE i /* enable interrupts (clear PRIMASK) */ - .else /* M3/M4/M7 */ + /* NOTE: After the QK scheduler returns, we need to resume the preempted + * task. However, this must be accomplished by a return-from-exception, + * while we are still in the task context. The switch to the exception + * contex is accomplished by triggering the NMI exception. + * NOTE: The NMI exception is triggered with nterrupts DISABLED, + * because QK scheduler disables interrutps before return. + */ + /* before triggering the NMI exception, make sure that the + * VFP stack frame will NOT be used... + */ .ifdef __FPU_PRESENT /* if VFP available... */ MRS r0,CONTROL /* r0 := CONTROL */ BICS r0,r0,#4 /* r0 := r0 & ~4 (FPCA bit) */ MSR CONTROL,r0 /* CONTROL := r0 (clear CONTROL[2] FPCA bit) */ .endif /* VFP available */ - MOVS r0,#0 - MSR BASEPRI,r0 /* enable interrupts (clear BASEPRI) */ - .endif /* M3/M4/M7 */ - /* trigger PendSV to return to preempted task... */ + /* trigger NMI to return to preempted task... */ LDR r0,=0xE000ED04 /* Interrupt Control and State Register */ MOVS r1,#1 - LSLS r1,r1,#28 /* r0 := (1 << 28) (PENDSVSET bit) */ - STR r1,[r0] /* ICSR[28] := 1 (pend PendSV) */ - B . /* wait for preemption by PendSV */ + LSLS r1,r1,#31 /* r0 := (1 << 31) (NMI bit) */ + STR r1,[r0] /* ICSR[31] := 1 (pend NMI) */ + B . /* wait for preemption by NMI */ .size PendSV_Handler, . - PendSV_Handler + +/***************************************************************************** +* The NMI_Handler exception handler is used for returning back to the +* interrupted task. The NMI exception simply removes its own interrupt +* stack frame from the stack and returns to the preempted task using the +* interrupt stack frame that must be at the top of the stack. +* +* NOTE: The NMI exception is entered with interrupts DISABLED, so it needs +* to re-enable interrupts before it returns to the preempted task. +*****************************************************************************/ + .section .text.NMI_Handler + .global NMI_Handler /* CMSIS-compliant exception name */ + .type NMI_Handler, %function + +NMI_Handler: + ADD sp,sp,#(8*4) /* remove one 8-register exception frame */ + + .if __ARM_ARCH == 6 /* Cortex-M0/M0+/M1 (v6-M, v6S-M)? */ + CPSIE i /* enable interrupts (clear PRIMASK) */ + BX lr /* return to the preempted task */ + .else /* M3/M4/M7 */ + MOVS r0,#0 + MSR BASEPRI,r0 /* enable interrupts (clear BASEPRI) */ + .ifdef __FPU_PRESENT /* if VFP available... */ + POP {r0,pc} /* pop stack "aligner" and EXC_RETURN to PC */ + .else /* no VFP */ + BX lr /* return to the preempted task */ + .endif /* VFP available */ + .endif /* M3/M4/M7 */ + .size NMI_Handler, . - NMI_Handler + .end diff --git a/ports/arm-cm/qk/iar/qk_port.h b/ports/arm-cm/qk/iar/qk_port.h index 3088b9ad..064710be 100644 --- a/ports/arm-cm/qk/iar/qk_port.h +++ b/ports/arm-cm/qk/iar/qk_port.h @@ -2,8 +2,8 @@ /// @brief QK/C++ port to ARM Cortex-M, preemptive QK kernel, IAR-ARM toolset /// @cond ///*************************************************************************** -/// Last updated for version 5.6.0 -/// Last updated on 2015-12-28 +/// Last updated for version 5.6.4 +/// Last updated on 2016-04-25 /// /// Q u a n t u m L e a P s /// --------------------------- @@ -43,19 +43,9 @@ /* QK interrupt entry and exit */ #define QK_ISR_ENTRY() ((void)0) - -#define QK_ISR_EXIT() do { \ - QF_INT_DISABLE(); \ - uint_fast8_t nextPrio_ = QK_schedPrio_(); \ - if (nextPrio_ != static_cast(0)) { \ - QK_nextPrio_ = nextPrio_; \ - (*Q_UINT2PTR_CAST(uint32_t, 0xE000ED04U) \ - = static_cast(1U << 28)); \ - } \ - QF_INT_ENABLE(); \ -} while (false) - -extern uint_fast8_t QK_nextPrio_; // priority of the next task to execute +#define QK_ISR_EXIT() \ + ((*Q_UINT2PTR_CAST(uint32_t, 0xE000ED04U) = \ + static_cast(1U << 28))) #include "qk.h" // QK platform-independent public interface diff --git a/ports/arm-cm/qk/iar/qk_port.s b/ports/arm-cm/qk/iar/qk_port.s index 30bd7385..6fa621ea 100644 --- a/ports/arm-cm/qk/iar/qk_port.s +++ b/ports/arm-cm/qk/iar/qk_port.s @@ -1,7 +1,7 @@ ;***************************************************************************** ; Product: QK port to ARM Cortex-M (M0,M0+,M1,M3,M4,M7), IAR ARM assembler -; Last Updated for Version: 5.6.0 -; Date of the Last Update: 2015-12-11 +; Last Updated for Version: 5.6.4 +; Date of the Last Update: 2016-04-21 ; ; Q u a n t u m L e a P s ; --------------------------- @@ -34,7 +34,7 @@ PUBLIC QK_init PUBLIC PendSV_Handler ; CMSIS-compliant PendSV exception name - PUBLIC QK_nextPrio_ ; priority of the next task to execute + PUBLIC NMI_Handler ; CMSIS-compliant NMI exception name EXTERN QK_schedPrio_ ; external reference EXTERN QK_sched_ ; external reference @@ -42,21 +42,13 @@ ; NOTE: keep in synch with QF_BASEPRI value defined in "qf_port.h" !!! QF_BASEPRI EQU (0xFF >> 2) - RSEG .data:DATA:NOROOT(2) -;***************************************************************************** -; Global priority of the next task to execute or zero to indicate return -; to the preempted task -;***************************************************************************** -QK_nextPrio_: - DC32 0 - RSEG CODE:CODE:NOROOT(2) ;***************************************************************************** ; The QK_init function sets the priorities of PendSV to 0xFF (lowest). ; The priority is set within a critical section. ;***************************************************************************** -QK_init +QK_init: MRS r0,PRIMASK ; store the state of the PRIMASK in r0 CPSID i ; disable interrupts (set PRIMASK) @@ -92,7 +84,6 @@ QK_init ; check for the asynchronous preemption. ;***************************************************************************** PendSV_Handler: - #if (__CORE__ == __ARM6M__) ; Cortex-M0/M0+/M1 ? CPSID i ; disable interrupts (set PRIMASK) #else ; M3/M4/M7 @@ -101,14 +92,15 @@ PendSV_Handler: #endif ; M3/M4/M7 ISB ; reset the instruction pipeline - LDR r0,=QK_nextPrio_ - LDR r0,[r0] - CMP r0,#0 - BNE.N PendSV_sched ; if QK_nextPrio_ != 0, branch to scheduler +#ifdef __ARMVFP__ ; if VFP available... + PUSH {r0,lr} ; push lr (EXC_RETURN) plus stack "aligner" +#endif ; VFP available - ; QK_nextPrio_ == 0: return to the preempted task... - ADD sp,sp,#(8*4) ; remove one 8-register exception frame + BL QK_schedPrio_ ; call QK_schedPrio_() + CMP r0,#0 ; is the returned next prio 0? + BNE.N PendSV_sched ; if next prio != 0, branch to scheduler +PendSV_ret: #if (__CORE__ == __ARM6M__) ; Cortex-M0/M0+/M1 ? CPSIE i ; enable interrupts (clear PRIMASK) MOVS r0,#6 @@ -126,18 +118,20 @@ PendSV_Handler: #endif ; no VFP #endif ; M3/M4/M7 -PendSV_sched: -#ifdef __ARMVFP__ ; if VFP available... - PUSH {r0,lr} ; push lr (EXC_RETURN) plus stack "aligner" -#endif ; VFP available - +PendSV_sched: ; call the QK scheduler... + ; NOTE: The QK scheduler must be called in a task context, while + ; we are still in the PendSV exception context. The switch to the + ; task context is accomplished by returning from PendSV using a + ; fabricated exception stack frame, where the return address is + ; the QK scheduler. + ; NOTE: the QK scheduler is called with interrupts DISABLED. MOVS r3,#1 LSLS r3,r3,#24 ; r3:=(1 << 24), set the T bit (new xpsr) LDR r2,=QK_sched_ ; address of the QK scheduler (new pc) LDR r1,=PendSV_sched_ret ; return address after the call (new lr) SUB sp,sp,#8*4 ; reserve space for exception stack frame - STR r0,[sp] ; save the prio argument (new r0) + STR r0,[sp] ; save the prio argument (new r0) ADD r0,sp,#5*4 ; r0 := 5 registers below the top of stack STM r0!,{r1-r3} ; save xpsr,pc,lr @@ -146,28 +140,53 @@ PendSV_sched: BX r0 ; exception-return to the QK scheduler PendSV_sched_ret: - LDR r0,=QK_nextPrio_ - MOVS r1,#0 - STR r1,[r0] ; QK_nextPrio_ = 0; + ; NOTE: After the QK scheduler returns, we need to resume the preempted + ; task. However, this must be accomplished by a return-from-exception, + ; while we are still in the task context. The switch to the exception + ; contex is accomplished by triggering the NMI exception. + ; NOTE: The NMI exception is triggered with nterrupts DISABLED, + ; because QK scheduler disables interrutps before return. -#if (__CORE__ == __ARM6M__) ; Cortex-M0/M0+/M1 ? - CPSIE i ; enable interrupts (clear PRIMASK) -#else ; M3/M4/M7 + ; before triggering the NMI exception, make sure that the + ; VFP stack frame will NOT be used... #ifdef __ARMVFP__ ; if VFP available... MRS r0,CONTROL ; r0 := CONTROL BICS r0,r0,#4 ; r0 := r0 & ~4 (FPCA bit) MSR CONTROL,r0 ; CONTROL := r0 (clear CONTROL[2] FPCA bit) #endif ; VFP available - MOVS r0,#0 - MSR BASEPRI,r0 ; enable interrupts (clear BASEPRI) -#endif ; M3/M4/M7 - ; trigger PendSV to return to preempted task... + ; trigger NMI to return to preempted task... LDR r0,=0xE000ED04 ; Interrupt Control and State Register MOVS r1,#1 - LSLS r1,r1,#28 ; r0 := (1 << 28) (PENDSVSET bit) - STR r1,[r0] ; ICSR[28] := 1 (pend PendSV) - B . ; wait for preemption by PendSV + LSLS r1,r1,#31 ; r0 := (1 << 31) (NMI bit) + STR r1,[r0] ; ICSR[31] := 1 (pend NMI) + B . ; wait for preemption by NMI + + +;***************************************************************************** +; The NMI_Handler exception handler is used for returning back to the +; interrupted task. The NMI exception simply removes its own interrupt +; stack frame from the stack and returns to the preempted task using the +; interrupt stack frame that must be at the top of the stack. +; +; NOTE: The NMI exception is entered with interrupts DISABLED, so it needs +; to re-enable interrupts before it returns to the preempted task. +;***************************************************************************** +NMI_Handler: + ADD sp,sp,#(8*4) ; remove one 8-register exception frame + +#if (__CORE__ == __ARM6M__) ; Cortex-M0/M0+/M1 ? + CPSIE i ; enable interrupts (clear PRIMASK) + BX lr ; return to the preempted task +#else ; M3/M4/M7 + MOVS r0,#0 + MSR BASEPRI,r0 ; enable interrupts (clear BASEPRI) +#ifdef __ARMVFP__ ; if VFP available... + POP {r0,pc} ; pop stack "aligner" and EXC_RETURN to PC +#else ; no VFP + BX lr ; return to the preempted task +#endif ; no VFP +#endif ; M3/M4/M7 ALIGNROM 2,0xFF ; make sure the END is properly aligned diff --git a/ports/arm-cm/qk/ti/qk_port.h b/ports/arm-cm/qk/ti/qk_port.h index fea9b5b4..56517c32 100644 --- a/ports/arm-cm/qk/ti/qk_port.h +++ b/ports/arm-cm/qk/ti/qk_port.h @@ -2,8 +2,8 @@ /// @brief QK/C++ port to ARM Cortex-M, preemptive QK kernel, TI-ARM toolset /// @cond ///*************************************************************************** -/// Last updated for version 5.6.0 -/// Last updated on 2015-12-30 +/// Last updated for version 5.6.4 +/// Last updated on 2016-04-25 /// /// Q u a n t u m L e a P s /// --------------------------- @@ -38,11 +38,19 @@ #ifndef qk_port_h #define qk_port_h -// QK interrupt entry and exit (defined in assembly) +// determination if the code executes in the ISR context +#define QK_ISR_CONTEXT_() (QK_get_IPSR() != static_cast(0)) + +// QK interrupt entry and exit +#define QK_ISR_ENTRY() ((void)0) +#define QK_ISR_EXIT() \ + ((*Q_UINT2PTR_CAST(uint32_t, 0xE000ED04U) = \ + static_cast(1U << 28))) + extern "C" { - void QK_ISR_ENTRY(void); - void QK_ISR_EXIT(void); -} // extern "C" + // get the IPSR defined in assembly + uint32_t QK_get_IPSR(void); +} #include "qk.h" // QK platform-independent public interface diff --git a/ports/arm-cm/qk/ti/qk_port.s b/ports/arm-cm/qk/ti/qk_port.s index 8f33b8de..9665b774 100644 --- a/ports/arm-cm/qk/ti/qk_port.s +++ b/ports/arm-cm/qk/ti/qk_port.s @@ -1,7 +1,7 @@ ;***************************************************************************** ; Product: QK port to ARM Cortex-M (M0,M0+,M1,M3,M4,M7), TI-ARM assembler -; Last Updated for Version: 5.6.1 -; Date of the Last Update: 2015-12-30 +; Last Updated for Version: 5.6.4 +; Date of the Last Update: 2016-04-21 ; ; Q u a n t u m L e a P s ; --------------------------- @@ -34,10 +34,10 @@ .global QK_init .global PendSV_Handler ; CMSIS-compliant PendSV exception name + .global NMI_Handler ; CMSIS-compliant NMI exception name .global QF_set_BASEPRI ; set BASEPRI register - .global QK_ISR_ENTRY ; inform QK about interrupt entry - .global QK_ISR_EXIT ; inform QK about interrupt exit + .global QK_get_IPSR ; get the IPSR .global assert_failed ; low-level assert handler .ref QK_schedPrio_ ; external reference @@ -48,16 +48,9 @@ ; NOTE: keep in synch with QF_BASEPRI value defined in "qf_port.h" !!! QF_BASEPRI: .equ (0xFF >> 2) - .data -;***************************************************************************** -; Priority of the next task to execute or zero to indicate return -; to the preempted task -;***************************************************************************** -QK_nextPrio_: .word 0 - - .text .thumb + ;***************************************************************************** ; The QK_init function sets the priorities of PendSV to 0xFF (lowest). ; The priority is set within a critical section. @@ -107,14 +100,15 @@ PendSV_Handler: .asmfunc .endif ; M0/M0+/M1 ISB ; reset the instruction pipeline - LDR r0,QK_nextPrio_addr - LDR r0,[r0] - CMP r0,#0 - BNE.N PendSV_sched ; if QK_nextPrio_ != 0, branch to scheduler + .if __TI_VFP_SUPPORT__ ; if VFP available... + PUSH {r0,lr} ; push lr (EXC_RETURN) plus stack "aligner" + .endif ; VFP available - ; QK_nextPrio_ == 0: return to the preempted task... - ADD sp,sp,#(8*4) ; remove one 8-register exception frame + BL QK_schedPrio_ ; call QK_schedPrio_() + CMP r0,#0 ; is the returned next prio 0? + BNE.N PendSV_sched ; if next prio != 0, branch to scheduler +PendSV_ret: .if __TI_TMS470_V7M3__ | __TI_TMS470_V7M4__ ; | __TI_TMS470_V7M7__ ; NOTE: r0 == 0 at this point MSR BASEPRI,r0 ; enable interrupts (clear BASEPRI) @@ -132,18 +126,20 @@ PendSV_Handler: .asmfunc BX r0 ; exception-return to the task .endif ; M0/M0+/M1 -PendSV_sched: - .if __TI_VFP_SUPPORT__ ; if VFP available... - PUSH {r0,lr} ; push lr (EXC_RETURN) plus stack "aligner" - .endif ; VFP available - +PendSV_sched: ; call the QK scheduler... + ; NOTE: The QK scheduler must be called in a task context, while + ; we are still in the PendSV exception context. The switch to the + ; task context is accomplished by returning from PendSV using a + ; fabricated exception stack frame, where the return address is + ; the QK scheduler. + ; NOTE: the QK scheduler is called with interrupts DISABLED. MOVS r3,#1 LSLS r3,r3,#24 ; r3:=(1 << 24), set the T bit (new xpsr) LDR r2,QK_sched_addr ; address of the QK scheduler (new pc) LDR r1,PendSV_sched_ret_addr ; ret address after the call (new lr) SUB sp,sp,#8*4 ; reserve space for exception stack frame - STR r0,[sp] ; save the prio argument (new r0) + STR r0,[sp] ; save the prio argument (new r0) ADD r0,sp,#5*4 ; r0 := 5 registers below the top of stack STM r0!,{r1-r3} ; save xpsr,pc,lr @@ -153,32 +149,59 @@ PendSV_sched: .endasmfunc PendSV_sched_ret: .asmfunc ; to ensure that the label is THUMB - LDR r0,QK_nextPrio_addr - MOVS r1,#0 - STR r1,[r0] ; QK_nextPrio_ = 0; + ; NOTE: After the QK scheduler returns, we need to resume the preempted + ; task. However, this must be accomplished by a return-from-exception, + ; while we are still in the task context. The switch to the exception + ; contex is accomplished by triggering the NMI exception. + ; NOTE: The NMI exception is triggered with nterrupts DISABLED, + ; because QK scheduler disables interrutps before return. - .if __TI_TMS470_V7M3__ | __TI_TMS470_V7M4__ ; | __TI_TMS470_V7M7__ + ; before triggering the NMI exception, make sure that the + ; VFP stack frame will NOT be used... .if __TI_VFP_SUPPORT__ ; if VFP available... MRS r0,CONTROL ; r0 := CONTROL BICS r0,r0,#4 ; r0 := r0 & ~4 (FPCA bit) MSR CONTROL,r0 ; CONTROL := r0 (clear CONTROL[2] FPCA bit) .endif ; VFP available - MOVS r0,#0 - MSR BASEPRI,r0 ; enable interrupts (clear BASEPRI) - .else ; M0/M0+/M1 - CPSIE i ; enable interrupts (clear BASEPRI) - .endif ; M0/M0+/M1 - ; trigger PendSV to return to preempted task... + ; trigger NMI to return to preempted task... LDR r0,ICSR_addr ; Interrupt Control and State Register MOVS r1,#1 - LSLS r1,r1,#28 ; r0 := (1 << 28) (PENDSVSET bit) - STR r1,[r0] ; ICSR[28] := 1 (pend PendSV) + LSLS r1,r1,#31 ; r0 := (1 << 31) (NMI bit) + STR r1,[r0] ; ICSR[31] := 1 (pend NMI) PendSV_sched_wait: - B PendSV_sched_wait ; wait for preemption by PendSV + B PendSV_sched_wait ; wait for preemption by NMI .endasmfunc +;***************************************************************************** +; The NMI_Handler exception handler is used for returning back to the +; interrupted task. The NMI exception simply removes its own interrupt +; stack frame from the stack and returns to the preempted task using the +; interrupt stack frame that must be at the top of the stack. +; +; NOTE: The NMI exception is entered with interrupts DISABLED, so it needs +; to re-enable interrupts before it returns to the preempted task. +;***************************************************************************** +NMI_Handler: .asmfunc + ADD sp,sp,#(8*4) ; remove one 8-register exception frame + + .if __TI_TMS470_V7M3__ | __TI_TMS470_V7M4__ ; | __TI_TMS470_V7M7__ + + MOVS r0,#0 + MSR BASEPRI,r0 ; enable interrupts (clear BASEPRI) + .if __TI_VFP_SUPPORT__ ; if VFP available... + POP {r0,pc} ; pop stack "aligner" and EXC_RETURN to PC + .else ; no VFP + BX lr ; return to the preempted task + .endif ; VFP available + .else ; M0/M0+/M1 + CPSIE i ; enable interrupts (clear PRIMASK) + BX lr ; return to the preempted task + .endif ; M0/M0+/M1 + .endasmfunc + + ;***************************************************************************** ; The QF_set_BASEPRI function sets the BASEPRI register to the value ; passed in r0. @@ -191,80 +214,14 @@ QF_set_BASEPRI: .asmfunc ;***************************************************************************** -; Inform QK about interrupt entry. -; C prototype: void QK_ISR_ENTRY(void); +; The QK_get_IPSR function gets the IPSR register and returns it in r0. +; C prototype: uint32_t QK_get_IPSR(void); ;***************************************************************************** -QK_ISR_ENTRY: .asmfunc - .if __TI_TMS470_V7M3__ | __TI_TMS470_V7M4__ ; | __TI_TMS470_V7M7__ - MOVS r0,#QF_BASEPRI - MSR BASEPRI,r0 ; selectively disable interrupts - .else ; M0/M0+/M1 - CPSID i ; disable interrupts (set PRIMASK) - .endif ; M0/M0+/M1 - - ; ++QK_intNest_ - LDR r1,QK_intNest_addr ; address of the QK_intNest_ - LDR r0,[r1] - ADDS r0,r0,#1 - STR r0,[r1] - - .if __TI_TMS470_V7M3__ | __TI_TMS470_V7M4__ ; | __TI_TMS470_V7M7__ - MOVS r0,#0 - MSR BASEPRI,r0 ; set BASEPRI (disable interrupts) - .else ; M0/M0+/M1 - CPSIE i ; enable interrupts (set PRIMASK) - .endif ; M0/M0+/M1 - +QK_get_IPSR: .asmfunc + MRS r0,ipsr ; r0 := IPSR BX lr ; return to the caller .endasmfunc - -;***************************************************************************** -; Inform QK about interrupt exit. -; C prototype: void QK_ISR_EXIT(void); -;***************************************************************************** -QK_ISR_EXIT: .asmfunc - PUSH {r0,lr} ; push lr (return address) plus stack "aligner" - ; NOTE: because of the call to QK_schedPrio_() - - .if __TI_TMS470_V7M3__ | __TI_TMS470_V7M4__ ; | __TI_TMS470_V7M7__ - MOVS r0,#QF_BASEPRI - MSR BASEPRI,r0 ; selectively disable interrupts - .else ; M0/M0+/M1 - CPSID i ; disable interrupts (set PRIMASK) - .endif ; M0/M0+/M1 - - ; --QK_intNest_ - LDR r1,QK_intNest_addr ; address of the QK_intNest_ - LDR r0,[r1] - SUBS r0,r0,#1 - STR r0,[r1] - - BL QK_schedPrio_ ; check if we have preemption - CMP r0,#0 ; is prio == 0 ? - BEQ.N no_preemption ; if prio == 0, branch to no_preemption - - LDR r1,QK_nextPrio_addr ; address of the QK_nextPrio_ - STR r0,[r1] ; QK_nextPrio_ = prio - - ; trigger PendSV to return to preempted task... - LDR r0,ICSR_addr ; Interrupt Control and State Register - MOVS r1,#1 - LSLS r1,r1,#28 ; r0 := (1 << 28) (PENDSVSET bit) - STR r1,[r0] ; ICSR[28] := 1 (pend PendSV) - -no_preemption: - .if __TI_TMS470_V7M3__ | __TI_TMS470_V7M4__ ; | __TI_TMS470_V7M7__ - MOVS r0,#0 - MSR BASEPRI,r0 ; set BASEPRI (disable interrupts) - .else ; M0/M0+/M1 - CPSIE i ; enable interrupts (set PRIMASK) - .endif ; M0/M0+/M1 - - POP {r0,pc} ; pop the stack "aligner" and saved LR to PC - .endasmfunc - - ;***************************************************************************** ; The assert_failed() function restores the SP (in case stack is corrupted) ; and calls Q_onAssert(module, loc) @@ -289,7 +246,6 @@ VTOR_addr: .word 0xE000ED08 ;***************************************************************************** ; Addresses for PC-relative LDR ;***************************************************************************** -QK_nextPrio_addr: .word QK_nextPrio_ QK_sched_addr: .word QK_sched_ QK_intNest_addr: .word QK_intNest_ PendSV_sched_ret_addr .word PendSV_sched_ret diff --git a/ports/arm-cm/qxk/arm/qxk_port.s b/ports/arm-cm/qxk/arm/qxk_port.s index 6a9df00a..20931d6d 100644 --- a/ports/arm-cm/qxk/arm/qxk_port.s +++ b/ports/arm-cm/qxk/arm/qxk_port.s @@ -1,7 +1,7 @@ ;***************************************************************************** ; Product: QXK port to ARM Cortex-M (M0,M0+,M1,M3,M4,M7), ARM-Keil assembler -; Last Updated for Version: 5.6.0 -; Date of the Last Update: 2015-12-14 +; Last Updated for Version: 5.6.4 +; Date of the Last Update: 2016-04-23 ; ; Q u a n t u m L e a P s ; --------------------------- @@ -200,6 +200,12 @@ PendSV_Handler ENDIF ; M3/M4/M7 ISB ; flush the instruction pipeline + ; un-pend any PendSV pended from the time this PendSV was called... + LDR r2,=0xE000ED04 ; Interrupt Control and State Register + MOVS r1,#1 + LSLS r1,r1,#27 ; r0 := (1 << 27) (UNPENDSVSET bit) + STR r1,[r2] ; ICSR[27] := 1 (unpend PendSV) + ; store the SP of the current QXK thread... LDR r1,=QXK_attr_ LDR r2,[r1,#QXK_CURR] diff --git a/ports/arm-cm/qxk/gnu/qxk_port.s b/ports/arm-cm/qxk/gnu/qxk_port.s index 9f830694..ce8c282c 100644 --- a/ports/arm-cm/qxk/gnu/qxk_port.s +++ b/ports/arm-cm/qxk/gnu/qxk_port.s @@ -1,7 +1,7 @@ /***************************************************************************** * Product: QXK port to ARM Cortex-M (M0,M0+,M1,M3,M4,M7), GNU-ARM assembler -* Last Updated for Version: 5.6.0 -* Date of the Last Update: 2015-12-10 +* Last Updated for Version: 5.6.4 +* Date of the Last Update: 2016-04-23 * * Q u a n t u m L e a P s * --------------------------- @@ -200,6 +200,12 @@ PendSV_Handler: .endif /* M3/M4/M7 */ ISB /* reset the instruction pipeline */ + /* un-pend any PendSV pended from the time this PendSV was called... */ + LDR r2,=0xE000ED04 /* Interrupt Control and State Register */ + MOVS r1,#1 + LSLS r1,r1,#27 /* r0 := (1 << 27) (UNPENDSVSET bit) */ + STR r1,[r2] /* ICSR[27] := 1 (unpend PendSV) */ + /* store the SP of the current QXK thread... */ LDR r1,=QXK_attr_ LDR r2,[r1,#QXK_CURR] diff --git a/ports/arm-cm/qxk/iar/qxk_port.s b/ports/arm-cm/qxk/iar/qxk_port.s index 6d826491..38a37ae4 100644 --- a/ports/arm-cm/qxk/iar/qxk_port.s +++ b/ports/arm-cm/qxk/iar/qxk_port.s @@ -1,7 +1,7 @@ ;***************************************************************************** ; Product: QXK port to ARM Cortex-M (M0,M0+,M1,M3,M4,M7), IAR ARM assembler -; Last Updated for Version: 5.6.0 -; Date of the Last Update: 2015-12-09 +; Last Updated for Version: 5.6.4 +; Date of the Last Update: 2016-04-23 ; ; Q u a n t u m L e a P s ; --------------------------- @@ -196,6 +196,12 @@ PendSV_Handler: #endif ; M3/M4/M7 ISB ; flush the instruction pipeline + ; un-pend any PendSV pended from the time this PendSV was called... + LDR r2,=0xE000ED04 ; Interrupt Control and State Register + MOVS r1,#1 + LSLS r1,r1,#27 ; r0 := (1 << 27) (UNPENDSVSET bit) + STR r1,[r2] ; ICSR[27] := 1 (unpend PendSV) + ; store the SP of the current QXK thread... LDR r1,=QXK_attr_ LDR r2,[r1,#QXK_CURR] diff --git a/ports/arm-cm/qxk/ti/qxk_port.s b/ports/arm-cm/qxk/ti/qxk_port.s index 88dceb22..2e31aa1c 100644 --- a/ports/arm-cm/qxk/ti/qxk_port.s +++ b/ports/arm-cm/qxk/ti/qxk_port.s @@ -1,7 +1,7 @@ ;***************************************************************************** ; Product: QXK port to ARM Cortex-M (M0,M0+,M1,M3,M4,M7), TI-ARM assembler -; Last Updated for Version: 5.6.0 -; Date of the Last Update: 2015-12-12 +; Last Updated for Version: 5.6.4 +; Date of the Last Update: 2016-04-24 ; ; Q u a n t u m L e a P s ; --------------------------- @@ -206,6 +206,12 @@ PendSV_Handler: .asmfunc .endif ; M0/M0+/M1 ISB ; flush the instruction pipeline + ; un-pend any PendSV pended from the time this PendSV was called... + LDR r2,ICSR_addr ; Interrupt Control and State Register + MOVS r1,#1 + LSLS r1,r1,#27 ; r0 := (1 << 27) (UNPENDSVSET bit) + STR r1,[r2] ; ICSR[27] := 1 (unpend PendSV) + ; store the SP of the current QXK thread... LDR r1,QXK_attr_addr LDR r2,[r1,#QXK_CURR] diff --git a/ports/win32-qv/QSpy/vc120.pdb b/ports/win32-qv/QSpy/vc120.pdb index c8829596..5f13917e 100644 Binary files a/ports/win32-qv/QSpy/vc120.pdb and b/ports/win32-qv/QSpy/vc120.pdb differ diff --git a/ports/win32/QSpy/vc120.pdb b/ports/win32/QSpy/vc120.pdb index 1d42f377..ec6b8538 100644 Binary files a/ports/win32/QSpy/vc120.pdb and b/ports/win32/QSpy/vc120.pdb differ diff --git a/version-5.6.3 b/version-5.6.3 deleted file mode 100644 index 1e203ee5..00000000 --- a/version-5.6.3 +++ /dev/null @@ -1,2 +0,0 @@ -QP/C++ 5.6.3 -2016-04-12 diff --git a/version-5.6.4 b/version-5.6.4 new file mode 100644 index 00000000..209989f9 --- /dev/null +++ b/version-5.6.4 @@ -0,0 +1,2 @@ +QP/C++ 5.6.4 +2016-04-25