QP is an event-driven, RTOS-like, active object framework for microcontrollers, such as mbed. The QP framework provides thread-safe execution of active objects (concurrent state machines) and support both manual and automatic coding of UML statecharts in readable, production-quality C or C++. Automatic code generation of QP code is supported by the free QM modeling tool.
Dependents: qp_hangman qp_dpp qp_blinky
QP/C++ (Quantum Platform in C++) is a lightweight, open source active object (actor) framework for building responsive and modular real-time embedded applications as systems of asynchronous event-driven active objects (actors). The QP/C++ framework is a member of a larger family consisting of QP/C++, QP/C, and QP-nano frameworks, which are all strictly quality controlled, thoroughly documented, and available under GPLv3 with a special Exception for mbed (see http://www.state-machine.com/licensing/QP-mbed_GPL_Exception.txt).
The behavior of active objects is specified in QP/C++ by means of hierarchical state machines (UML statecharts). The framework supports manual coding of UML state machines in C++ as well as automatic code generation by means of the free QM modeling tool (http://www.state-machine.com/qm).
Please see the "QP/C++ Reference Manual" (http://www.state-machine.com/qpcpp) for more information.
qk_port.s@9:ca2e6010d9e2, 2012-09-04 (annotated)
- Committer:
- QL
- Date:
- Tue Sep 04 22:20:52 2012 +0000
- Revision:
- 9:ca2e6010d9e2
- Parent:
- 5:949864ba515c
QP/C++ 4.5.02 compatible with QM 2.2.xx
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
QL | 9:ca2e6010d9e2 | 1 | ;***************************************************************************** |
QL | 9:ca2e6010d9e2 | 2 | ; Product: QK port to ARM Cortex-M0/M3, mbed ARM assembler, CMSIS-compliant |
QL | 9:ca2e6010d9e2 | 3 | ; Last Updated for Version: 4.5.02 |
QL | 9:ca2e6010d9e2 | 4 | ; Date of the Last Update: Sep 04, 2012 |
QL | 9:ca2e6010d9e2 | 5 | ; |
QL | 9:ca2e6010d9e2 | 6 | ; Q u a n t u m L e a P s |
QL | 9:ca2e6010d9e2 | 7 | ; --------------------------- |
QL | 9:ca2e6010d9e2 | 8 | ; innovating embedded systems |
QL | 9:ca2e6010d9e2 | 9 | ; |
QL | 9:ca2e6010d9e2 | 10 | ; Copyright (C) 2002-2012 Quantum Leaps, LLC. All rights reserved. |
QL | 9:ca2e6010d9e2 | 11 | ; |
QL | 9:ca2e6010d9e2 | 12 | ; This program is open source software: you can redistribute it and/or |
QL | 9:ca2e6010d9e2 | 13 | ; modify it under the terms of the GNU General Public License as published |
QL | 9:ca2e6010d9e2 | 14 | ; by the Free Software Foundation, either version 2 of the License, or |
QL | 9:ca2e6010d9e2 | 15 | ; (at your option) any later version. |
QL | 9:ca2e6010d9e2 | 16 | ; |
QL | 9:ca2e6010d9e2 | 17 | ; Alternatively, this program may be distributed and modified under the |
QL | 9:ca2e6010d9e2 | 18 | ; terms of Quantum Leaps commercial licenses, which expressly supersede |
QL | 9:ca2e6010d9e2 | 19 | ; the GNU General Public License and are specifically designed for |
QL | 9:ca2e6010d9e2 | 20 | ; licensees interested in retaining the proprietary status of their code. |
QL | 9:ca2e6010d9e2 | 21 | ; |
QL | 9:ca2e6010d9e2 | 22 | ; This program is distributed in the hope that it will be useful, |
QL | 9:ca2e6010d9e2 | 23 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of |
QL | 9:ca2e6010d9e2 | 24 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
QL | 9:ca2e6010d9e2 | 25 | ; GNU General Public License for more details. |
QL | 9:ca2e6010d9e2 | 26 | ; |
QL | 9:ca2e6010d9e2 | 27 | ; You should have received a copy of the GNU General Public License |
QL | 9:ca2e6010d9e2 | 28 | ; along with this program. If not, see <http://www.gnu.org/licenses/>. |
QL | 9:ca2e6010d9e2 | 29 | ; |
QL | 9:ca2e6010d9e2 | 30 | ; Contact information: |
QL | 9:ca2e6010d9e2 | 31 | ; Quantum Leaps Web sites: http://www.quantum-leaps.com |
QL | 9:ca2e6010d9e2 | 32 | ; http://www.state-machine.com |
QL | 9:ca2e6010d9e2 | 33 | ; e-mail: info@quantum-leaps.com |
QL | 9:ca2e6010d9e2 | 34 | ;***************************************************************************** |
QL | 9:ca2e6010d9e2 | 35 | AREA QK, CODE, READONLY |
QL | 9:ca2e6010d9e2 | 36 | PRESERVE8 |
QL | 9:ca2e6010d9e2 | 37 | |
QL | 9:ca2e6010d9e2 | 38 | EXPORT QK_init |
QL | 9:ca2e6010d9e2 | 39 | EXPORT PendSV_Handler ; CMSIS-compliant PendSV exception name |
QL | 9:ca2e6010d9e2 | 40 | EXPORT SVC_Handler ; CMSIS-compliant SVC exception name |
QL | 9:ca2e6010d9e2 | 41 | |
QL | 9:ca2e6010d9e2 | 42 | EXTERN QK_schedPrio_ ; external reference |
QL | 9:ca2e6010d9e2 | 43 | EXTERN QK_sched_ ; external reference |
QL | 9:ca2e6010d9e2 | 44 | |
QL | 9:ca2e6010d9e2 | 45 | |
QL | 9:ca2e6010d9e2 | 46 | ;***************************************************************************** |
QL | 9:ca2e6010d9e2 | 47 | ; |
QL | 9:ca2e6010d9e2 | 48 | ; The QK_init function sets the priorities of PendSV and SVCall exceptions |
QL | 9:ca2e6010d9e2 | 49 | ; to 0xFF and 0x00, respectively. The function internally disables |
QL | 9:ca2e6010d9e2 | 50 | ; interrupts, but restores the original interrupt lock before exit. |
QL | 9:ca2e6010d9e2 | 51 | ; |
QL | 9:ca2e6010d9e2 | 52 | ;***************************************************************************** |
QL | 9:ca2e6010d9e2 | 53 | QK_init |
QL | 9:ca2e6010d9e2 | 54 | MRS r0,PRIMASK ; store the state of the PRIMASK in r0 |
QL | 9:ca2e6010d9e2 | 55 | CPSID i ; disable interrupts (set PRIMASK) |
QL | 9:ca2e6010d9e2 | 56 | |
QL | 9:ca2e6010d9e2 | 57 | LDR r1,=0xE000ED18 ; System Handler Priority Register |
QL | 9:ca2e6010d9e2 | 58 | LDR r2,[r1,#8] ; load the System 12-15 Priority Register |
QL | 9:ca2e6010d9e2 | 59 | MOVS r3,#0xFF |
QL | 9:ca2e6010d9e2 | 60 | LSLS r3,r3,#16 |
QL | 9:ca2e6010d9e2 | 61 | ORRS r2,r3 ; set PRI_14 (PendSV) to 0xFF |
QL | 9:ca2e6010d9e2 | 62 | STR r2,[r1,#8] ; write the System 12-15 Priority Register |
QL | 9:ca2e6010d9e2 | 63 | LDR r2,[r1,#4] ; load the System 8-11 Priority Register |
QL | 9:ca2e6010d9e2 | 64 | LSLS r3,r3,#8 |
QL | 9:ca2e6010d9e2 | 65 | BICS r2,r3 ; set PRI_11 (SVCall) to 0x00 |
QL | 9:ca2e6010d9e2 | 66 | STR r2,[r1,#4] ; write the System 8-11 Priority Register |
QL | 9:ca2e6010d9e2 | 67 | |
QL | 9:ca2e6010d9e2 | 68 | MSR PRIMASK,r0 ; restore the original PRIMASK |
QL | 9:ca2e6010d9e2 | 69 | BX lr ; return to the caller |
QL | 9:ca2e6010d9e2 | 70 | |
QL | 9:ca2e6010d9e2 | 71 | |
QL | 9:ca2e6010d9e2 | 72 | ;***************************************************************************** |
QL | 9:ca2e6010d9e2 | 73 | ; |
QL | 9:ca2e6010d9e2 | 74 | ; The PendSV_Handler exception hanlder is used for handling asynchronous |
QL | 9:ca2e6010d9e2 | 75 | ; preemptions in QK. The use of the PendSV exception is the recommended |
QL | 9:ca2e6010d9e2 | 76 | ; and most efficient method for performing context switches with ARM Cortex. |
QL | 9:ca2e6010d9e2 | 77 | ; |
QL | 9:ca2e6010d9e2 | 78 | ; The PendSV exception should have the lowest priority in the whole system |
QL | 9:ca2e6010d9e2 | 79 | ; (0xFF, see QK_init). All other exeptions and interrupts should have higher |
QL | 9:ca2e6010d9e2 | 80 | ; priority. For example, for NVIC with 2 priority bits all interrupts and |
QL | 9:ca2e6010d9e2 | 81 | ; exceptions must have numerical value of priority lower than 0xC0. In this |
QL | 9:ca2e6010d9e2 | 82 | ; case the interrupt priority levels available to your applications are (in |
QL | 9:ca2e6010d9e2 | 83 | ; the order from the lowest urgency to the highest urgency): 0x80, 0x40, 0x00. |
QL | 9:ca2e6010d9e2 | 84 | ; |
QL | 9:ca2e6010d9e2 | 85 | ; Also, *all* ISRs in the QK application must trigger the PendSV exception |
QL | 9:ca2e6010d9e2 | 86 | ; by calling the QK_ISR_EXIT() macro. |
QL | 9:ca2e6010d9e2 | 87 | ; |
QL | 9:ca2e6010d9e2 | 88 | ; Due to tail-chaining and its lowest priority, the PendSV exception will be |
QL | 9:ca2e6010d9e2 | 89 | ; entered immediately after the exit from the *last* nested interrupt (or |
QL | 9:ca2e6010d9e2 | 90 | ; exception). In QK, this is exactly the time when the QK scheduler needs to |
QL | 9:ca2e6010d9e2 | 91 | ; check for the asynchronous preemptions. |
QL | 9:ca2e6010d9e2 | 92 | ; |
QL | 9:ca2e6010d9e2 | 93 | ;***************************************************************************** |
QL | 9:ca2e6010d9e2 | 94 | PendSV_Handler |
QL | 9:ca2e6010d9e2 | 95 | CPSID i ; disable interrupts at processor level |
QL | 9:ca2e6010d9e2 | 96 | BL QK_schedPrio_ ; check if we have preemption |
QL | 9:ca2e6010d9e2 | 97 | CMP r0,#0 ; is prio == 0 ? |
QL | 9:ca2e6010d9e2 | 98 | BNE.N scheduler ; if prio != 0, branch to scheduler |
QL | 9:ca2e6010d9e2 | 99 | |
QL | 9:ca2e6010d9e2 | 100 | CPSIE i ; enable interrupts at processor level |
QL | 9:ca2e6010d9e2 | 101 | MOVS r0,#0x6 |
QL | 9:ca2e6010d9e2 | 102 | MVNS r0,r0 ; r0:=~0x6=0xFFFFFFF9 |
QL | 9:ca2e6010d9e2 | 103 | BX r0 ; exception-return to the task |
QL | 9:ca2e6010d9e2 | 104 | |
QL | 9:ca2e6010d9e2 | 105 | scheduler |
QL | 9:ca2e6010d9e2 | 106 | MOVS r3,#1 |
QL | 9:ca2e6010d9e2 | 107 | LSLS r3,r3,#24 ; r3:=(1 << 24), set the T bit (new xpsr) |
QL | 9:ca2e6010d9e2 | 108 | LDR r2,=QK_sched_ ; address of the QK scheduler (new pc) |
QL | 9:ca2e6010d9e2 | 109 | LDR r1,=svc_ret ; return address after the call (new lr) |
QL | 9:ca2e6010d9e2 | 110 | PUSH {r1-r3} ; push xpsr,pc,lr |
QL | 9:ca2e6010d9e2 | 111 | SUB sp,sp,#(4*4) ; don't care for r12,r3,r2,r1 |
QL | 9:ca2e6010d9e2 | 112 | PUSH {r0} ; push the prio argument (new r0) |
QL | 9:ca2e6010d9e2 | 113 | MOVS r0,#0x6 |
QL | 9:ca2e6010d9e2 | 114 | MVNS r0,r0 ; r0:=~0x6=0xFFFFFFF9 |
QL | 9:ca2e6010d9e2 | 115 | BX r0 ; exception-return to the scheduler |
QL | 9:ca2e6010d9e2 | 116 | |
QL | 9:ca2e6010d9e2 | 117 | svc_ret |
QL | 9:ca2e6010d9e2 | 118 | CPSIE i ; enable interrupts to allow SVCall exception |
QL | 9:ca2e6010d9e2 | 119 | SVC 0 ; SV exception returns to the preempted task |
QL | 9:ca2e6010d9e2 | 120 | |
QL | 9:ca2e6010d9e2 | 121 | |
QL | 9:ca2e6010d9e2 | 122 | ;***************************************************************************** |
QL | 9:ca2e6010d9e2 | 123 | ; |
QL | 9:ca2e6010d9e2 | 124 | ; The SVC_Handler exception handler is used for returning back to the |
QL | 9:ca2e6010d9e2 | 125 | ; interrupted task. The SVCall exception simply removes its own interrupt |
QL | 9:ca2e6010d9e2 | 126 | ; stack frame from the stack and returns to the preempted task using the |
QL | 9:ca2e6010d9e2 | 127 | ; interrupt stack frame that must be at the top of the stack. |
QL | 9:ca2e6010d9e2 | 128 | ; |
QL | 9:ca2e6010d9e2 | 129 | ;***************************************************************************** |
QL | 9:ca2e6010d9e2 | 130 | SVC_Handler |
QL | 9:ca2e6010d9e2 | 131 | ADD sp,sp,#(8*4) ; remove one interrupt frame from the stack |
QL | 9:ca2e6010d9e2 | 132 | BX lr ; return to the preempted task |
QL | 9:ca2e6010d9e2 | 133 | |
QL | 9:ca2e6010d9e2 | 134 | ALIGN ; make sure the END is properly aligned |
QL | 9:ca2e6010d9e2 | 135 | END |