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