diff --git a/doxygen/Doxyfile b/doxygen/Doxyfile index ee1f8d8e..1f124ebe 100644 --- a/doxygen/Doxyfile +++ b/doxygen/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = QP/C++ -PROJECT_NUMBER = 7.1.1 +PROJECT_NUMBER = 7.1.2 PROJECT_BRIEF = "Real-Time Embedded Framework" PROJECT_LOGO = ../../ql-doxygen/images/logo_ql.png OUTPUT_DIRECTORY = diff --git a/doxygen/gs.dox b/doxygen/gs.dox index 486b9a5c..49ab1e80 100644 --- a/doxygen/gs.dox +++ b/doxygen/gs.dox @@ -144,7 +144,7 @@ The DPP example is provided for most supported boards as well as in the command- The Dining Philosophers Problem (DPP) example is described in the @webref{doc/AN_DPP.pdf, Application Note: Dining Philosophers Problem (DPP) Example}. -[![Application Note: Dining Philosophers Problem (DPP) Example](AN_DPP.jpg)](https://www.state-machine.com/doc/AN_Fly-n-Shoot.pdf) +[![Application Note: Dining Philosophers Problem (DPP) Example](AN_DPP.jpg)](https://www.state-machine.com/doc/AN_DPP.pdf) @note diff --git a/doxygen/history.dox b/doxygen/history.dox index 6da2ce2b..e8f01110 100644 --- a/doxygen/history.dox +++ b/doxygen/history.dox @@ -1,33 +1,23 @@ /** @page history Revision History -@section qpcpp_7_1_1 Version 7.1.1, 2022-09-30 -This release improves @ref srs_qs "software tracing" of the scheduler activity in the preemptive @ref srs_qk "QK" and @ref srs_qxk "QXK" kernels. - -@note -The QP framework "knows" the type of preemption (synchronous/asynchronous) and this information is now provided in the software trace to the user. - +@section qpcpp_7_1_2 Version 7.1.2, 2022-10-07 +This release improves preemption-threshold scheduling (PTS) in @ref srs_qk "QK" kernel, especially the generation of the software tracing information about the scheduler activity. Also, PTS has been removed from the @ref srs_qxk "QXK" kernel because of the inherent complexity of that kernel. Additionally, the default for #QF_TIMEEVT_CTR_SIZE has been increased from 2 to 4 bytes. This increases the default dynamic range for QTimeEvt counters to 32-bits. __Source__ -- Added new pre-defined QS trace records: - + QP::QS_SCHED_PREEMPT - for reporting *asynchronous* preemption - + QP::QS_SCHED_RESTORE - for reporting restoring the context - after an *asynchronous* preemption -- Added parameter `asynch` to QK_activate_(). This parameter is used to indicate the type of preemption and is set to 1 for asynchronous preemption and 0 for synchronous. This parameter is used in the #Q_SPY configuration only. -- changed all calls to QK_activate_() to add the `asynch` parameter, whereas all cases of synchronous preemption call QK_activate_(0U), while cases for asynchronous preemption call QK_activate_(1U); -- Added parameter `asynch` to QXK_activate_(). This parameter indicates the asynchronous preemption. This parameter is used in the #Q_SPY configuration only. -- Added parameter `asynch` to QXK_sched_(). This parameter is used to indicate the type of preemption and is set to 1 for asynchronous preemption and 0 for synchronous. This parameter is used in the #Q_SPY configuration only. -- changed all calls to QXK_sched_() and QXK_activate_() to add the `asynch` parameter, whereas all cases of synchronous preemption call QXK_sched_(0U)/XK_activate_(0U), while cases for asynchronous preemption call QXK_sched_(1U)/XK_activate_(1U); +- Modified QK_sched_() and QK_activate_() +- Modified QXK_sched_() and QXK_activate_() +- Added QXK_contextSw() to handle context switching (generation of software tracing information and invoking of the QXK_onContextSw() callback, if configured - increased default for #QF_TIMEEVT_CTR_SIZE 4 - changed inclusion guards in the QP/C++ header files (e.g. `QF_HPP` -> `QP_INC_QF_HPP_`) for compliance with the updated Quantum Leaps coding standard and to make the names more unique. __Ports__ -- All QK ports have been updated to set the `asynch` parameter for calling QK_activate_() -- All QXK ports have been updated to set the `asynch` parameter for calling QXK_sched_()/XK_activate_() +- Modified QXK ports (assembly) to call QXK_contextSw() +- Added port to RISC-V with the cooperative @ref srs_qvk "QV" kernel __Testing__ -- Added new directory `qpcpp/test/` for **system**-level testing QP/C++ itself. +- Added new directory `qpcpp/test/` for **system**-level testing of QP/C itself. - Added new tests for QK: `qpcpp/test/qk` - Added new tests for QXK: `qpcpp/test/qutest/qxk` @@ -35,7 +25,7 @@ __Testing__ The `qpcpp/test/` directory is planned to contain a growing number of system-level tests, which are based on QUTest, but *without* the QP-stub. The tests take advantage of the new QUTest configuration, where the QP-stub is NOT included (because the actual QP framework is linked). This configuration is activated by defining macro `Q_UTEST=0`. @attention -Many tests provided in the `qpcpp/test/` directory run only on embedded targets and cannot run on the host machine. +Most tests provided in the `qpcpp/test/` directory run only on embedded targets and cannot run on the host machine. @section qpcpp_7_1_0 Version 7.1.0, 2022-08-30 diff --git a/doxygen/metrics.dox b/doxygen/metrics.dox index fc62d98f..208b6bfe 100644 --- a/doxygen/metrics.dox +++ b/doxygen/metrics.dox @@ -66,8 +66,8 @@ 14 3 70 1 14 QP::QS::rxPut@805-818@..\include\qs.hpp 9 1 49 5 9 QP::QActiveDummy::start@1517-1525@..\include\qs.hpp 3 1 18 0 3 QP::QSpyId::getPrio@134-136@..\include\qs_dummy.hpp - 3 1 11 0 3 QP::QXThread::getTimeEvt@210-212@..\include\qxk.hpp - 9 1 49 5 9 QP::QXThread::start@312-320@..\include\qxk.hpp + 3 1 11 0 3 QP::QXThread::getTimeEvt@208-210@..\include\qxk.hpp + 9 1 49 5 9 QP::QXThread::start@310-318@..\include\qxk.hpp 2 1 15 2 3 QP::QEvt@101-103@..\src\qf\qep_hsm.cpp 4 1 27 1 4 QP::QHsm::QHsm@130-133@..\src\qf\qep_hsm.cpp 50 7 303 2 71 QP::QHsm::init@136-206@..\src\qf\qep_hsm.cpp @@ -200,7 +200,7 @@ NLOC Avg.NLOC AvgCCN Avg.token function_cnt file 25 0.0 0.0 0.0 0 ..\include\qs_pkg.hpp 9 0.0 0.0 0.0 0 ..\include\quit.hpp 8 0.0 0.0 0.0 0 ..\include\qv.hpp - 122 6.0 1.0 30.0 2 ..\include\qxk.hpp + 120 6.0 1.0 30.0 2 ..\include\qxk.hpp 323 37.5 5.9 199.0 8 ..\src\qf\qep_hsm.cpp 307 41.4 7.1 228.1 7 ..\src\qf\qep_msm.cpp 2 0.0 0.0 0.0 0 ..\src\qf\qf_act.cpp @@ -231,6 +231,6 @@ NLOC Avg.NLOC AvgCCN Avg.token function_cnt file ========================================================================================== Total nloc Avg.NLOC AvgCCN Avg.token Fun Cnt Warning cnt Fun Rt nloc Rt ------------------------------------------------------------------------------------------ - 4523 18.2 3.2 108.0 176 3 0.02 0.09 + 4521 18.2 3.2 108.0 176 3 0.02 0.09 @endcode */ diff --git a/doxygen/snippets/qf_main.cpp b/doxygen/snippets/qf_main.cpp index 7b254105..2b3dfd86 100644 --- a/doxygen/snippets/qf_main.cpp +++ b/doxygen/snippets/qf_main.cpp @@ -1,6 +1,6 @@ -#include "qpc.h" -#include "dpp.h" -#include "bsp.h" +#include "qpcpp.hpp" +#include "dpp.hpp" +#include "bsp.hpp" namespace DPP { @@ -12,14 +12,13 @@ int_t main(void) { // object dictionaries... QS_OBJ_DICTIONARY(AO_Table); - QS_OBJ_DICTIONARY(AO_Philo[0]); - QS_OBJ_DICTIONARY(AO_Philo[1]); - QS_OBJ_DICTIONARY(AO_Philo[2]); - QS_OBJ_DICTIONARY(AO_Philo[3]); - QS_OBJ_DICTIONARY(AO_Philo[4]); + for (std::uint8_t n = 0U; n < N_PHILO; ++n) { + QS_OBJ_ARR_DICTIONARY(AO_Philo[n], n); + } + // initialize publish-subscribe... static QP::QSubscrList subscrSto[MAX_PUB_SIG]; - QP::QActive::psInit(subscrSto, Q_DIM(subscrSto)); // init publish-subscribe + QP::QActive::psInit(subscrSto, Q_DIM(subscrSto)); // initialize event pools... static QF_MPOOL_EL(TableEvt) smlPoolSto[2*N_PHILO]; @@ -29,15 +28,21 @@ int_t main(void) { // start the active objects... static QP::QEvt const *philoQueueSto[N_PHILO][N_PHILO]; for (std::uint8_t n = 0U; n < N_PHILO; ++n) { - AO_Philo[n]->start(n + 1U, - philoQueueSto[n], Q_DIM(philoQueueSto[n]), - nullptr, 0U); + AO_Philo[n]->start( + Q_PRIO(n + 1U, N_PHILO), // QF-priority/preemption-threshold + philoQueueSto[n], // event queue storage + Q_DIM(philoQueueSto[n]), // event queue length [events] + nullptr, // stack storage (not used) + 0U); // stack size [bytes] (not used) } static QP::QEvt const *tableQueueSto[N_PHILO]; - AO_Table->start(N_PHILO + 1U, - tableQueueSto, Q_DIM(tableQueueSto), - nullptr, 0U); + AO_Table->start( + N_PHILO + 1U, + tableQueueSto, + Q_DIM(tableQueueSto), + nullptr, + 0U); return QP::QF::run(); // run the QF application } diff --git a/examples/arm-cm/dpp_efm32-slstk3401a/qk/main.cpp b/examples/arm-cm/dpp_efm32-slstk3401a/qk/main.cpp index 847ce07d..d49507cc 100644 --- a/examples/arm-cm/dpp_efm32-slstk3401a/qk/main.cpp +++ b/examples/arm-cm/dpp_efm32-slstk3401a/qk/main.cpp @@ -1,11 +1,11 @@ //============================================================================ // DPP example -// Last updated for version 7.1.1 -// Last updated on 2022-09-23 +// Last updated for version 7.1.2 +// Last updated on 2022-10-05 // -// Q u a n t u m L e a P s -// --------------------------- -// innovating embedded systems +// Q u a n t u m L e a P s +// ------------------------ +// Modern Embedded Software // // Copyright (C) Quantum Leaps, LLC. All rights reserved. // @@ -65,11 +65,11 @@ int main() { } // example of prioritizing the Ticker0 active object - DPP::the_Ticker0->start(Q_PRIO(N_PHILO + 1U, 2U), // priority + DPP::the_Ticker0->start(N_PHILO + 1U, // priority 0, 0, 0, 0); DPP::AO_Table->start( - (N_PHILO + 2U, // QF-prio/preempt-thre. + N_PHILO + 2U, // QF-prio/preempt-thre. tableQueueSto, // event queue storage Q_DIM(tableQueueSto), // queue length [events] nullptr, 0U); // no stack storage diff --git a/examples/arm-cm/dpp_efm32-slstk3401a/qxk/armclang/dpp-qxk.uvoptx b/examples/arm-cm/dpp_efm32-slstk3401a/qxk/armclang/dpp-qxk.uvoptx index 19d27a72..b9783b64 100644 --- a/examples/arm-cm/dpp_efm32-slstk3401a/qxk/armclang/dpp-qxk.uvoptx +++ b/examples/arm-cm/dpp_efm32-slstk3401a/qxk/armclang/dpp-qxk.uvoptx @@ -152,9 +152,9 @@ 0 0 - 355 + 362 1 -
2142
+
2144
0 0 0 @@ -163,39 +163,23 @@ 1 ..\bsp.cpp - \\dpp_qxk\../bsp.cpp\355 + \\dpp_qxk\../bsp.cpp\362
1 0 - 292 + 355 1 -
7064
+
0
0 0 0 0 0 - 1 - ..\..\..\..\..\src\qf\qf_time.cpp + 0 + ..\bsp.cpp - \\dpp_qxk\../../../../../src/qf/qf_time.cpp\292 -
- - 2 - 0 - 112 - 1 -
6920
- 0 - 0 - 0 - 0 - 0 - 1 - ..\..\..\..\..\src\qf\qf_time.cpp - - \\dpp_qxk\../../../../../src/qf/qf_time.cpp\112 +
@@ -753,7 +737,7 @@ QP - 0 + 1 0 0 0 diff --git a/examples/arm-cm/dpp_efm32-slstk3401a/qxk/main.cpp b/examples/arm-cm/dpp_efm32-slstk3401a/qxk/main.cpp index 0900f0d0..6a466168 100644 --- a/examples/arm-cm/dpp_efm32-slstk3401a/qxk/main.cpp +++ b/examples/arm-cm/dpp_efm32-slstk3401a/qxk/main.cpp @@ -1,7 +1,7 @@ //============================================================================ // DPP example for QXK -// Last updated for version 7.1.1 -// Last updated on 2022-09-23 +// Last updated for version 7.1.2 +// Last updated on 2022-10-05 // // Q u a n t u m L e a P s // --------------------------- @@ -78,7 +78,7 @@ int main() { // start the Philo active objects... for (uint8_t n = 0U; n < N_PHILO; ++n) { DPP::AO_Philo[n]->start( - Q_PRIO(n + 3U, N_PHILO + 2U), // QF-prio/preempt-thre. + n + 3U, // QF-prio/preempt-thre. philoQueueSto[n], // event queue storage Q_DIM(philoQueueSto[n]), // queue length [events] nullptr, 0U); // no stack storage diff --git a/examples/arm-cm/dpp_ek-tm4c123gxl/qk/main.cpp b/examples/arm-cm/dpp_ek-tm4c123gxl/qk/main.cpp index 9d41617a..dbb72858 100644 --- a/examples/arm-cm/dpp_ek-tm4c123gxl/qk/main.cpp +++ b/examples/arm-cm/dpp_ek-tm4c123gxl/qk/main.cpp @@ -1,11 +1,11 @@ //============================================================================ // DPP example -// Last updated for version 6.3.3 -// Last updated on 2018-06-23 +// Last updated for version 7.1.2 +// Last updated on 2022-10-05 // -// Q u a n t u m L e a P s -// --------------------------- -// innovating embedded systems +// Q u a n t u m L e a P s +// ------------------------ +// Modern Embedded Software // // Copyright (C) Quantum Leaps, LLC. All rights reserved. // @@ -57,17 +57,18 @@ int main() { // start the active objects... for (uint8_t n = 0U; n < N_PHILO; ++n) { - DPP::AO_Philo[n]->start((uint_fast8_t)(n + 1U), // priority - philoQueueSto[n], Q_DIM(philoQueueSto[n]), - nullptr, 0U); + DPP::AO_Philo[n]->start( + Q_PRIO(n + 1U, N_PHILO), // QF-prio/preempt-thre. + philoQueueSto[n], Q_DIM(philoQueueSto[n]), + nullptr, 0U); } // example of prioritizing the Ticker0 active object - DPP::the_Ticker0->start((uint_fast8_t)(N_PHILO + 1U), // priority + DPP::the_Ticker0->start(N_PHILO + 1U, // priority 0, 0, 0, 0); - DPP::AO_Table->start((uint_fast8_t)(N_PHILO + 2U), // priority + DPP::AO_Table->start(N_PHILO + 2U, // priority tableQueueSto, Q_DIM(tableQueueSto), nullptr, 0U); diff --git a/examples/arm-cm/dpp_nucleo-h743zi/qk/main.cpp b/examples/arm-cm/dpp_nucleo-h743zi/qk/main.cpp index 7e551378..5c6c2d99 100644 --- a/examples/arm-cm/dpp_nucleo-h743zi/qk/main.cpp +++ b/examples/arm-cm/dpp_nucleo-h743zi/qk/main.cpp @@ -1,13 +1,13 @@ //============================================================================ // DPP example -// Last updated for: @qpcpp_7_0_0 -// Last updated on 2022-02-28 +// Last updated for version 7.1.2 +// Last updated on 2022-10-05 // -// Q u a n t u m L e a P s -// --------------------------- -// innovating embedded systems +// Q u a n t u m L e a P s +// ------------------------ +// Modern Embedded Software // -// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. +// 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 @@ -25,7 +25,7 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// along with this program. If not, see . // // Contact information: // @@ -54,12 +54,15 @@ int main() { // start the active objects... for (uint8_t n = 0U; n < N_PHILO; ++n) { - DPP::AO_Philo[n]->start((uint_fast8_t)(n + 1U), // priority - philoQueueSto[n], Q_DIM(philoQueueSto[n]), - nullptr, 0U); + DPP::AO_Philo[n]->start( + Q_PRIO(n + 1U, N_PHILO), // QF-prio/preempt-thre. + philoQueueSto[n], // event queue storage + Q_DIM(philoQueueSto[n]), // queue length [events] + nullptr, 0U); // no stack storage } - DPP::AO_Table->start((uint_fast8_t)(N_PHILO + 1U), // priority + DPP::AO_Table->start( + N_PHILO + 1U, // priority tableQueueSto, Q_DIM(tableQueueSto), nullptr, 0U); diff --git a/examples/arm-cm/dpp_nucleo-l053r8/qk/main.cpp b/examples/arm-cm/dpp_nucleo-l053r8/qk/main.cpp index ecebcdb3..6091f666 100644 --- a/examples/arm-cm/dpp_nucleo-l053r8/qk/main.cpp +++ b/examples/arm-cm/dpp_nucleo-l053r8/qk/main.cpp @@ -1,11 +1,11 @@ //============================================================================ // DPP example -// Last updated for version 6.3.3 -// Last updated on 2018-06-23 +// Last updated for version 7.1.2 +// Last updated on 2022-10-05 // -// Q u a n t u m L e a P s -// --------------------------- -// innovating embedded systems +// Q u a n t u m L e a P s +// ------------------------ +// Modern Embedded Software // // Copyright (C) Quantum Leaps, LLC. All rights reserved. // @@ -55,14 +55,20 @@ int main() { // start the active objects... for (uint8_t n = 0U; n < N_PHILO; ++n) { - DPP::AO_Philo[n]->start((uint8_t)(n + 1U), - philoQueueSto[n], Q_DIM(philoQueueSto[n]), - nullptr, 0U); + DPP::AO_Philo[n]->start( + Q_PRIO(n + 1U, N_PHILO), // QF-prio/preempt-thre. + philoQueueSto[n], // event queue storage + Q_DIM(philoQueueSto[n]), // queue length [events] + nullptr, 0U); // no stack storage } + // leave the priority level (N_PHILO + 1) free for the mutex in BSP - DPP::AO_Table->start((uint8_t)(N_PHILO + 2U), - tableQueueSto, Q_DIM(tableQueueSto), - nullptr, 0U); + + DPP::AO_Table->start( + N_PHILO + 2U, // QF-prio/preempt-thre. + tableQueueSto, // event queue storage + Q_DIM(tableQueueSto), // queue length [events] + nullptr, 0U); // no stack storage return QP::QF::run(); // run the QF application } diff --git a/examples/arm-cm/dpp_nucleo-l152re/qk/main.cpp b/examples/arm-cm/dpp_nucleo-l152re/qk/main.cpp index f19ec8ae..53f76dd0 100644 --- a/examples/arm-cm/dpp_nucleo-l152re/qk/main.cpp +++ b/examples/arm-cm/dpp_nucleo-l152re/qk/main.cpp @@ -1,13 +1,13 @@ //============================================================================ // DPP example -// Last updated for version 6.3.3 -// Last updated on 2018-06-23 +// Last updated for version 7.1.2 +// Last updated on 2022-10-05 // -// Q u a n t u m L e a P s -// --------------------------- -// innovating embedded systems +// Q u a n t u m L e a P s +// ------------------------ +// Modern Embedded Software // -// 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 @@ -56,13 +56,17 @@ int main() { // start the active objects... for (uint8_t n = 0U; n < N_PHILO; ++n) { - DPP::AO_Philo[n]->start((uint8_t)(n + 1U), - philoQueueSto[n], Q_DIM(philoQueueSto[n]), - nullptr, 0U); + DPP::AO_Philo[n]->start( + Q_PRIO(n + 1U, N_PHILO), // QF-prio/preempt-thre. + philoQueueSto[n], // event queue storage + Q_DIM(philoQueueSto[n]), // queue length [events] + nullptr, 0U); // no stack storage } - DPP::AO_Table->start((uint8_t)(N_PHILO + 1U), - tableQueueSto, Q_DIM(tableQueueSto), - nullptr, 0U); + DPP::AO_Table->start( + N_PHILO + 1U, // QF-prio/preempt-thre. + tableQueueSto, // event queue storage + Q_DIM(tableQueueSto), // queue length [events] + nullptr, 0U); // no stack storage return QP::QF::run(); // run the QF application } diff --git a/examples/arm-cm/dpp_nucleo-l552ze/qk/main.cpp b/examples/arm-cm/dpp_nucleo-l552ze/qk/main.cpp index 7e551378..bac89e38 100644 --- a/examples/arm-cm/dpp_nucleo-l552ze/qk/main.cpp +++ b/examples/arm-cm/dpp_nucleo-l552ze/qk/main.cpp @@ -1,13 +1,13 @@ //============================================================================ // DPP example -// Last updated for: @qpcpp_7_0_0 -// Last updated on 2022-02-28 +// Last updated for version 7.1.2 +// Last updated on 2022-10-05 // -// Q u a n t u m L e a P s -// --------------------------- -// innovating embedded systems +// Q u a n t u m L e a P s +// ------------------------ +// Modern Embedded Software // -// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved. +// 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 @@ -25,7 +25,7 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// along with this program. If not, see . // // Contact information: // @@ -54,14 +54,18 @@ int main() { // start the active objects... for (uint8_t n = 0U; n < N_PHILO; ++n) { - DPP::AO_Philo[n]->start((uint_fast8_t)(n + 1U), // priority - philoQueueSto[n], Q_DIM(philoQueueSto[n]), - nullptr, 0U); + DPP::AO_Philo[n]->start( + Q_PRIO(n + 1U, N_PHILO), // QF-prio/preempt-thre. + philoQueueSto[n], // event queue storage + Q_DIM(philoQueueSto[n]), // queue length [events] + nullptr, 0U); // no stack storage } - DPP::AO_Table->start((uint_fast8_t)(N_PHILO + 1U), // priority - tableQueueSto, Q_DIM(tableQueueSto), - nullptr, 0U); + DPP::AO_Table->start( + N_PHILO + 1U, // QF-prio/preempt-thre. + tableQueueSto, // event queue storage + Q_DIM(tableQueueSto), // queue length [events] + nullptr, 0U); // no stack storage return QP::QF::run(); // run the QF application } diff --git a/examples/arm-cm/dpp_stm32f4-discovery/qk/main.cpp b/examples/arm-cm/dpp_stm32f4-discovery/qk/main.cpp index 6040d007..327b7342 100644 --- a/examples/arm-cm/dpp_stm32f4-discovery/qk/main.cpp +++ b/examples/arm-cm/dpp_stm32f4-discovery/qk/main.cpp @@ -1,11 +1,11 @@ //============================================================================ // DPP example -// Last updated for version 6.0.4 -// Last updated on 2018-01-07 +// Last updated for version 7.1.2 +// Last updated on 2022-10-05 // -// Q u a n t u m L e a P s -// --------------------------- -// innovating embedded systems +// Q u a n t u m L e a P s +// ------------------------ +// Modern Embedded Software // // Copyright (C) Quantum Leaps, LLC. All rights reserved. // @@ -64,19 +64,24 @@ int main() { // start the active objects... for (uint8_t n = 0U; n < N_PHILO; ++n) { - DPP::AO_Philo[n]->start((uint_fast8_t)(n + 1U), // priority - philoQueueSto[n], Q_DIM(philoQueueSto[n]), - nullptr, 0U); + DPP::AO_Philo[n]->start( + Q_PRIO(n + 1U, N_PHILO), // QF-prio/preempt-thre. + philoQueueSto[n], // event queue storage + Q_DIM(philoQueueSto[n]), // queue length [events] + nullptr, 0U); // no stack storage } // example of prioritizing the Ticker0 active object - DPP::the_Ticker0->start((uint_fast8_t)(N_PHILO + 1U), // priority + DPP::the_Ticker0->start( + N_PHILO + 1U, // priority (QP::QEvt const **)0, 0U, nullptr, 0U); - DPP::AO_Table->start((uint_fast8_t)(N_PHILO + 2U), // priority - tableQueueSto, Q_DIM(tableQueueSto), - nullptr, 0U); + DPP::AO_Table->start( + N_PHILO + 2U, // QF-prio/preempt-thre. + tableQueueSto, // event queue storage + Q_DIM(tableQueueSto), // queue length [events] + nullptr, 0U); // no stack storage return QP::QF::run(); // run the QF application } diff --git a/examples/arm-cr/dpp_launchxl2-tms57012/qk/main.cpp b/examples/arm-cr/dpp_launchxl2-tms57012/qk/main.cpp index 8366e1f1..bcccf811 100644 --- a/examples/arm-cr/dpp_launchxl2-tms57012/qk/main.cpp +++ b/examples/arm-cr/dpp_launchxl2-tms57012/qk/main.cpp @@ -1,11 +1,11 @@ //============================================================================ // DPP example -// Last updated for version 5.6.2 -// Last updated on 2016-03-31 +// Last updated for version 7.1.2 +// Last updated on 2022-10-05 // -// Q u a n t u m L e a P s -// --------------------------- -// innovating embedded systems +// Q u a n t u m L e a P s +// ------------------------ +// Modern Embedded Software // // Copyright (C) Quantum Leaps, LLC. All rights reserved. // @@ -28,7 +28,7 @@ // along with this program. If not, see . // // Contact information: -// https://state-machine.com +// // //============================================================================ #include "qpcpp.hpp" @@ -48,7 +48,8 @@ int main() { DPP::BSP::init(); // initialize the BSP - QP::QActive::psInit(subscrSto, Q_DIM(subscrSto)); // init publish-subscribe + // init publish-subscribe + QP::QActive::psInit(subscrSto, Q_DIM(subscrSto)); // initialize event pools... QP::QF::poolInit(smlPoolSto, @@ -56,13 +57,17 @@ int main() { // start the active objects... for (uint8_t n = 0U; n < N_PHILO; ++n) { - DPP::AO_Philo[n]->start((uint_fast8_t)(n + 1U), - philoQueueSto[n], Q_DIM(philoQueueSto[n]), - nullptr, 0U); + DPP::AO_Philo[n]->start( + Q_PRIO(n + 1U, N_PHILO), // QF-prio/preempt-thre. + philoQueueSto[n], // event queue storage + Q_DIM(philoQueueSto[n]), // queue length [events] + nullptr, 0U); // no stack storage } - DPP::AO_Table->start((uint_fast8_t)(N_PHILO + 1U), - tableQueueSto, Q_DIM(tableQueueSto), - nullptr, 0U); + DPP::AO_Table->start( + N_PHILO + 1U, // QF-prio/preempt-thre. + tableQueueSto, // event queue storage + Q_DIM(tableQueueSto), // queue length [events] + nullptr, 0U); // no stack storage return QP::QF::run(); // run the QF application } diff --git a/include/qep.hpp b/include/qep.hpp index 1c30b234..3a911b1a 100644 --- a/include/qep.hpp +++ b/include/qep.hpp @@ -52,7 +52,7 @@ // major version number, Y is a 1-digit minor version number, and Z is // a 1-digit release number. // -#define QP_VERSION 710U +#define QP_VERSION 712U //! The current QP version as a zero terminated string literal. // @@ -61,10 +61,10 @@ // major version number, Y is a 1-digit minor version number, and Z is // a 1-digit release number. // -#define QP_VERSION_STR "7.1.0" +#define QP_VERSION_STR "7.1.2" -//! Encrypted current QP release (7.1.0) and date (2022-08-30) -#define QP_RELEASE 0x7C600159U +//! Encrypted current QP release (7.1.2) and date (2022-10-07) +#define QP_RELEASE 0x7C44FF47U //============================================================================ // Global namespace... diff --git a/include/qf.hpp b/include/qf.hpp index d82a4eea..a863ac2e 100644 --- a/include/qf.hpp +++ b/include/qf.hpp @@ -201,7 +201,7 @@ using QTimeEvtCtr = std::uint32_t; //! When QP runs on top of 3rd-party kernels/RTOSes or general-purpose //! operating systems, sthe second priority can have different meaning, //! depending on the specific RTOS/GPOS used. -using QPrioSpec = std::uint_fast16_t; +using QPrioSpec = std::uint16_t; //${QF-types::QSchedStatus} .................................................. //! The scheduler lock status used in some real-time kernels diff --git a/include/qk.hpp b/include/qk.hpp index 9e4ce6e0..fa326d10 100644 --- a/include/qk.hpp +++ b/include/qk.hpp @@ -150,8 +150,9 @@ extern QK_Attr QK_attr_; //! that (1) has events to process and (2) has priority that is above the //! current priority. //! -//! @returns the 1-based priority of the the active object, or zero if -//! no eligible active object is ready to run. +//! @returns +//! The QF-priority of the next active object to activate, or zero +//! if no activation of AO is needed. //! //! @attention //! QK_sched_() must be always called with interrupts **disabled** and @@ -162,17 +163,14 @@ std::uint_fast8_t QK_sched_() noexcept; //! QK activator activates the next active object. The activated AO preempts //! the currently executing AOs //! -//! @param[in] asynch flag conveying the type of activation: -//! != 0 for asynchronous activation and -//! == 0 for synchronous activation //! @details //! QK_activate_() activates ready-to run AOs that are above the initial -//! active priority (QK_attr_.actPrio). +//! preemption-threshold. //! //! @note //! The activator might enable interrupts internally, but always returns with //! interrupts **disabled**. -void QK_activate_(std::uint_fast8_t const asynch) noexcept; +void QK_activate_() noexcept; //${QK-extern-C::QK_onContextSw} ............................................. #ifdef QK_ON_CONTEXT_SW @@ -251,7 +249,7 @@ void QK_onContextSw( static_cast((me_)->m_prio)); \ if (!QK_ISR_CONTEXT_()) { \ if (QK_sched_() != 0U) { \ - QK_activate_(0U); \ + QK_activate_(); \ } \ } \ } while (false) diff --git a/include/qs.hpp b/include/qs.hpp index 2950c57c..44c35cef 100644 --- a/include/qs.hpp +++ b/include/qs.hpp @@ -205,7 +205,7 @@ enum QSpyPre : std::int8_t { QS_SCHED_UNLOCK, //!< scheduler was unlocked QS_SCHED_NEXT, //!< scheduler found next task to execute QS_SCHED_IDLE, //!< scheduler became idle - QS_SCHED_RESUME, //!< scheduler resumed previous task (not idle) + QS_SCHED_RESUME, //!< scheduler resumed a (blocked) task // [55] Additional QEP records QS_QEP_TRAN_HIST, //!< a tran to history was taken diff --git a/include/qxk.hpp b/include/qxk.hpp index 5f5c2e1d..8906d04a 100644 --- a/include/qxk.hpp +++ b/include/qxk.hpp @@ -145,10 +145,8 @@ void schedUnlock(QSchedStatus const stat) noexcept; //${QXK::QXK-base::Timeouts} ................................................. //! timeout signals for extended threads enum Timeouts : enum_t { - DELAY_SIG = Q_USER_SIG, - QUEUE_SIG, - SEMA_SIG, - MUTEX_SIG + DELAY_SIG = 1, + TIMEOUT_SIG }; } // namespace QXK @@ -600,15 +598,9 @@ public: //! the priority and priority-threshold of the holding thread to the //! priority specification in `prioSpec` (see QP::QPrioSpec). //! - //! @attention - //! When the priority-ceiling protocol is used (`prioSpec != 0`), the - //! QF-priority specified in `prioSpec` must be unused by any other thread - //! or mutex. Also, the priority-threshold must be higher or equal to the - //! threshold of any thread that uses this mutex (see QP::QPrioSpec). - //! //! @usage //! @include qxk_mutex.cpp - void init(QPrioSpec const prioSpec) noexcept override; + void init(QPrioSpec const prioSpec) noexcept; //! try to lock the QXK priority-ceiling mutex QP::QXMutex //! @@ -684,8 +676,8 @@ extern "C" { struct QXK_Attr { QP::QActive * volatile curr; //!< currently executing thread QP::QActive * volatile next; //!< next thread to execute - std::uint8_t volatile actPrio; //!< prio of the active AO - std::uint8_t volatile actThre; //!< active preemption-threshold + QP::QActive * volatile prev; //!< previous thread + std::uint8_t volatile actPrio; //!< QF-prio of the active AO std::uint8_t volatile lockCeil; //!< lock preemption-ceiling (0==no-lock) std::uint8_t volatile lockHolder; //!< prio of the lock holder }; @@ -697,9 +689,6 @@ extern QXK_Attr QXK_attr_; //${QXK-extern-C::QXK_sched_} ................................................ //! QXK scheduler finds the highest-priority thread ready to run //! -//! @param[in] asynch flag conveying the type of scheduling: -//! != 0 for asynchronous scheduling and -//! == 0 for synchronous scheduling //! @details //! The QXK scheduler finds the priority of the highest-priority thread //! that is ready to run. @@ -710,15 +699,12 @@ extern QXK_Attr QXK_attr_; //! @attention //! QXK_sched_() must be always called with interrupts **disabled** and //! returns with interrupts **disabled**. -std::uint_fast8_t QXK_sched_(std::uint_fast8_t const asynch) noexcept; +std::uint_fast8_t QXK_sched_() noexcept; //${QXK-extern-C::QXK_activate_} ............................................. //! QXK activator activates the next active object. The activated AO preempts //! the currently executing AOs //! -//! @param[in] asynch flag conveying the type of activation: -//! != 0 for asynchronous activation and -//! == 0 for synchronous activation //! @attention //! QXK_activate_() must be always called with interrupts **disabled** and //! returns with interrupts **disabled**. @@ -726,10 +712,13 @@ std::uint_fast8_t QXK_sched_(std::uint_fast8_t const asynch) noexcept; //! @note //! The activate function might enable interrupts internally, but it always //! returns with interrupts **disabled**. -void QXK_activate_(std::uint_fast8_t const asynch) noexcept; +void QXK_activate_() noexcept; //${QXK-extern-C::QXK_current} ............................................... -//! return the currently executing active-object/thread +//! obtain the currently executing active-object/thread +//! +//! @returns +//! pointer to the currently executing active-object/thread QP::QActive * QXK_current() noexcept; //${QXK-extern-C::QXK_stackInit_} ............................................ @@ -740,6 +729,22 @@ void QXK_stackInit_( void * const stkSto, std::uint_fast16_t const stkSize) noexcept; +//${QXK-extern-C::QXK_contextSw} ............................................. +#if defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) +//! QXK context switch management +//! +//! @details +//! This function performs software tracing (if #Q_SPY is defined) +//! and calls QXK_onContextSw() (if #QXK_ON_CONTEXT_SW is defined) +//! +//! @param[in] next pointer to the next thread (NULL for basic-thread) +//! +//! @attention +//! QXK_contextSw() is invoked with interrupts **disabled** and must also +//! return with interrupts **disabled**. +void QXK_contextSw(QP::QActive * const next); +#endif // defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) + //${QXK-extern-C::QXK_onContextSw} ........................................... #ifdef QXK_ON_CONTEXT_SW //! QXK context switch callback (customized in BSPs for QXK) @@ -856,8 +861,8 @@ void QXK_threadExit_(); QF::readySet_.insert( \ static_cast((me_)->m_prio)); \ if (!QXK_ISR_CONTEXT_()) { \ - if (QXK_sched_(0U) != 0U) { \ - QXK_activate_(0U); \ + if (QXK_sched_() != 0U) { \ + QXK_activate_(); \ } \ } \ } while (false) diff --git a/ports/arm-cm/qxk/armclang/qxk_port.cpp b/ports/arm-cm/qxk/armclang/qxk_port.cpp index 4d225fe1..e387eb55 100644 --- a/ports/arm-cm/qxk/armclang/qxk_port.cpp +++ b/ports/arm-cm/qxk/armclang/qxk_port.cpp @@ -23,8 +23,8 @@ * ============================================================================*/ /*! -* @date Last updated on: 2022-09-04 -* @version Last updated for: @ref qpcpp_7_1_1 +* @date Last updated on: 2022-10-04 +* @version Last updated for: @ref qpcpp_7_1_2 * * @file * @brief QXK/C++ port to ARM Cortex-M, ARM-CLANG toolset @@ -165,21 +165,21 @@ void QXK_stackInit_(void *thr, QP::QXThreadHandler const handler, /* NOTE: keep in synch with struct QXK_Attr in "qxk.hpp" !!! */ #define QXK_CURR 0 #define QXK_NEXT 4 -#define QXK_ACT_THRE 9 +#define QXK_ACT_PRIO 12 /* make sure that the offsets match the QXK declaration in "qxk.hpp" */ Q_ASSERT_STATIC(QXK_CURR == offsetof(QXK_Attr, curr)); Q_ASSERT_STATIC(QXK_NEXT == offsetof(QXK_Attr, next)); -Q_ASSERT_STATIC(QXK_ACT_THRE == offsetof(QXK_Attr, actThre)); +Q_ASSERT_STATIC(QXK_ACT_PRIO == offsetof(QXK_Attr, actPrio)); + /* offsets within struct QActive; NOTE: keep in synch with "qf.hpp" !!! */ #define QACTIVE_OSOBJ 28 #define QACTIVE_PRIO 36 -#define QACTIVE_PTHRE 37 /* make sure that the offsets match the QXK declaration in "qf.hpp" */ Q_ASSERT_STATIC(QACTIVE_OSOBJ == offsetof(QP::QActive, m_osObject)); -Q_ASSERT_STATIC(QACTIVE_PTHRE == offsetof(QP::QActive, m_pthre)); +Q_ASSERT_STATIC(QACTIVE_PRIO == offsetof(QP::QActive, m_prio)); /* helper macros to "stringify" values */ #define VAL(x) #x @@ -273,11 +273,6 @@ __asm volatile ( " ADD r0,sp,#(5*4) \n" /* r0 := 5 registers below the top of stack */ " STM r0!,{r1-r3} \n" /* save xpsr,pc,lr */ -#ifdef Q_SPY - " MOVS r0,#1 \n" /* set the parameter 'asynch` */ - " STR r0,[sp] \n" /* for call QK_activate_(asynch == 1) */ -#endif /* Q_SPY */ - " MOVS r0,#6 \n" " MVNS r0,r0 \n" /* r0 := ~6 == 0xFFFFFFF9 */ #if (__ARM_ARCH != 6) /* ARMv7-M or higher */ @@ -328,9 +323,9 @@ __asm volatile ( * r12 -> QXK_attr_.next / basic-thread */ "PendSV_restore_ao: \n" - " MOVS r0,#0 \n" - " STR r0,[r3,#" STRINGIFY(QXK_CURR) "]\n" /* QXK_attr_.curr := 0 */ - /* don't clear QXK_attr_.next, as it might be needed for AO activation */ + /* don NOT clear QXK_attr_.curr or QXK_attr_.next, + * as they might be needed for AO activation + */ #if (__ARM_ARCH == 6) /* if ARMv6-M... */ " MOV r0,sp \n" /* r0 := top of stack */ @@ -361,26 +356,25 @@ __asm volatile ( #endif /* ARMv7-M or higher */ " MOV r0,r12 \n" /* r0 := QXK_attr_.next */ - " MOVS r2,#" STRINGIFY(QACTIVE_PTHRE) "\n" /* r2 := offset of .pthre */ - " LDRB r0,[r0,r2] \n" /* r0 := QXK_attr_.next->pthre */ - " LDRB r2,[r3,#" STRINGIFY(QXK_ACT_THRE) "]\n" /* r2 := QXK_attr_.actThre */ + " MOVS r2,#" STRINGIFY(QACTIVE_PRIO) "\n" /* r2 := offset of .prio */ + " LDRB r0,[r0,r2] \n" /* r0 := QXK_attr_.next->prio */ + " LDRB r2,[r3,#" STRINGIFY(QXK_ACT_PRIO) "]\n" /* r2 := QXK_attr_.actPrio */ " CMP r2,r0 \n" - " BCC PendSV_activate \n" /* if (next->pthre > actThre) activate the next AO */ + " BCC PendSV_activate \n" /* if (next->prio > actPrio) activate the next AO */ /* otherwise no activation needed... */ " MOVS r0,#0 \n" - " STR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" /* QXK_attr_.next := 0 (clear the next) */ - " MOV r12,r0 \n" /* also clear r12==QXK_attr_.next */ + " STR r0,[r3,#" STRINGIFY(QXK_CURR) "]\n" /* QXK_attr_.curr := 0 */ + " STR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" /* QXK_attr_.next := 0 */ -#ifdef QXK_ON_CONTEXT_SW - " MOVS r0,r1 \n" /* r0 := QXK_attr_.curr / basic */ - " MOV r1,r12 \n" /* r1 := QXK_attr_.next / basic */ - " LDR r2,=QXK_onContextSw \n" - " PUSH {r1,lr} \n" /* save the aligner + exception lr */ - " BLX r2 \n" /* call QXK_onContextSw() */ - " POP {r1,r2} \n" /* restore the aligner + lr into r2 */ - " MOV lr,r2 \n" /* restore the exception lr */ -#endif /* QXK_ON_CONTEXT_SW */ +#if defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) + " MOVS r0,#0 \n" /* r0 := 0 (next is basic) */ + " PUSH {r3,lr} \n" /* save QXK_attr_ + exception lr */ + " LDR r3,=QXK_contextSw \n" + " BLX r3 \n" /* call QXK_contextSw() */ + " POP {r0,r1} \n" /* restore the aligner + lr into r1 */ + " MOV lr,r1 \n" /* restore the exception lr */ +#endif /* defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) */ /* re-enable interrupts and return from PendSV */ "PendSV_return: \n" @@ -395,7 +389,7 @@ __asm volatile ( " BX lr \n" /* return to the preempted AO-thread */ /*------------------------------------------------------------------------- - * Saving extended-thread before crossing to AO-thread + * Saving extended-thread * expected register contents: * r0 -> QXK_attr_.next / basic-thread * r1 -> QXK_attr_.curr / basic-thread @@ -437,7 +431,7 @@ __asm volatile ( /* otherwise continue to restoring next extended-thread... */ /*------------------------------------------------------------------------- - * Restoring extended-thread after crossing from AO-thread + * Restoring extended-thread * expected register contents: * r0 -> QXK_attr_.next / basic-thread * r1 -> QXK_attr_.curr / basic-thread @@ -446,20 +440,19 @@ __asm volatile ( * r12 -> QXK_attr_.next / basic-thread */ "PendSV_restore_ex: \n" -#ifdef QXK_ON_CONTEXT_SW - " MOVS r0,r1 \n" /* r0 := QXK_attr_.curr / basic */ - " MOV r1,r12 \n" /* r1 := QXK_attr_.next / basic */ - " LDR r2,=QXK_onContextSw \n" - " PUSH {r1,lr} \n" /* save the aligner + exception lr */ - " BLX r2 \n" /* call QXK_onContextSw() */ - " POP {r1,r2} \n" /* restore the aligner + lr into r2 */ - " MOV lr,r2 \n" /* restore the exception lr */ +#if defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) + " MOV r0,r12 \n" /* r0 := next */ + " PUSH {r3,lr} \n" /* save QXK_attr_ + exception lr */ + " LDR r3,=QXK_contextSw \n" + " BLX r3 \n" /* call QXK_contextSw() */ + " POP {r0,r1} \n" /* restore the aligner + lr into r1 */ + " MOV lr,r1 \n" /* restore the exception lr */ + " MOVS r3,r0 \n" /* restore the saved QXK_attr_ in r3 */ /* restore the AAPCS-clobbered registers after a functin call... */ - " LDR r3,=QXK_attr_ \n" " LDR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" /* r0 := QXK_attr_.next */ " LDR r2,[r0,#" STRINGIFY(QACTIVE_OSOBJ) "]\n" /* r2 := QXK_attr_.curr->osObject */ -#endif /* QXK_ON_CONTEXT_SW */ +#endif /* defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) */ " STR r0,[r3,#" STRINGIFY(QXK_CURR) "]\n" /* QXK_attr_.curr := r0 (QXK_attr_.next) */ " MOVS r0,#0 \n" diff --git a/ports/arm-cm/qxk/armclang/qxk_port.hpp b/ports/arm-cm/qxk/armclang/qxk_port.hpp index 9ae6ff12..c59385fc 100644 --- a/ports/arm-cm/qxk/armclang/qxk_port.hpp +++ b/ports/arm-cm/qxk/armclang/qxk_port.hpp @@ -21,8 +21,8 @@ // // //============================================================================ -//! @date Last updated on: 2022-09-04 -//! @version Last updated for: @ref qpcpp_7_1_1 +//! @date Last updated on: 2022-10-04 +//! @version Last updated for: @ref qpcpp_7_1_2 //! //! @file //! @brief QXK/C++ port to ARM Cortex-M, ARM-CLANG toolset @@ -49,7 +49,7 @@ static inline uint32_t QXK_get_IPSR(void) { #define QXK_ISR_EXIT() do { \ QF_INT_DISABLE(); \ - if (QXK_sched_(1U) != 0U) {\ + if (QXK_sched_() != 0U) { \ QXK_CONTEXT_SWITCH_(); \ } \ QF_INT_ENABLE(); \ diff --git a/ports/arm-cm/qxk/gnu/qxk_port.cpp b/ports/arm-cm/qxk/gnu/qxk_port.cpp index d1a3e09f..6d82ad14 100644 --- a/ports/arm-cm/qxk/gnu/qxk_port.cpp +++ b/ports/arm-cm/qxk/gnu/qxk_port.cpp @@ -23,8 +23,8 @@ * ============================================================================*/ /*! -* @date Last updated on: 2022-09-20 -* @version Last updated for: @ref qpcpp_7_1_1 +* @date Last updated on: 2022-10-04 +* @version Last updated for: @ref qpcpp_7_1_2 * * @file * @brief QXK/C++ port to ARM Cortex-M, GNU-ARM toolset @@ -165,21 +165,21 @@ void QXK_stackInit_(void *thr, QP::QXThreadHandler const handler, /* NOTE: keep in synch with struct QXK_Attr in "qxk.hpp" !!! */ #define QXK_CURR 0 #define QXK_NEXT 4 -#define QXK_ACT_THRE 9 +#define QXK_ACT_PRIO 12 /* make sure that the offsets match the QXK declaration in "qxk.hpp" */ //Q_ASSERT_STATIC(QXK_CURR == offsetof(QXK_Attr, curr)); //Q_ASSERT_STATIC(QXK_NEXT == offsetof(QXK_Attr, next)); -//Q_ASSERT_STATIC(QXK_ACT_THRE == offsetof(QXK_Attr, actThre)); +//Q_ASSERT_STATIC(QXK_ACT_PRIO == offsetof(QXK_Attr, actPrio)); + /* offsets within struct QActive; NOTE: keep in synch with "qf.hpp" !!! */ #define QACTIVE_OSOBJ 28 #define QACTIVE_PRIO 36 -#define QACTIVE_PTHRE 37 /* make sure that the offsets match the QXK declaration in "qf.hpp" */ //Q_ASSERT_STATIC(QACTIVE_OSOBJ == offsetof(QP::QActive, m_osObject)); -//Q_ASSERT_STATIC(QACTIVE_PTHRE == offsetof(QP::QActive, m_pthre)); +//Q_ASSERT_STATIC(QACTIVE_PRIO == offsetof(QP::QActive, m_prio)); /* helper macros to "stringify" values */ #define VAL(x) #x @@ -278,11 +278,6 @@ __asm volatile ( " ADD r0,sp,#(5*4) \n" /* r0 := 5 registers below the top of stack */ " STM r0!,{r1-r3} \n" /* save xpsr,pc,lr */ -#ifdef Q_SPY - " MOV r0,#1 \n" /* set the parameter 'asynch` */ - " STR r0,[sp] \n" /* for call QK_activate_(asynch == 1) */ -#endif /* Q_SPY */ - " MOV r0,#6 \n" " MVN r0,r0 \n" /* r0 := ~6 == 0xFFFFFFF9 */ #if (__ARM_ARCH != 6) /* ARMv7-M or higher */ @@ -333,9 +328,9 @@ __asm volatile ( * r12 -> QXK_attr_.next / basic-thread */ "PendSV_restore_ao: \n" - " MOV r0,#0 \n" - " STR r0,[r3,#" STRINGIFY(QXK_CURR) "]\n" /* QXK_attr_.curr := 0 */ - /* don't clear QXK_attr_.next, as it might be needed for AO activation */ + /* don NOT clear QXK_attr_.curr or QXK_attr_.next, + * as they might be needed for AO activation + */ #if (__ARM_ARCH == 6) /* if ARMv6-M... */ " MOV r0,sp \n" /* r0 := top of stack */ @@ -366,26 +361,25 @@ __asm volatile ( #endif /* ARMv7-M or higher */ " MOV r0,r12 \n" /* r0 := QXK_attr_.next */ - " MOV r2,#" STRINGIFY(QACTIVE_PTHRE) "\n" /* r2 := offset of .pthre */ - " LDRB r0,[r0,r2] \n" /* r0 := QXK_attr_.next->pthre */ - " LDRB r2,[r3,#" STRINGIFY(QXK_ACT_THRE) "]\n" /* r2 := QXK_attr_.actThre */ + " MOV r2,#" STRINGIFY(QACTIVE_PRIO) "\n" /* r2 := offset of .prio */ + " LDRB r0,[r0,r2] \n" /* r0 := QXK_attr_.next->prio */ + " LDRB r2,[r3,#" STRINGIFY(QXK_ACT_PRIO) "]\n" /* r2 := QXK_attr_.actPrio */ " CMP r2,r0 \n" - " BCC PendSV_activate \n" /* if (next->pthre > actThre) activate the next AO */ + " BCC PendSV_activate \n" /* if (next->prio > actPrio) activate the next AO */ /* otherwise no activation needed... */ " MOV r0,#0 \n" - " STR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" /* QXK_attr_.next := 0 (clear the next) */ - " MOV r12,r0 \n" /* also clear r12==QXK_attr_.next */ + " STR r0,[r3,#" STRINGIFY(QXK_CURR) "]\n" /* QXK_attr_.curr := 0 */ + " STR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" /* QXK_attr_.next := 0 */ -#ifdef QXK_ON_CONTEXT_SW - " MOV r0,r1 \n" /* r0 := QXK_attr_.curr / basic */ - " MOV r1,r12 \n" /* r1 := QXK_attr_.next / basic */ - " LDR r2,=QXK_onContextSw \n" - " PUSH {r1,lr} \n" /* save the aligner + exception lr */ - " BLX r2 \n" /* call QXK_onContextSw() */ - " POP {r1,r2} \n" /* restore the aligner + lr into r2 */ - " MOV lr,r2 \n" /* restore the exception lr */ -#endif /* QXK_ON_CONTEXT_SW */ +#if defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) + " MOV r0,#0 \n" /* r0 := 0 (next is basic) */ + " PUSH {r3,lr} \n" /* save QXK_attr_ + exception lr */ + " LDR r3,=QXK_contextSw \n" + " BLX r3 \n" /* call QXK_contextSw() */ + " POP {r0,r1} \n" /* restore the aligner + lr into r1 */ + " MOV lr,r1 \n" /* restore the exception lr */ +#endif /* defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) */ /* re-enable interrupts and return from PendSV */ "PendSV_return: \n" @@ -400,7 +394,7 @@ __asm volatile ( " BX lr \n" /* return to the preempted AO-thread */ /*------------------------------------------------------------------------- - * Saving extended-thread before crossing to AO-thread + * Saving extended-thread * expected register contents: * r0 -> QXK_attr_.next / basic-thread * r1 -> QXK_attr_.curr / basic-thread @@ -442,7 +436,7 @@ __asm volatile ( /* otherwise continue to restoring next extended-thread... */ /*------------------------------------------------------------------------- - * Restoring extended-thread after crossing from AO-thread + * Restoring extended-thread * expected register contents: * r0 -> QXK_attr_.next / basic-thread * r1 -> QXK_attr_.curr / basic-thread @@ -451,20 +445,19 @@ __asm volatile ( * r12 -> QXK_attr_.next / basic-thread */ "PendSV_restore_ex: \n" -#ifdef QXK_ON_CONTEXT_SW - " MOV r0,r1 \n" /* r0 := QXK_attr_.curr / basic */ - " MOV r1,r12 \n" /* r1 := QXK_attr_.next / basic */ - " LDR r2,=QXK_onContextSw \n" - " PUSH {r1,lr} \n" /* save the aligner + exception lr */ - " BLX r2 \n" /* call QXK_onContextSw() */ - " POP {r1,r2} \n" /* restore the aligner + lr into r2 */ - " MOV lr,r2 \n" /* restore the exception lr */ +#if defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) + " MOV r0,r12 \n" /* r0 := next */ + " PUSH {r3,lr} \n" /* save QXK_attr_ + exception lr */ + " LDR r3,=QXK_contextSw \n" + " BLX r3 \n" /* call QXK_contextSw() */ + " POP {r0,r1} \n" /* restore the aligner + lr into r1 */ + " MOV lr,r1 \n" /* restore the exception lr */ + " MOV r3,r0 \n" /* restore the saved QXK_attr_ in r3 */ /* restore the AAPCS-clobbered registers after a functin call... */ - " LDR r3,=QXK_attr_ \n" " LDR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" /* r0 := QXK_attr_.next */ " LDR r2,[r0,#" STRINGIFY(QACTIVE_OSOBJ) "]\n" /* r2 := QXK_attr_.curr->osObject */ -#endif /* QXK_ON_CONTEXT_SW */ +#endif /* defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) */ " STR r0,[r3,#" STRINGIFY(QXK_CURR) "]\n" /* QXK_attr_.curr := r0 (QXK_attr_.next) */ " MOV r0,#0 \n" @@ -539,7 +532,7 @@ __asm volatile ( " ISB \n" /* ISB after MSR CONTROL (ARM AN321,Sect.4.16) */ #endif /*--------- VFP available */ -#ifndef QXK_USE_IRQ_NUM /*--------- IRQ NOT defined, used NMI by default */ +#ifndef QXK_USE_IRQ_NUM /*--------- IRQ NOT defined, use NMI by default */ " LDR r0,=" STRINGIFY(NVIC_ICSR) "\n" /* Interrupt Control and State */ " MOV r1,#1 \n" " LSL r1,r1,#31 \n" /* r1 := (1 << 31) (NMI bit) */ diff --git a/ports/arm-cm/qxk/gnu/qxk_port.hpp b/ports/arm-cm/qxk/gnu/qxk_port.hpp index 74ddd034..2e236df1 100644 --- a/ports/arm-cm/qxk/gnu/qxk_port.hpp +++ b/ports/arm-cm/qxk/gnu/qxk_port.hpp @@ -21,8 +21,8 @@ // // //============================================================================ -//! @date Last updated on: 2022-09-04 -//! @version Last updated for: @ref qpcpp_7_1_1 +//! @date Last updated on: 2022-10-04 +//! @version Last updated for: @ref qpcpp_7_1_2 //! //! @file //! @brief QXK/C++ port to ARM Cortex-M, GNU-ARM toolset @@ -49,7 +49,7 @@ static inline uint32_t QXK_get_IPSR(void) { #define QXK_ISR_EXIT() do { \ QF_INT_DISABLE(); \ - if (QXK_sched_(1U) != 0U) {\ + if (QXK_sched_() != 0U) { \ QXK_CONTEXT_SWITCH_(); \ } \ QF_INT_ENABLE(); \ diff --git a/ports/arm-cm/qxk/iar/qxk_port.cpp b/ports/arm-cm/qxk/iar/qxk_port.cpp index e03b7f18..c24731a1 100644 --- a/ports/arm-cm/qxk/iar/qxk_port.cpp +++ b/ports/arm-cm/qxk/iar/qxk_port.cpp @@ -23,8 +23,8 @@ * ============================================================================*/ /*! -* @date Last updated on: 2022-09-20 -* @version Last updated for: @ref qpcpp_7_1_1 +* @date Last updated on: 2022-10-04 +* @version Last updated for: @ref qpcpp_7_1_2 * * @file * @brief QXK/C++ port to ARM Cortex-M, IAR-ARM toolset @@ -165,21 +165,21 @@ void QXK_stackInit_(void *thr, QP::QXThreadHandler const handler, /* NOTE: keep in synch with struct QXK_Attr in "qxk.hpp" !!! */ #define QXK_CURR 0 #define QXK_NEXT 4 -#define QXK_ACT_THRE 9 +#define QXK_ACT_PRIO 12 /* make sure that the offsets match the QXK declaration in "qxk.hpp" */ Q_ASSERT_STATIC(QXK_CURR == offsetof(QXK_Attr, curr)); Q_ASSERT_STATIC(QXK_NEXT == offsetof(QXK_Attr, next)); -Q_ASSERT_STATIC(QXK_ACT_THRE == offsetof(QXK_Attr, actThre)); +Q_ASSERT_STATIC(QXK_ACT_PRIO == offsetof(QXK_Attr, actPrio)); + /* offsets within struct QActive; NOTE: keep in synch with "qf.hpp" !!! */ #define QACTIVE_OSOBJ 28 #define QACTIVE_PRIO 36 -#define QACTIVE_PTHRE 37 /* make sure that the offsets match the QXK declaration in "qf.hpp" */ Q_ASSERT_STATIC(QACTIVE_OSOBJ == offsetof(QP::QActive, m_osObject)); -Q_ASSERT_STATIC(QACTIVE_PTHRE == offsetof(QP::QActive, m_pthre)); +Q_ASSERT_STATIC(QACTIVE_PRIO == offsetof(QP::QActive, m_prio)); /* helper macros to "stringify" values */ #define VAL(x) #x @@ -273,11 +273,6 @@ __asm volatile ( " ADD r0,sp,#(5*4) \n" /* r0 := 5 registers below the top of stack */ " STM r0!,{r1-r3} \n" /* save xpsr,pc,lr */ -#ifdef Q_SPY - " MOVS r0,#1 \n" /* set the parameter 'asynch` */ - " STR r0,[sp] \n" /* for call QK_activate_(asynch == 1) */ -#endif /* Q_SPY */ - " MOVS r0,#6 \n" " MVNS r0,r0 \n" /* r0 := ~6 == 0xFFFFFFF9 */ #if (__ARM_ARCH != 6) /* ARMv7-M or higher */ @@ -328,9 +323,9 @@ __asm volatile ( * r12 -> QXK_attr_.next / basic-thread */ "PendSV_restore_ao: \n" - " MOVS r0,#0 \n" - " STR r0,[r3,#" STRINGIFY(QXK_CURR) "]\n" /* QXK_attr_.curr := 0 */ - /* don't clear QXK_attr_.next, as it might be needed for AO activation */ + /* don NOT clear QXK_attr_.curr or QXK_attr_.next, + * as they might be needed for AO activation + */ #if (__ARM_ARCH == 6) /* if ARMv6-M... */ " MOV r0,sp \n" /* r0 := top of stack */ @@ -361,26 +356,25 @@ __asm volatile ( #endif /* ARMv7-M or higher */ " MOV r0,r12 \n" /* r0 := QXK_attr_.next */ - " MOVS r2,#" STRINGIFY(QACTIVE_PTHRE) "\n" /* r2 := offset of .pthre */ - " LDRB r0,[r0,r2] \n" /* r0 := QXK_attr_.next->pthre */ - " LDRB r2,[r3,#" STRINGIFY(QXK_ACT_THRE) "]\n" /* r2 := QXK_attr_.actThre */ + " MOVS r2,#" STRINGIFY(QACTIVE_PRIO) "\n" /* r2 := offset of .prio */ + " LDRB r0,[r0,r2] \n" /* r0 := QXK_attr_.next->prio */ + " LDRB r2,[r3,#" STRINGIFY(QXK_ACT_PRIO) "]\n" /* r2 := QXK_attr_.actPrio */ " CMP r2,r0 \n" - " BCC PendSV_activate \n" /* if (next->pthre > actThre) activate the next AO */ + " BCC PendSV_activate \n" /* if (next->prio > actPrio) activate the next AO */ /* otherwise no activation needed... */ " MOVS r0,#0 \n" - " STR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" /* QXK_attr_.next := 0 (clear the next) */ - " MOV r12,r0 \n" /* also clear r12==QXK_attr_.next */ + " STR r0,[r3,#" STRINGIFY(QXK_CURR) "]\n" /* QXK_attr_.curr := 0 */ + " STR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" /* QXK_attr_.next := 0 */ -#ifdef QXK_ON_CONTEXT_SW - " MOVS r0,r1 \n" /* r0 := QXK_attr_.curr / basic */ - " MOV r1,r12 \n" /* r1 := QXK_attr_.next / basic */ - " LDR r2,=QXK_onContextSw \n" - " PUSH {r1,lr} \n" /* save the aligner + exception lr */ - " BLX r2 \n" /* call QXK_onContextSw() */ - " POP {r1,r2} \n" /* restore the aligner + lr into r2 */ - " MOV lr,r2 \n" /* restore the exception lr */ -#endif /* QXK_ON_CONTEXT_SW */ +#if defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) + " MOVS r0,#0 \n" /* r0 := 0 (next is basic) */ + " PUSH {r3,lr} \n" /* save QXK_attr_ + exception lr */ + " LDR r3,=QXK_contextSw \n" + " BLX r3 \n" /* call QXK_contextSw() */ + " POP {r0,r1} \n" /* restore the aligner + lr into r1 */ + " MOV lr,r1 \n" /* restore the exception lr */ +#endif /* defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) */ /* re-enable interrupts and return from PendSV */ "PendSV_return: \n" @@ -395,7 +389,7 @@ __asm volatile ( " BX lr \n" /* return to the preempted AO-thread */ /*------------------------------------------------------------------------- - * Saving extended-thread before crossing to AO-thread + * Saving extended-thread * expected register contents: * r0 -> QXK_attr_.next / basic-thread * r1 -> QXK_attr_.curr / basic-thread @@ -437,7 +431,7 @@ __asm volatile ( /* otherwise continue to restoring next extended-thread... */ /*------------------------------------------------------------------------- - * Restoring extended-thread after crossing from AO-thread + * Restoring extended-thread * expected register contents: * r0 -> QXK_attr_.next / basic-thread * r1 -> QXK_attr_.curr / basic-thread @@ -446,20 +440,19 @@ __asm volatile ( * r12 -> QXK_attr_.next / basic-thread */ "PendSV_restore_ex: \n" -#ifdef QXK_ON_CONTEXT_SW - " MOVS r0,r1 \n" /* r0 := QXK_attr_.curr / basic */ - " MOV r1,r12 \n" /* r1 := QXK_attr_.next / basic */ - " LDR r2,=QXK_onContextSw \n" - " PUSH {r1,lr} \n" /* save the aligner + exception lr */ - " BLX r2 \n" /* call QXK_onContextSw() */ - " POP {r1,r2} \n" /* restore the aligner + lr into r2 */ - " MOV lr,r2 \n" /* restore the exception lr */ +#if defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) + " MOV r0,r12 \n" /* r0 := next */ + " PUSH {r3,lr} \n" /* save QXK_attr_ + exception lr */ + " LDR r3,=QXK_contextSw \n" + " BLX r3 \n" /* call QXK_contextSw() */ + " POP {r0,r1} \n" /* restore the aligner + lr into r1 */ + " MOV lr,r1 \n" /* restore the exception lr */ + " MOVS r3,r0 \n" /* restore the saved QXK_attr_ in r3 */ /* restore the AAPCS-clobbered registers after a functin call... */ - " LDR r3,=QXK_attr_ \n" " LDR r0,[r3,#" STRINGIFY(QXK_NEXT) "]\n" /* r0 := QXK_attr_.next */ " LDR r2,[r0,#" STRINGIFY(QACTIVE_OSOBJ) "]\n" /* r2 := QXK_attr_.curr->osObject */ -#endif /* QXK_ON_CONTEXT_SW */ +#endif /* defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) */ " STR r0,[r3,#" STRINGIFY(QXK_CURR) "]\n" /* QXK_attr_.curr := r0 (QXK_attr_.next) */ " MOVS r0,#0 \n" diff --git a/ports/arm-cm/qxk/iar/qxk_port.hpp b/ports/arm-cm/qxk/iar/qxk_port.hpp index 723ffc0f..833c538e 100644 --- a/ports/arm-cm/qxk/iar/qxk_port.hpp +++ b/ports/arm-cm/qxk/iar/qxk_port.hpp @@ -21,8 +21,8 @@ // // //============================================================================ -//! @date Last updated on: 2022-09-04 -//! @version Last updated for: @ref qpcpp_7_1_1 +//! @date Last updated on: 2022-10-04 +//! @version Last updated for: @ref qpcpp_7_1_2 //! //! @file //! @brief QXK/C++ port to ARM Cortex-M, QXK kernel, IAR-ARM toolset @@ -42,7 +42,7 @@ #define QXK_ISR_EXIT() do { \ QF_INT_DISABLE(); \ - if (QXK_sched_(1U) != 0U) {\ + if (QXK_sched_() != 0U) { \ QXK_CONTEXT_SWITCH_(); \ } \ QF_INT_ENABLE(); \ diff --git a/ports/arm-cr/qk/gnu/qk_port.hpp b/ports/arm-cr/qk/gnu/qk_port.hpp index 2657f261..27d8eeda 100644 --- a/ports/arm-cr/qk/gnu/qk_port.hpp +++ b/ports/arm-cr/qk/gnu/qk_port.hpp @@ -22,8 +22,8 @@ // // //============================================================================ -//! @date Last updated on: 2022-09-04 -//! @version Last updated for: @ref qpcpp_7_1_1 +//! @date Last updated on: 2022-10-04 +//! @version Last updated for: @ref qpcpp_7_1_2 //! //! @file //! @brief QK/C++ port to ARM Cortex-R, preemptive QK kernel, GNU-ARM toolset @@ -71,7 +71,7 @@ } --QP::QF::intNest_; \ if (QP::QF::intNest_ == 0U) { \ if (QK_sched_() != 0U) { \ - QK_activate_(1U); \ + QK_activate_(); \ } \ } \ __asm volatile (" POP {R3, LR}\n" \ @@ -89,7 +89,7 @@ } --QP::QF::intNest_; \ if (QP::QF::intNest_ == 0U) { \ if (QK_sched_() != 0U) { \ - QK_activate_(1U); \ + QK_activate_(); \ } \ } \ __asm volatile (" POP {R3, LR}\n" \ diff --git a/ports/arm-cr/qk/iar/qk_port.hpp b/ports/arm-cr/qk/iar/qk_port.hpp index 28470f92..6769b78e 100644 --- a/ports/arm-cr/qk/iar/qk_port.hpp +++ b/ports/arm-cr/qk/iar/qk_port.hpp @@ -22,8 +22,8 @@ // // //============================================================================ -//! @date Last updated on: 2022-09-04 -//! @version Last updated for: @ref qpcpp_7_1_1 +//! @date Last updated on: 2022-10-04 +//! @version Last updated for: @ref qpcpp_7_1_2 //! //! @file //! @brief QK/C++ port to ARM Cortex-R, preemptive QK kernel, IAR-ARM toolset @@ -67,7 +67,7 @@ } --QP::QF::intNest_; \ if (QP::QF::intNest_ == 0U) { \ if (QK_sched_() != 0U) { \ - QK_activate_(1U); \ + QK_activate_(); \ } \ } \ __asm(" POP {R3, LR}\n" \ @@ -85,7 +85,7 @@ } --QP::QF::intNest_; \ if (QP::QF::intNest_ == 0U) { \ if (QK_sched_() != 0U) { \ - QK_activate_(1U); \ + QK_activate_(); \ } \ } \ __asm(" POP {R3, LR}\n" \ diff --git a/ports/arm-cr/qk/ti/qk_port.hpp b/ports/arm-cr/qk/ti/qk_port.hpp index f3aff513..639d724a 100644 --- a/ports/arm-cr/qk/ti/qk_port.hpp +++ b/ports/arm-cr/qk/ti/qk_port.hpp @@ -22,8 +22,8 @@ // // //============================================================================ -//! @date Last updated on: 2022-09-04 -//! @version Last updated for: @ref qpcpp_7_1_1 +//! @date Last updated on: 2022-10-04 +//! @version Last updated for: @ref qpcpp_7_1_2 //! //! @file //! @brief QK/C++ port to ARM Cortex-R, preemptive QK kernel, TI-ARM toolset @@ -73,7 +73,7 @@ } --QP::QF::intNest_; \ if (QP::QF::intNest_ == 0U) { \ if (QK_sched_() != 0U) { \ - QK_activate_(1U); \ + QK_activate_(); \ } \ } \ } diff --git a/ports/lint-plus/qk/qk_port.hpp b/ports/lint-plus/qk/qk_port.hpp index ac974419..42a0d2ad 100644 --- a/ports/lint-plus/qk/qk_port.hpp +++ b/ports/lint-plus/qk/qk_port.hpp @@ -22,8 +22,8 @@ // // //============================================================================ -//! @date Last updated on: 2022-09-04 -//! @version Last updated for: @ref qpcpp_7_1_1 +//! @date Last updated on: 2022-10-04 +//! @version Last updated for: @ref qpcpp_7_1_2 //! //! @file //! @brief QK/C++ port to Lint, Generic C++ compiler @@ -60,7 +60,7 @@ --QP::QF::intNest_; \ if (QP::QF::intNest_ == 0U) {\ if (QK_sched_() != 0U) { \ - QK_activate_(1U); \ + QK_activate_(); \ } \ } \ else { \ diff --git a/ports/lint-plus/qxk/qxk_port.hpp b/ports/lint-plus/qxk/qxk_port.hpp index e0de1f9c..de3d515c 100644 --- a/ports/lint-plus/qxk/qxk_port.hpp +++ b/ports/lint-plus/qxk/qxk_port.hpp @@ -22,8 +22,8 @@ // // //============================================================================ -//! @date Last updated on: 2022-09-04 -//! @version Last updated for: @ref qpcpp_7_1_1 +//! @date Last updated on: 2022-10-04 +//! @version Last updated for: @ref qpcpp_7_1_2 //! //! @file //! @brief QXK/C++ port example, Generic C++ compiler @@ -70,8 +70,8 @@ #define QXK_ISR_EXIT() do { \ --QP::QF::intNest_; \ if (QP::QF::intNest_ == 0U) { \ - if (QXK_sched_(1U) != 0U) {\ - QXK_activate_(1U); \ + if (QXK_sched_() != 0U) { \ + QXK_activate_(); \ } \ } \ else { \ diff --git a/ports/msp430/qk/qk_port.hpp b/ports/msp430/qk/qk_port.hpp index 70e01c24..ed42c4f5 100644 --- a/ports/msp430/qk/qk_port.hpp +++ b/ports/msp430/qk/qk_port.hpp @@ -22,8 +22,8 @@ // // //============================================================================ -//! @date Last updated on: 2022-09-04 -//! @version Last updated for: @ref qpcpp_7_1_1 +//! @date Last updated on: 2022-10-04 +//! @version Last updated for: @ref qpcpp_7_1_2 //! //! @file //! @brief QK/C++ port to MSP430 @@ -38,7 +38,7 @@ --QP::QF::intNest_; \ if (QP::QF::intNest_ == 0U) {\ if (QK_sched_() != 0U) { \ - QK_activate_(1U); \ + QK_activate_(); \ } \ } \ else { \ diff --git a/ports/pic32/qk/xc32/qk_port.cpp b/ports/pic32/qk/xc32/qk_port.cpp index 1d9d44ec..70768e3f 100644 --- a/ports/pic32/qk/xc32/qk_port.cpp +++ b/ports/pic32/qk/xc32/qk_port.cpp @@ -22,8 +22,8 @@ // // //============================================================================ -//! @date Last updated on: 2022-09-04 -//! @version Last updated for: @ref qpcpp_7_1_1 +//! @date Last updated on: 2022-10-04 +//! @version Last updated for: @ref qpcpp_7_1_2 //! //! @file //! @brief QK/C++ port to PIC32, preemptive QK kernel, XC32 toolchain @@ -49,7 +49,7 @@ void QK_isr_(void) { // see NOTE2 QF_INT_DISABLE(); _mtc0(_CP0_STATUS, _CP0_STATUS_SELECT, 0U); // drop IPL to 0 - (void)QK_activate_(1U); // asynchronously activate higher priority AO + (void)QK_activate_(); // asynchronously activate higher priority AO _mtc0(_CP0_STATUS, _CP0_STATUS_SELECT, 1U << 10); //restore IPL to 1 QF_INT_ENABLE(); } diff --git a/qpcpp.qm b/qpcpp.qm index fc67e1c2..15182ba0 100644 --- a/qpcpp.qm +++ b/qpcpp.qm @@ -2323,7 +2323,7 @@ return r; //! When QP runs on top of 3rd-party kernels/RTOSes or general-purpose //! operating systems, sthe second priority can have different meaning, //! depending on the specific RTOS/GPOS used. - = std::uint_fast16_t; + = std::uint16_t; @@ -3759,7 +3759,7 @@ QF_QMACTIVE_TO_QMSM_CAST_(this)->QMsm::init(qs_id); m_interval(0U) //! @pre The signal must be valid and the tick rate in range -Q_REQUIRE_ID(300, (sgnl >= Q_USER_SIG) +Q_REQUIRE_ID(300, (sgnl != 0) && (tickRate < QF_MAX_TICK_RATE)); #ifndef Q_EVT_CTOR @@ -6560,7 +6560,7 @@ if (QS_GLB_CHECK_(rec_) && QS_LOC_CHECK_(qs_id_)) { \ QS_SCHED_UNLOCK, //!< scheduler was unlocked QS_SCHED_NEXT, //!< scheduler found next task to execute QS_SCHED_IDLE, //!< scheduler became idle - QS_SCHED_RESUME, //!< scheduler resumed previous task (not idle) + QS_SCHED_RESUME, //!< scheduler resumed a (blocked) task // [55] Additional QEP records QS_QEP_TRAN_HIST, //!< a tran to history was taken @@ -9637,8 +9637,8 @@ if (stat != 0xFFU) { QS_BEGIN_NOCRIT_PRE_(QS_SCHED_UNLOCK, 0U) QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(lockCeil, // current lock ceiling (old) - prevCeil); // previous lock ceiling (new) + // current lock ceiling (old), previous lock ceiling (new) + QS_2U8_PRE_(lockCeil, prevCeil); QS_END_NOCRIT_PRE_() // restore the previous lock ceiling and lock holder @@ -9647,7 +9647,7 @@ if (stat != 0xFFU) { // find if any AOs should be run after unlocking the scheduler if (QK_sched_() != 0U) { // synchronous preemption needed? - QK_activate_(0U); // synchronously activate any unlocked AOs + QK_activate_(); // synchronously activate any unlocked AOs } QF_CRIT_X_(); @@ -9691,7 +9691,7 @@ QK_attr_.lockCeil = 0U; // scheduler unlocked // any active objects need to be scheduled before starting event loop? if (QK_sched_() != 0U) { // synchronous preemption needed? - QK_activate_(0U); // synchronously activate AOs to process events + QK_activate_(); // synchronously activate AOs to process events } onStartup(); // application-specific startup callback @@ -9752,7 +9752,7 @@ QS_FLUSH(); // flush the trace buffer to the host QF_CRIT_STAT_ QF_CRIT_E_(); if (QK_sched_() != 0U) { // synchronous preemption needed? - QK_activate_(0U); // synchronously activate AOs + QK_activate_(); // synchronously activate AOs } QF_CRIT_X_(); @@ -9785,26 +9785,33 @@ QF_CRIT_X_(); //! that (1) has events to process and (2) has priority that is above the //! current priority. //! -//! @returns the 1-based priority of the the active object, or zero if -//! no eligible active object is ready to run. +//! @returns +//! The QF-priority of the next active object to activate, or zero +//! if no activation of AO is needed. //! //! @attention //! QK_sched_() must be always called with interrupts **disabled** and //! returns with interrupts **disabled**. - // find the highest-prio AO with non-empty event queue -std::uint_fast8_t p = QP::QF::readySet_.findMax(); + std::uint_fast8_t p; -// is the AO's priority below the active preemption-threshold? -if (p <= QK_attr_.actThre) { - p = 0U; // no preemption needed -} -// is the AO's priority below the lock preemption-ceiling? -else if (p <= QK_attr_.lockCeil) { - p = 0U; // no preemption needed +if (QP::QF::readySet_.isEmpty()) { + p = 0U; // no activation needed } else { - Q_ASSERT_ID(410, p <= QF_MAX_ACTIVE); - QK_attr_.nextPrio = static_cast<std::uint8_t>(p); // next AO to run + // find the highest-prio AO with non-empty event queue + p = QP::QF::readySet_.findMax(); + + // is the AO's priority below the active preemption-threshold? + if (p <= QK_attr_.actThre) { + p = 0U; // no activation needed + } + // is the AO's priority below the lock preemption-ceiling? + else if (p <= QK_attr_.lockCeil) { + p = 0U; // no activation needed + } + else { + QK_attr_.nextPrio = static_cast<std::uint8_t>(p); + } } return p; @@ -9814,21 +9821,14 @@ return p; //! QK activator activates the next active object. The activated AO preempts //! the currently executing AOs //! -//! @param[in] asynch flag conveying the type of activation: -//! != 0 for asynchronous activation and -//! == 0 for synchronous activation //! @details //! QK_activate_() activates ready-to run AOs that are above the initial -//! active priority (QK_attr_.actPrio). +//! preemption-threshold. //! //! @note //! The activator might enable interrupts internally, but always returns with //! interrupts **disabled**. - - - Q_UNUSED_PAR(asynch); // unused when Q_SPY not defined - -std::uint8_t const prio_in = QK_attr_.actPrio; // saved initial priority + std::uint8_t const prio_in = QK_attr_.actPrio; // saved initial priority std::uint_fast8_t p = QK_attr_.nextPrio; // next prio to run QK_attr_.nextPrio = 0U; // clear for the next time @@ -9849,25 +9849,14 @@ do { QK_attr_.actPrio = static_cast<std::uint8_t>(p); QK_attr_.actThre = QP::QActive::registry_[p]->m_pthre; -#ifdef Q_SPY - if ((asynch != 0U) && (pprev == prio_in)) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_PREEMPT, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(p, // priority of the scheduled AO - pprev); // previous priority - QS_END_NOCRIT_PRE_() - } - else { +#if (defined QK_ON_CONTEXT_SW) || (defined Q_SPY) + if (p != pprev) { // changing threads? + QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, a->m_prio) QS_TIME_PRE_(); // timestamp QS_2U8_PRE_(p, // priority of the scheduled AO pprev); // previous priority QS_END_NOCRIT_PRE_() - } -#endif // Q_SPY - -#if (defined QK_ON_CONTEXT_SW) || (defined Q_SPY) - if (p != pprev) { // changing threads? #ifdef QK_ON_CONTEXT_SW // context-switch callback @@ -9892,6 +9881,7 @@ do { #if (QF_MAX_EPOOL > 0U) QP::QF::gc(e); #endif + // determine the next highest-priority AO ready to run... QF_INT_DISABLE(); // unconditionally disable interrupts @@ -9899,19 +9889,24 @@ do { QP::QF::readySet_.remove(p); } - // find new highest-prio AO ready to run... - p = QP::QF::readySet_.findMax(); - - // is the new priority below the initial preemption-threshold? - if (p <= QP::QActive::registry_[prio_in]->m_pthre) { - p = 0U; // no preemption needed - } - // is the AO's priority below the lock preemption-ceiling? - else if (p <= QK_attr_.lockCeil) { - p = 0U; // no preemption needed + if (QP::QF::readySet_.isEmpty()) { + p = 0U; // no activation needed } else { - Q_ASSERT_ID(510, p <= QF_MAX_ACTIVE); + // find new highest-prio AO ready to run... + p = QP::QF::readySet_.findMax(); + + // is the new priority below the initial preemption-threshold? + if (p <= QP::QActive::registry_[prio_in]->m_pthre) { + p = 0U; // no activation needed + } + // is the AO's priority below the lock preemption-ceiling? + else if (p <= QK_attr_.lockCeil) { + p = 0U; // no activation needed + } + else { + Q_ASSERT_ID(510, p <= QF_MAX_ACTIVE); + } } } while (p != 0U); @@ -9923,22 +9918,11 @@ QK_attr_.actThre = QP::QActive::registry_[prio_in]->m_pthre; if (prio_in != 0U) { // resuming an active object? a = QP::QActive::registry_[prio_in]; // pointer to preempted AO -#ifdef Q_SPY - if (asynch != 0U) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_RESTORE, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(prio_in, // priority of the resumed AO - pprev); // previous priority - QS_END_NOCRIT_PRE_() - } - else { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_RESUME, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(prio_in, // priority of the resumed AO - pprev); // previous priority - QS_END_NOCRIT_PRE_() - } -#endif // Q_SPY + QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, a->m_prio) + QS_TIME_PRE_(); // timestamp + // priority of the resumed AO, previous priority + QS_2U8_PRE_(prio_in, pprev); + QS_END_NOCRIT_PRE_() } else { // resuming priority==0 --> idle a = nullptr; // QK idle loop @@ -10038,7 +10022,7 @@ QK_onContextSw(QP::QActive::registry_[pprev], a); static_cast<std::uint_fast8_t>((me_)->m_prio)); \ if (!QK_ISR_CONTEXT_()) { \ if (QK_sched_() != 0U) { \ - QK_activate_(0U); \ + QK_activate_(); \ } \ } \ } while (false) @@ -10174,8 +10158,8 @@ if (stat != 0xFFU) { QXK_attr_.lockHolder = static_cast<std::uint8_t>(stat & 0xFFU); // find the highest-prio thread ready to run - if (QXK_sched_(0U) != 0U) { // synchronous preemption needed? - QXK_activate_(0U); // synchronously activate unlocked AOs + if (QXK_sched_() != 0U) { // synchronous preemption needed? + QXK_activate_(); // synchronously activate unlocked AOs } QF_CRIT_X_(); @@ -10185,10 +10169,8 @@ if (stat != 0xFFU) { //! timeout signals for extended threads : enum_t { - DELAY_SIG = Q_USER_SIG, - QUEUE_SIG, - SEMA_SIG, - MUTEX_SIG + DELAY_SIG = 1, + TIMEOUT_SIG }; @@ -10386,10 +10368,10 @@ if (thr->m_eQueue.m_frontEvt == nullptr) { // remember the blocking object (the thread's queue) thr->m_temp.obj = QXK_PTR_CAST_(QMState*, &thr->m_eQueue); - thr->teArm_(static_cast<enum_t>(QXK::QUEUE_SIG), nTicks); + thr->teArm_(static_cast<enum_t>(QXK::TIMEOUT_SIG), nTicks); QF::readySet_.remove( static_cast<std::uint_fast8_t>(thr->m_prio)); - static_cast<void>(QXK_sched_(0U)); // synchronous scheduling + static_cast<void>(QXK_sched_()); // synchronous scheduling QF_CRIT_X_(); QF_CRIT_EXIT_NOP(); // BLOCK here @@ -10527,10 +10509,13 @@ Q_ERROR_ID(120); //! - NOT be called from an ISR; //! - the stack storage must be provided; //! - the thread must be instantiated (see #QXThread). +//! - preemption-threshold is NOT provided (because QXK kernel +//! does not support preemption-threshold scheduling) Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) && (stkSto != nullptr) && (stkSize != 0U) - && (m_state.act == nullptr)); + && (m_state.act == nullptr) + && ((prioSpec & 0xFF00U) == 0U)); // is storage for the queue buffer provided? if (qSto != nullptr) { @@ -10542,7 +10527,7 @@ if (qSto != nullptr) { QXK_stackInit_(this, m_temp.thr, stkSto, stkSize); m_prio = static_cast<std::uint8_t>(prioSpec & 0xFFU); // QF-prio. -m_pthre = static_cast<std::uint8_t>(prioSpec >> 8U); // preemption-thre. +m_pthre = 0U; // preemption-threshold NOT used register_(); // make QF aware of this AO // the new thread is not blocked on any object @@ -10554,7 +10539,9 @@ QF_CRIT_E_(); QF::readySet_.insert(static_cast<std::uint_fast8_t>(m_prio)); // see if this thread needs to be scheduled in case QXK is running -static_cast<void>(QXK_sched_(0U)); // synchronous scheduling +if (QXK_attr_.lockCeil <= QF_MAX_ACTIVE) { + static_cast<void>(QXK_sched_()); // synchronous scheduling +} QF_CRIT_X_(); @@ -10691,7 +10678,7 @@ else if (m_eQueue.m_end != 0U) { QF::readySet_.insert( static_cast<std::uint_fast8_t>(m_prio)); if (!QXK_ISR_CONTEXT_()) { - static_cast<void>(QXK_sched_(0U)); + static_cast<void>(QXK_sched_()); } } } @@ -10770,7 +10757,7 @@ Q_ERROR_ID(410); //! @pre the thread holding the lock cannot block! Q_REQUIRE_ID(600, (QXK_attr_.lockHolder != m_prio)); QF::readySet_.remove(static_cast<std::uint_fast8_t>(m_prio)); -static_cast<void>(QXK_sched_(0U)); // synchronous scheduling +static_cast<void>(QXK_sched_()); // synchronous scheduling @@ -10787,7 +10774,7 @@ static_cast<void>(QXK_sched_(0U)); // synchronous scheduling if ((!QXK_ISR_CONTEXT_()) // not inside ISR? && (QActive::registry_[0] != nullptr)) // kernel started? { - static_cast<void>(QXK_sched_(0U)); // synchronous scheduling + static_cast<void>(QXK_sched_()); // synchronous scheduling } @@ -10992,7 +10979,7 @@ else { // remember the blocking object (this semaphore) curr->m_temp.obj = QXK_PTR_CAST_(QMState*, this); - curr->teArm_(static_cast<enum_t>(QXK::SEMA_SIG), nTicks); + curr->teArm_(static_cast<enum_t>(QXK::TIMEOUT_SIG), nTicks); QS_BEGIN_NOCRIT_PRE_(QS_SEM_BLOCK, curr->m_prio) QS_TIME_PRE_(); // timestamp @@ -11001,7 +10988,7 @@ else { QS_END_NOCRIT_PRE_() // schedule the next thread if multitasking started - static_cast<void>(QXK_sched_(0U)); // synchronous scheduling + static_cast<void>(QXK_sched_()); // synchronous scheduling QF_CRIT_X_(); QF_CRIT_EXIT_NOP(); // BLOCK here !!! @@ -11157,7 +11144,7 @@ if (m_count < m_max_count) { QS_END_NOCRIT_PRE_() if (!QXK_ISR_CONTEXT_()) { // not inside ISR? - static_cast<void>(QXK_sched_(0U)); // synchronous scheduling + static_cast<void>(QXK_sched_()); // synchronous scheduling } } } @@ -11218,7 +11205,7 @@ return signaled; - noexcept override + noexcept //! initialize the QXK priority-ceiling mutex QP::QXMutex //! //! @details @@ -11242,18 +11229,15 @@ return signaled; //! the priority and priority-threshold of the holding thread to the //! priority specification in `prioSpec` (see QP::QPrioSpec). //! -//! @attention -//! When the priority-ceiling protocol is used (`prioSpec != 0`), the -//! QF-priority specified in `prioSpec` must be unused by any other thread -//! or mutex. Also, the priority-threshold must be higher or equal to the -//! threshold of any thread that uses this mutex (see QP::QPrioSpec). -//! //! @usage //! @include qxk_mutex.cpp - m_prio = static_cast<std::uint8_t>(prioSpec & 0xFFU); -m_pthre = static_cast<std::uint8_t>(prioSpec >> 8U); + //! @pre preemption-threshold must not be used +Q_REQUIRE_ID(100, (prioSpec & 0xFF00U) == 0U); + +m_prio = static_cast<std::uint8_t>(prioSpec & 0xFFU); +m_pthre = 0U; // preemption-threshold not used if (prioSpec != 0U) { // priority-ceiling protocol used? register_(); // register this mutex as AO @@ -11495,7 +11479,7 @@ else { // the mutex is already locked by a different thread // set the blocking object (this mutex) curr->m_temp.obj = QXK_PTR_CAST_(QMState*, this); - curr->teArm_(static_cast<enum_t>(QXK::MUTEX_SIG), nTicks); + curr->teArm_(static_cast<enum_t>(QXK::TIMEOUT_SIG), nTicks); QS_BEGIN_NOCRIT_PRE_(QS_MTX_BLOCK, curr->m_prio) QS_TIME_PRE_(); // timestamp @@ -11505,7 +11489,7 @@ else { // the mutex is already locked by a different thread QS_END_NOCRIT_PRE_() // schedule the next thread if multitasking started - static_cast<void>(QXK_sched_(0U)); // synchronous scheduling + static_cast<void>(QXK_sched_()); // synchronous scheduling QF_CRIT_X_(); QF_CRIT_EXIT_NOP(); // BLOCK here !!! @@ -11663,8 +11647,8 @@ if (m_eQueue.m_nFree == 1U) { } // schedule the next thread if multitasking started - if (QXK_sched_(0U) != 0U) { // synchronous preemption needed? - QXK_activate_(0U); // synchronously activate basic threads + if (QXK_sched_() != 0U) { // synchronous preemption needed? + QXK_activate_(); // synchronously activate basic threads } } else { // releasing one level of nested mutex lock @@ -11699,11 +11683,11 @@ bzero(&QXK_attr_, sizeof(QXK_attr_)); QXK_attr_.lockCeil = (QF_MAX_ACTIVE + 1U); // scheduler locked // QXK idle AO object (const in ROM) -static QActive * const idle_obj[(sizeof(QActive)/sizeof(QActive*)) + 1U] +static QActive * const idle_ao[(sizeof(QActive)/sizeof(QActive*)) + 1U] = { nullptr }; // register the idle AO object (cast 'const' away) QActive::registry_[0] = QF_CONST_CAST_(QActive*, - QXK_PTR_CAST_(QActive const*, &idle_obj[0])); + QXK_PTR_CAST_(QActive const*, &idle_ao[0])); #ifdef QXK_INIT QXK_INIT(); // port-specific initialization of the QXK kernel @@ -11724,9 +11708,10 @@ QXK_INIT(); // port-specific initialization of the QXK kernel QXK_attr_.lockCeil = 0U; // unlock the scheduler // any active objects need to be scheduled before starting event loop? -if (QXK_sched_(0U) != 0U) { // synchronous preemption needed? - QXK_activate_(0U); // synchronously activate AOs to process events +if (QXK_sched_() != 0U) { // synchronous preemption needed? + QXK_activate_(); // synchronously activate AOs to process events } + onStartup(); // application-specific startup callback // produce the QS_QF_RUN trace record @@ -11735,6 +11720,9 @@ QS_END_NOCRIT_PRE_() QF_INT_ENABLE(); +QS_SIG_DICTIONARY(QP::QXK::DELAY_SIG, nullptr); +QS_SIG_DICTIONARY(QP::QXK::TIMEOUT_SIG, nullptr); + // the QXK idle loop... for (;;) { QXK::onIdle(); // application-specific QXK idle callback @@ -11770,15 +11758,18 @@ Q_UNUSED_PAR(stkSize); // not needed in QXK //! @pre AO cannot be started: //! - from an ISR; //! - the stack storage must NOT be provided +//! - preemption-threshold is NOT provided (because QXK kernel +//! does not support preemption-threshold scheduling) Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) - && (stkSto == nullptr)); + && (stkSto == nullptr) + && ((prioSpec & 0xFF00U) == 0U)); m_prio = static_cast<std::uint8_t>(prioSpec & 0xFFU); // QF-prio. -m_pthre = static_cast<std::uint8_t>(prioSpec >> 8U); // preemption-thre. +m_pthre = 0U; // preemption-threshold NOT used register_(); // make QF aware of this AO -m_osObject = nullptr; // no private stack for AO m_eQueue.init(qSto, qLen); // initialize QEQueue of this AO +m_osObject = nullptr; // no private stack for AO this->init(par, m_prio); // take the top-most initial tran. (virtual) QS_FLUSH(); // flush the trace buffer to the host @@ -11786,8 +11777,10 @@ QS_FLUSH(); // flush the trace buffer to the host // see if this AO needs to be scheduled in case QXK is running QF_CRIT_STAT_ QF_CRIT_E_(); -if (QXK_sched_(0U) != 0U) { // synchronous preemption needed? - QXK_activate_(0U); // synchronously activate basic threads +if (QXK_attr_.lockCeil <= QF_MAX_ACTIVE) { // scheduler running? + if (QXK_sched_() != 0U) { // synchronous preemption needed? + QXK_activate_(); // synchronously activate basic threads + } } QF_CRIT_X_(); @@ -11806,8 +11799,8 @@ QF_CRIT_X_(); { QP::QActive * volatile curr; //!< currently executing thread QP::QActive * volatile next; //!< next thread to execute - std::uint8_t volatile actPrio; //!< prio of the active AO - std::uint8_t volatile actThre; //!< active preemption-threshold + QP::QActive * volatile prev; //!< previous thread + std::uint8_t volatile actPrio; //!< QF-prio of the active AO std::uint8_t volatile lockCeil; //!< lock preemption-ceiling (0==no-lock) std::uint8_t volatile lockHolder; //!< prio of the lock holder }; @@ -11821,9 +11814,6 @@ QF_CRIT_X_(); noexcept //! QXK scheduler finds the highest-priority thread ready to run //! -//! @param[in] asynch flag conveying the type of scheduling: -//! != 0 for asynchronous scheduling and -//! == 0 for synchronous scheduling //! @details //! The QXK scheduler finds the priority of the highest-priority thread //! that is ready to run. @@ -11834,103 +11824,56 @@ QF_CRIT_X_(); //! @attention //! QXK_sched_() must be always called with interrupts **disabled** and //! returns with interrupts **disabled**. - - - Q_UNUSED_PAR(asynch); // unused when Q_SPY not defined + std::uint_fast8_t p; -// find the highest-prio thread ready to run -std::uint_fast8_t p = QP::QF::readySet_.findMax(); - -if (p <= QXK_attr_.lockCeil) { - // priority of the thread holding the lock - p = static_cast<std::uint_fast8_t>( - QP::QActive::registry_[QXK_attr_.lockHolder]->m_prio); - if (p != 0U) { - Q_ASSERT_ID(610, QP::QF::readySet_.hasElement(p)); +if (QP::QF::readySet_.isEmpty()) { + p = 0U; // no activation needed +} +else { + // find the highest-prio thread ready to run + p = QP::QF::readySet_.findMax(); + if (p <= QXK_attr_.lockCeil) { + // priority of the thread holding the lock + p = static_cast<std::uint_fast8_t>( + QP::QActive::registry_[QXK_attr_.lockHolder]->m_prio); + if (p != 0U) { + Q_ASSERT_ID(610, QP::QF::readySet_.hasElement(p)); + } } } - +QP::QActive const * const curr = QXK_attr_.curr; QP::QActive * const next = QP::QActive::registry_[p]; // the thread found must be registered in QF Q_ASSERT_ID(620, next != nullptr); // is the current thread a basic-thread? -if (QXK_attr_.curr == nullptr) { +if (curr == nullptr) { - // is next a basic-thread? - if (next->m_osObject == nullptr) { - // is the new priority above the actvie pre-thre? - if (p > QXK_attr_.actThre) { - QXK_attr_.next = next; // set the next AO to activate - } - else { - QXK_attr_.next = nullptr; + // is the new priority above the active priority? + if (p > QXK_attr_.actPrio) { + QXK_attr_.next = next; // set the next AO to activate + + if (next->m_osObject != nullptr) { // is next extended? + QXK_CONTEXT_SWITCH_(); p = 0U; // no activation needed } } - else { // the next thread is extended - -#ifdef Q_SPY - if (asynch != 0U) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_PREEMPT, next->m_prio) - QS_TIME_PRE_(); // timestamp - // prio of the next AO & prio of the curr AO - QS_2U8_PRE_(p, QXK_attr_.actPrio); - QS_END_NOCRIT_PRE_() } - else { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, next->m_prio) - QS_TIME_PRE_(); // timestamp - // prio of the next AO & prio of the curr AO - QS_2U8_PRE_(p, QXK_attr_.actPrio); - QS_END_NOCRIT_PRE_() - } -#endif // Q_SPY - - QXK_attr_.next = next; + else { // below the pre-thre + QXK_attr_.next = nullptr; p = 0U; // no activation needed - QXK_CONTEXT_SWITCH_(); } } else { // currently executing an extended-thread - - // is the next thread different from the current? - if (next != QXK_attr_.curr) { - -#ifdef Q_SPY - if (next->m_prio != 0U) { - if (asynch != 0U) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_PREEMPT, next->m_prio) - QS_TIME_PRE_(); // timestamp - // previous prio & current prio - QS_2U8_PRE_(static_cast<std::uint8_t>(p), - QXK_attr_.curr->m_prio); - QS_END_NOCRIT_PRE_() - } - else { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, next->m_prio) - QS_TIME_PRE_(); // timestamp - // previous prio & current prio - QS_2U8_PRE_(static_cast<std::uint8_t>(p), - QXK_attr_.curr->m_prio); - QS_END_NOCRIT_PRE_() - } - } - else { // resuming the idle thread - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_IDLE, 0U) - QS_TIME_PRE_(); // timestamp - QS_U8_PRE_(QXK_attr_.curr->m_prio); // previous prio - QS_END_NOCRIT_PRE_() - } -#endif + // is the current thread different from the next? + if (curr != next) { QXK_attr_.next = next; - p = 0U; // no activation needed QXK_CONTEXT_SWITCH_(); } else { // next is the same as current QXK_attr_.next = nullptr; // no need to context-switch - p = 0U; // no activation needed } + p = 0U; // no activation needed } return p; @@ -11940,9 +11883,6 @@ return p; //! QXK activator activates the next active object. The activated AO preempts //! the currently executing AOs //! -//! @param[in] asynch flag conveying the type of activation: -//! != 0 for asynchronous activation and -//! == 0 for synchronous activation //! @attention //! QXK_activate_() must be always called with interrupts **disabled** and //! returns with interrupts **disabled**. @@ -11950,63 +11890,26 @@ return p; //! @note //! The activate function might enable interrupts internally, but it always //! returns with interrupts **disabled**. - - - Q_UNUSED_PAR(asynch); // unused when Q_SPY not defined - -std::uint8_t const prio_in = QXK_attr_.actPrio; -QP::QActive *a = QXK_attr_.next; // the next AO (basic-thread) to run + std::uint8_t const prio_in = QXK_attr_.actPrio; +QP::QActive *next = QXK_attr_.next; // the next AO (basic-thread) to run //! @pre QXK_attr_.next must be valid and the prio must be in range -Q_REQUIRE_ID(700, (a != nullptr) && (prio_in <= QF_MAX_ACTIVE)); +Q_REQUIRE_ID(700, (next != nullptr) && (prio_in <= QF_MAX_ACTIVE)); // QXK Context switch callback defined or QS tracing enabled? #if (defined QXK_ON_CONTEXT_SW) || (defined Q_SPY) -std::uint_fast8_t pprev = prio_in; +QXK_contextSw(next); #endif // QXK_ON_CONTEXT_SW || Q_SPY -// priority and preemption-threshold of the next AO -std::uint_fast8_t p = static_cast<std::uint_fast8_t>(a->m_prio); +QXK_attr_.next = nullptr; // clear the next AO +QXK_attr_.curr = nullptr; // current is basic-thread + +// priority of the next thread +std::uint_fast8_t p = static_cast<std::uint_fast8_t>(next->m_prio); // loop until no more ready-to-run AOs of higher prio than the initial do { - a = QP::QActive::registry_[p]; // obtain the pointer to the AO - - QXK_attr_.actPrio = static_cast<std::uint8_t>(p); // new active prio - QXK_attr_.actThre = QP::QActive::registry_[p]->m_pthre; // new pthre - QXK_attr_.next = nullptr; // clear the next AO - -#ifdef Q_SPY - if ((asynch != 0U) && (pprev == prio_in)) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_PREEMPT, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(p, pprev); // next prio & prev prio - QS_END_NOCRIT_PRE_() - } - else { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(p, pprev); // next prio & prev prio - QS_END_NOCRIT_PRE_() - } -#endif // Q_SPY - -#if (defined QXK_ON_CONTEXT_SW) || (defined Q_SPY) - if (p != pprev) { // changing threads? - -#ifdef QXK_ON_CONTEXT_SW - Q_ASSERT_ID(710, pprev <= QF_MAX_ACTIVE); - - // context-switch callback - QXK_onContextSw(((pprev!=0U) - ? QP::QActive::registry_[pprev] - : nullptr), - a); -#endif // QXK_ON_CONTEXT_SW - - pprev = p; // update previous priority - } -#endif // QXK_ON_CONTEXT_SW || Q_SPY + QXK_attr_.actPrio = static_cast<std::uint8_t>(p); // next active prio QF_INT_ENABLE(); // unconditionally enable interrupts @@ -12016,109 +11919,81 @@ do { // 2. dispatch the event to the AO's state machine. // 3. determine if event is garbage and collect it if so // - QP::QEvt const * const e = a->get_(); - a->dispatch(e, a->m_prio); + QP::QEvt const * const e = next->get_(); + next->dispatch(e, next->m_prio); #if (QF_MAX_EPOOL > 0U) QP::QF::gc(e); #endif + QF_INT_DISABLE(); // unconditionally disable interrupts - if (a->m_eQueue.isEmpty()) { // empty queue? + if (next->m_eQueue.isEmpty()) { // empty queue? QP::QF::readySet_.remove(p); } - // find new highest-prio AO ready to run... - p = QP::QF::readySet_.findMax(); - a = QP::QActive::registry_[p]; - - // the AO must be registered in QF - Q_ASSERT_ID(720, a != nullptr); - - // is the new priority below the lock ceiling? - if (p <= static_cast<std::uint_fast8_t>(QXK_attr_.lockCeil)) { - p = static_cast<std::uint_fast8_t>(QXK_attr_.lockHolder); - if (p != 0U) { - Q_ASSERT_ID(710, QP::QF::readySet_.hasElement(p)); - } + if (QP::QF::readySet_.isEmpty()) { + QXK_attr_.next = nullptr; + next = QP::QActive::registry_[0]; + p = 0U; // no activation needed } + else { + // find new highest-prio AO ready to run... + p = QP::QF::readySet_.findMax(); + next = QP::QActive::registry_[p]; - // is the next a basic thread? - if (a->m_osObject == nullptr) { - // is the new priority above the initial pre-thre? - if (p > QP::QActive::registry_[prio_in]->m_pthre) { - QXK_attr_.next = a; + // the AO must be registered in QF + Q_ASSERT_ID(710, next != nullptr); + + // is the new priority below the lock ceiling? + if (p <= static_cast<std::uint_fast8_t>(QXK_attr_.lockCeil)) { + p = static_cast<std::uint_fast8_t>(QXK_attr_.lockHolder); + if (p != 0U) { + Q_ASSERT_ID(720, QP::QF::readySet_.hasElement(p)); + } } - else { - QXK_attr_.next = nullptr; + + // is the next a basic thread? + if (next->m_osObject == nullptr) { + // is the next priority above the initial priority? + if (p > QP::QActive::registry_[prio_in]->m_prio) { +#if (defined QXK_ON_CONTEXT_SW) || (defined Q_SPY) + if (p != QXK_attr_.actPrio) { // changing threads? + QXK_contextSw(next); + } +#endif // QXK_ON_CONTEXT_SW || Q_SPY + QXK_attr_.next = next; + } + else { + QXK_attr_.next = nullptr; + p = 0U; // no activation needed + } + } + else { // next is the extended-thread + QXK_attr_.next = next; + QXK_CONTEXT_SWITCH_(); p = 0U; // no activation needed } } - else { // next is the extended thread +} while (p != 0U); // while activation needed -#ifdef Q_SPY - if (asynch != 0U) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_PREEMPT, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(p, QXK_attr_.actPrio); - QS_END_NOCRIT_PRE_() - } - else { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(p, QXK_attr_.actPrio); - QS_END_NOCRIT_PRE_() - } -#endif // Q_SPY - - QXK_attr_.next = a; - p = 0U; // no activation needed - QXK_CONTEXT_SWITCH_(); - } -} while (p != 0U); // while preemption needed - -// restore the active priority and preemption-threshold +// restore the active priority QXK_attr_.actPrio = prio_in; -QXK_attr_.actThre = QP::QActive::registry_[prio_in]->m_pthre; #if (defined QXK_ON_CONTEXT_SW) || (defined Q_SPY) -if (prio_in != 0U) { // resuming an active object? - a = QP::QActive::registry_[prio_in]; // pointer to the preempted AO - -#ifdef Q_SPY - if (asynch != 0U) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_RESTORE, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(prio_in, pprev); // resumed prio & previous prio - QS_END_NOCRIT_PRE_() - } - else { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_RESUME, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(prio_in, pprev); // resumed prio & previous prio - QS_END_NOCRIT_PRE_() - } -#endif // Q_SPY +if (next->m_osObject == nullptr) { + QXK_contextSw((prio_in == 0U) + ? nullptr + : QP::QActive::registry_[prio_in]); } -else { // resuming priority==0 --> idle - a = nullptr; - - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_IDLE, 0U) - QS_TIME_PRE_(); // timestamp - QS_U8_PRE_(pprev); // previous prio - QS_END_NOCRIT_PRE_() -} - -#ifdef QXK_ON_CONTEXT_SW -// context-switch callback -QXK_onContextSw(QP::QActive::registry_[pprev], a); -#endif // QXK_ON_CONTEXT_SW - #endif // QXK_ON_CONTEXT_SW || Q_SPY noexcept - //! return the currently executing active-object/thread + //! obtain the currently executing active-object/thread +//! +//! @returns +//! pointer to the currently executing active-object/thread //! @pre the QXK kernel must be running Q_REQUIRE_ID(800, QXK_attr_.lockCeil <= QF_MAX_ACTIVE); @@ -12149,6 +12024,51 @@ return curr; + + + //! QXK context switch management +//! +//! @details +//! This function performs software tracing (if #Q_SPY is defined) +//! and calls QXK_onContextSw() (if #QXK_ON_CONTEXT_SW is defined) +//! +//! @param[in] next pointer to the next thread (NULL for basic-thread) +//! +//! @attention +//! QXK_contextSw() is invoked with interrupts **disabled** and must also +//! return with interrupts **disabled**. + + + std::uint8_t const prev_prio = (QXK_attr_.prev != nullptr) + ? QXK_attr_.prev->m_prio + : 0U; +std::uint8_t const next_prio = (next != nullptr) + ? next->m_prio + : QXK_attr_.actPrio; + +if (next_prio == 0U) { // going to idle? + QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_IDLE, 0U) + QS_TIME_PRE_(); // timestamp + QS_U8_PRE_(prev_prio); + QS_END_NOCRIT_PRE_() + +#ifdef QXK_ON_CONTEXT_SW + QXK_onContextSw(QXK_attr_.prev, nullptr); +#endif // QXK_ON_CONTEXT_SW +} +else { + QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, next_prio) + QS_TIME_PRE_(); // timestamp + QS_2U8_PRE_(next_prio, prev_prio); + QS_END_NOCRIT_PRE_() + +#ifdef QXK_ON_CONTEXT_SW + QXK_onContextSw(QXK_attr_.prev, next); +#endif // QXK_ON_CONTEXT_SW +} + +QXK_attr_.prev = next; // update the previous thread + //! QXK context switch callback (customized in BSPs for QXK) @@ -12206,7 +12126,7 @@ std::uint_fast8_t const p = // remove this thread from the QF QP::QActive::registry_[p] = nullptr; QP::QF::readySet_.remove(p); -static_cast<void>(QXK_sched_(0U)); // synchronous scheduling +static_cast<void>(QXK_sched_()); // synchronous scheduling QF_CRIT_X_(); @@ -12301,8 +12221,8 @@ QF_CRIT_X_(); QF::readySet_.insert( \ static_cast<std::uint_fast8_t>((me_)->m_prio)); \ if (!QXK_ISR_CONTEXT_()) { \ - if (QXK_sched_(0U) != 0U) { \ - QXK_activate_(0U); \ + if (QXK_sched_() != 0U) { \ + QXK_activate_(); \ } \ } \ } while (false) @@ -12328,7 +12248,7 @@ QF_CRIT_X_(); // major version number, Y is a 1-digit minor version number, and Z is // a 1-digit release number. // -#define QP_VERSION 710U +#define QP_VERSION 712U //! The current QP version as a zero terminated string literal. // @@ -12337,10 +12257,10 @@ QF_CRIT_X_(); // major version number, Y is a 1-digit minor version number, and Z is // a 1-digit release number. // -#define QP_VERSION_STR "7.1.0" +#define QP_VERSION_STR "7.1.2" -//! Encrypted current QP release (7.1.0) and date (2022-08-30) -#define QP_RELEASE 0x7C600159U +//! Encrypted current QP release (7.1.2) and date (2022-10-07) +#define QP_RELEASE 0x7C44FF47U //============================================================================ // Global namespace... diff --git a/src/qf/qf_time.cpp b/src/qf/qf_time.cpp index 55e7a638..be14d823 100644 --- a/src/qf/qf_time.cpp +++ b/src/qf/qf_time.cpp @@ -85,7 +85,7 @@ QTimeEvt::QTimeEvt( m_interval(0U) { //! @pre The signal must be valid and the tick rate in range - Q_REQUIRE_ID(300, (sgnl >= Q_USER_SIG) + Q_REQUIRE_ID(300, (sgnl != 0) && (tickRate < QF_MAX_TICK_RATE)); #ifndef Q_EVT_CTOR diff --git a/src/qk/qk.cpp b/src/qk/qk.cpp index 5ca5600a..ca136bd9 100644 --- a/src/qk/qk.cpp +++ b/src/qk/qk.cpp @@ -123,8 +123,8 @@ void schedUnlock(QSchedStatus const stat) noexcept { QS_BEGIN_NOCRIT_PRE_(QS_SCHED_UNLOCK, 0U) QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(lockCeil, // current lock ceiling (old) - prevCeil); // previous lock ceiling (new) + // current lock ceiling (old), previous lock ceiling (new) + QS_2U8_PRE_(lockCeil, prevCeil); QS_END_NOCRIT_PRE_() // restore the previous lock ceiling and lock holder @@ -133,7 +133,7 @@ void schedUnlock(QSchedStatus const stat) noexcept { // find if any AOs should be run after unlocking the scheduler if (QK_sched_() != 0U) { // synchronous preemption needed? - QK_activate_(0U); // synchronously activate any unlocked AOs + QK_activate_(); // synchronously activate any unlocked AOs } QF_CRIT_X_(); @@ -179,7 +179,7 @@ int_t run() { // any active objects need to be scheduled before starting event loop? if (QK_sched_() != 0U) { // synchronous preemption needed? - QK_activate_(0U); // synchronously activate AOs to process events + QK_activate_(); // synchronously activate AOs to process events } onStartup(); // application-specific startup callback @@ -238,7 +238,7 @@ void QActive::start( QF_CRIT_STAT_ QF_CRIT_E_(); if (QK_sched_() != 0U) { // synchronous preemption needed? - QK_activate_(0U); // synchronously activate AOs + QK_activate_(); // synchronously activate AOs } QF_CRIT_X_(); } @@ -255,28 +255,32 @@ QK_Attr QK_attr_; //${QK-extern-C::QK_sched_} .................................................. std::uint_fast8_t QK_sched_() noexcept { - // find the highest-prio AO with non-empty event queue - std::uint_fast8_t p = QP::QF::readySet_.findMax(); + std::uint_fast8_t p; - // is the AO's priority below the active preemption-threshold? - if (p <= QK_attr_.actThre) { - p = 0U; // no preemption needed - } - // is the AO's priority below the lock preemption-ceiling? - else if (p <= QK_attr_.lockCeil) { - p = 0U; // no preemption needed + if (QP::QF::readySet_.isEmpty()) { + p = 0U; // no activation needed } else { - Q_ASSERT_ID(410, p <= QF_MAX_ACTIVE); - QK_attr_.nextPrio = static_cast(p); // next AO to run + // find the highest-prio AO with non-empty event queue + p = QP::QF::readySet_.findMax(); + + // is the AO's priority below the active preemption-threshold? + if (p <= QK_attr_.actThre) { + p = 0U; // no activation needed + } + // is the AO's priority below the lock preemption-ceiling? + else if (p <= QK_attr_.lockCeil) { + p = 0U; // no activation needed + } + else { + QK_attr_.nextPrio = static_cast(p); + } } return p; } //${QK-extern-C::QK_activate_} ............................................... -void QK_activate_(std::uint_fast8_t const asynch) noexcept { - Q_UNUSED_PAR(asynch); // unused when Q_SPY not defined - +void QK_activate_() noexcept { std::uint8_t const prio_in = QK_attr_.actPrio; // saved initial priority std::uint_fast8_t p = QK_attr_.nextPrio; // next prio to run QK_attr_.nextPrio = 0U; // clear for the next time @@ -298,25 +302,14 @@ void QK_activate_(std::uint_fast8_t const asynch) noexcept { QK_attr_.actPrio = static_cast(p); QK_attr_.actThre = QP::QActive::registry_[p]->m_pthre; - #ifdef Q_SPY - if ((asynch != 0U) && (pprev == prio_in)) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_PREEMPT, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(p, // priority of the scheduled AO - pprev); // previous priority - QS_END_NOCRIT_PRE_() - } - else { + #if (defined QK_ON_CONTEXT_SW) || (defined Q_SPY) + if (p != pprev) { // changing threads? + QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, a->m_prio) QS_TIME_PRE_(); // timestamp QS_2U8_PRE_(p, // priority of the scheduled AO pprev); // previous priority QS_END_NOCRIT_PRE_() - } - #endif // Q_SPY - - #if (defined QK_ON_CONTEXT_SW) || (defined Q_SPY) - if (p != pprev) { // changing threads? #ifdef QK_ON_CONTEXT_SW // context-switch callback @@ -341,6 +334,7 @@ void QK_activate_(std::uint_fast8_t const asynch) noexcept { #if (QF_MAX_EPOOL > 0U) QP::QF::gc(e); #endif + // determine the next highest-priority AO ready to run... QF_INT_DISABLE(); // unconditionally disable interrupts @@ -348,19 +342,24 @@ void QK_activate_(std::uint_fast8_t const asynch) noexcept { QP::QF::readySet_.remove(p); } - // find new highest-prio AO ready to run... - p = QP::QF::readySet_.findMax(); - - // is the new priority below the initial preemption-threshold? - if (p <= QP::QActive::registry_[prio_in]->m_pthre) { - p = 0U; // no preemption needed - } - // is the AO's priority below the lock preemption-ceiling? - else if (p <= QK_attr_.lockCeil) { - p = 0U; // no preemption needed + if (QP::QF::readySet_.isEmpty()) { + p = 0U; // no activation needed } else { - Q_ASSERT_ID(510, p <= QF_MAX_ACTIVE); + // find new highest-prio AO ready to run... + p = QP::QF::readySet_.findMax(); + + // is the new priority below the initial preemption-threshold? + if (p <= QP::QActive::registry_[prio_in]->m_pthre) { + p = 0U; // no activation needed + } + // is the AO's priority below the lock preemption-ceiling? + else if (p <= QK_attr_.lockCeil) { + p = 0U; // no activation needed + } + else { + Q_ASSERT_ID(510, p <= QF_MAX_ACTIVE); + } } } while (p != 0U); @@ -372,22 +371,11 @@ void QK_activate_(std::uint_fast8_t const asynch) noexcept { if (prio_in != 0U) { // resuming an active object? a = QP::QActive::registry_[prio_in]; // pointer to preempted AO - #ifdef Q_SPY - if (asynch != 0U) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_RESTORE, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(prio_in, // priority of the resumed AO - pprev); // previous priority - QS_END_NOCRIT_PRE_() - } - else { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_RESUME, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(prio_in, // priority of the resumed AO - pprev); // previous priority - QS_END_NOCRIT_PRE_() - } - #endif // Q_SPY + QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, a->m_prio) + QS_TIME_PRE_(); // timestamp + // priority of the resumed AO, previous priority + QS_2U8_PRE_(prio_in, pprev); + QS_END_NOCRIT_PRE_() } else { // resuming priority==0 --> idle a = nullptr; // QK idle loop diff --git a/src/qxk/qxk.cpp b/src/qxk/qxk.cpp index 1aa12947..210c2526 100644 --- a/src/qxk/qxk.cpp +++ b/src/qxk/qxk.cpp @@ -136,8 +136,8 @@ void schedUnlock(QSchedStatus const stat) noexcept { QXK_attr_.lockHolder = static_cast(stat & 0xFFU); // find the highest-prio thread ready to run - if (QXK_sched_(0U) != 0U) { // synchronous preemption needed? - QXK_activate_(0U); // synchronously activate unlocked AOs + if (QXK_sched_() != 0U) { // synchronous preemption needed? + QXK_activate_(); // synchronously activate unlocked AOs } QF_CRIT_X_(); @@ -166,11 +166,11 @@ void init() { QXK_attr_.lockCeil = (QF_MAX_ACTIVE + 1U); // scheduler locked // QXK idle AO object (const in ROM) - static QActive * const idle_obj[(sizeof(QActive)/sizeof(QActive*)) + 1U] + static QActive * const idle_ao[(sizeof(QActive)/sizeof(QActive*)) + 1U] = { nullptr }; // register the idle AO object (cast 'const' away) QActive::registry_[0] = QF_CONST_CAST_(QActive*, - QXK_PTR_CAST_(QActive const*, &idle_obj[0])); + QXK_PTR_CAST_(QActive const*, &idle_ao[0])); #ifdef QXK_INIT QXK_INIT(); // port-specific initialization of the QXK kernel @@ -189,9 +189,10 @@ int_t run() { QXK_attr_.lockCeil = 0U; // unlock the scheduler // any active objects need to be scheduled before starting event loop? - if (QXK_sched_(0U) != 0U) { // synchronous preemption needed? - QXK_activate_(0U); // synchronously activate AOs to process events + if (QXK_sched_() != 0U) { // synchronous preemption needed? + QXK_activate_(); // synchronously activate AOs to process events } + onStartup(); // application-specific startup callback // produce the QS_QF_RUN trace record @@ -200,6 +201,9 @@ int_t run() { QF_INT_ENABLE(); + QS_SIG_DICTIONARY(QP::QXK::DELAY_SIG, nullptr); + QS_SIG_DICTIONARY(QP::QXK::TIMEOUT_SIG, nullptr); + // the QXK idle loop... for (;;) { QXK::onIdle(); // application-specific QXK idle callback @@ -233,15 +237,18 @@ void QActive::start( //! @pre AO cannot be started: //! - from an ISR; //! - the stack storage must NOT be provided + //! - preemption-threshold is NOT provided (because QXK kernel + //! does not support preemption-threshold scheduling) Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) - && (stkSto == nullptr)); + && (stkSto == nullptr) + && ((prioSpec & 0xFF00U) == 0U)); m_prio = static_cast(prioSpec & 0xFFU); // QF-prio. - m_pthre = static_cast(prioSpec >> 8U); // preemption-thre. + m_pthre = 0U; // preemption-threshold NOT used register_(); // make QF aware of this AO - m_osObject = nullptr; // no private stack for AO m_eQueue.init(qSto, qLen); // initialize QEQueue of this AO + m_osObject = nullptr; // no private stack for AO this->init(par, m_prio); // take the top-most initial tran. (virtual) QS_FLUSH(); // flush the trace buffer to the host @@ -249,8 +256,10 @@ void QActive::start( // see if this AO needs to be scheduled in case QXK is running QF_CRIT_STAT_ QF_CRIT_E_(); - if (QXK_sched_(0U) != 0U) { // synchronous preemption needed? - QXK_activate_(0U); // synchronously activate basic threads + if (QXK_attr_.lockCeil <= QF_MAX_ACTIVE) { // scheduler running? + if (QXK_sched_() != 0U) { // synchronous preemption needed? + QXK_activate_(); // synchronously activate basic threads + } } QF_CRIT_X_(); } @@ -266,163 +275,83 @@ extern "C" { QXK_Attr QXK_attr_; //${QXK-extern-C::QXK_sched_} ................................................ -std::uint_fast8_t QXK_sched_(std::uint_fast8_t const asynch) noexcept { - Q_UNUSED_PAR(asynch); // unused when Q_SPY not defined +std::uint_fast8_t QXK_sched_() noexcept { + std::uint_fast8_t p; - // find the highest-prio thread ready to run - std::uint_fast8_t p = QP::QF::readySet_.findMax(); - - if (p <= QXK_attr_.lockCeil) { - // priority of the thread holding the lock - p = static_cast( - QP::QActive::registry_[QXK_attr_.lockHolder]->m_prio); - if (p != 0U) { - Q_ASSERT_ID(610, QP::QF::readySet_.hasElement(p)); + if (QP::QF::readySet_.isEmpty()) { + p = 0U; // no activation needed + } + else { + // find the highest-prio thread ready to run + p = QP::QF::readySet_.findMax(); + if (p <= QXK_attr_.lockCeil) { + // priority of the thread holding the lock + p = static_cast( + QP::QActive::registry_[QXK_attr_.lockHolder]->m_prio); + if (p != 0U) { + Q_ASSERT_ID(610, QP::QF::readySet_.hasElement(p)); + } } } - + QP::QActive const * const curr = QXK_attr_.curr; QP::QActive * const next = QP::QActive::registry_[p]; // the thread found must be registered in QF Q_ASSERT_ID(620, next != nullptr); // is the current thread a basic-thread? - if (QXK_attr_.curr == nullptr) { + if (curr == nullptr) { - // is next a basic-thread? - if (next->m_osObject == nullptr) { - // is the new priority above the actvie pre-thre? - if (p > QXK_attr_.actThre) { - QXK_attr_.next = next; // set the next AO to activate - } - else { - QXK_attr_.next = nullptr; + // is the new priority above the active priority? + if (p > QXK_attr_.actPrio) { + QXK_attr_.next = next; // set the next AO to activate + + if (next->m_osObject != nullptr) { // is next extended? + QXK_CONTEXT_SWITCH_(); p = 0U; // no activation needed } } - else { // the next thread is extended - - #ifdef Q_SPY - if (asynch != 0U) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_PREEMPT, next->m_prio) - QS_TIME_PRE_(); // timestamp - // prio of the next AO & prio of the curr AO - QS_2U8_PRE_(p, QXK_attr_.actPrio); - QS_END_NOCRIT_PRE_() } - else { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, next->m_prio) - QS_TIME_PRE_(); // timestamp - // prio of the next AO & prio of the curr AO - QS_2U8_PRE_(p, QXK_attr_.actPrio); - QS_END_NOCRIT_PRE_() - } - #endif // Q_SPY - - QXK_attr_.next = next; + else { // below the pre-thre + QXK_attr_.next = nullptr; p = 0U; // no activation needed - QXK_CONTEXT_SWITCH_(); } } else { // currently executing an extended-thread - - // is the next thread different from the current? - if (next != QXK_attr_.curr) { - - #ifdef Q_SPY - if (next->m_prio != 0U) { - if (asynch != 0U) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_PREEMPT, next->m_prio) - QS_TIME_PRE_(); // timestamp - // previous prio & current prio - QS_2U8_PRE_(static_cast(p), - QXK_attr_.curr->m_prio); - QS_END_NOCRIT_PRE_() - } - else { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, next->m_prio) - QS_TIME_PRE_(); // timestamp - // previous prio & current prio - QS_2U8_PRE_(static_cast(p), - QXK_attr_.curr->m_prio); - QS_END_NOCRIT_PRE_() - } - } - else { // resuming the idle thread - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_IDLE, 0U) - QS_TIME_PRE_(); // timestamp - QS_U8_PRE_(QXK_attr_.curr->m_prio); // previous prio - QS_END_NOCRIT_PRE_() - } - #endif + // is the current thread different from the next? + if (curr != next) { QXK_attr_.next = next; - p = 0U; // no activation needed QXK_CONTEXT_SWITCH_(); } else { // next is the same as current QXK_attr_.next = nullptr; // no need to context-switch - p = 0U; // no activation needed } + p = 0U; // no activation needed } return p; } //${QXK-extern-C::QXK_activate_} ............................................. -void QXK_activate_(std::uint_fast8_t const asynch) noexcept { - Q_UNUSED_PAR(asynch); // unused when Q_SPY not defined - +void QXK_activate_() noexcept { std::uint8_t const prio_in = QXK_attr_.actPrio; - QP::QActive *a = QXK_attr_.next; // the next AO (basic-thread) to run + QP::QActive *next = QXK_attr_.next; // the next AO (basic-thread) to run //! @pre QXK_attr_.next must be valid and the prio must be in range - Q_REQUIRE_ID(700, (a != nullptr) && (prio_in <= QF_MAX_ACTIVE)); + Q_REQUIRE_ID(700, (next != nullptr) && (prio_in <= QF_MAX_ACTIVE)); // QXK Context switch callback defined or QS tracing enabled? #if (defined QXK_ON_CONTEXT_SW) || (defined Q_SPY) - std::uint_fast8_t pprev = prio_in; + QXK_contextSw(next); #endif // QXK_ON_CONTEXT_SW || Q_SPY - // priority and preemption-threshold of the next AO - std::uint_fast8_t p = static_cast(a->m_prio); + QXK_attr_.next = nullptr; // clear the next AO + QXK_attr_.curr = nullptr; // current is basic-thread + + // priority of the next thread + std::uint_fast8_t p = static_cast(next->m_prio); // loop until no more ready-to-run AOs of higher prio than the initial do { - a = QP::QActive::registry_[p]; // obtain the pointer to the AO - - QXK_attr_.actPrio = static_cast(p); // new active prio - QXK_attr_.actThre = QP::QActive::registry_[p]->m_pthre; // new pthre - QXK_attr_.next = nullptr; // clear the next AO - - #ifdef Q_SPY - if ((asynch != 0U) && (pprev == prio_in)) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_PREEMPT, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(p, pprev); // next prio & prev prio - QS_END_NOCRIT_PRE_() - } - else { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(p, pprev); // next prio & prev prio - QS_END_NOCRIT_PRE_() - } - #endif // Q_SPY - - #if (defined QXK_ON_CONTEXT_SW) || (defined Q_SPY) - if (p != pprev) { // changing threads? - - #ifdef QXK_ON_CONTEXT_SW - Q_ASSERT_ID(710, pprev <= QF_MAX_ACTIVE); - - // context-switch callback - QXK_onContextSw(((pprev!=0U) - ? QP::QActive::registry_[pprev] - : nullptr), - a); - #endif // QXK_ON_CONTEXT_SW - - pprev = p; // update previous priority - } - #endif // QXK_ON_CONTEXT_SW || Q_SPY + QXK_attr_.actPrio = static_cast(p); // next active prio QF_INT_ENABLE(); // unconditionally enable interrupts @@ -432,103 +361,72 @@ void QXK_activate_(std::uint_fast8_t const asynch) noexcept { // 2. dispatch the event to the AO's state machine. // 3. determine if event is garbage and collect it if so // - QP::QEvt const * const e = a->get_(); - a->dispatch(e, a->m_prio); + QP::QEvt const * const e = next->get_(); + next->dispatch(e, next->m_prio); #if (QF_MAX_EPOOL > 0U) QP::QF::gc(e); #endif + QF_INT_DISABLE(); // unconditionally disable interrupts - if (a->m_eQueue.isEmpty()) { // empty queue? + if (next->m_eQueue.isEmpty()) { // empty queue? QP::QF::readySet_.remove(p); } - // find new highest-prio AO ready to run... - p = QP::QF::readySet_.findMax(); - a = QP::QActive::registry_[p]; - - // the AO must be registered in QF - Q_ASSERT_ID(720, a != nullptr); - - // is the new priority below the lock ceiling? - if (p <= static_cast(QXK_attr_.lockCeil)) { - p = static_cast(QXK_attr_.lockHolder); - if (p != 0U) { - Q_ASSERT_ID(710, QP::QF::readySet_.hasElement(p)); - } + if (QP::QF::readySet_.isEmpty()) { + QXK_attr_.next = nullptr; + next = QP::QActive::registry_[0]; + p = 0U; // no activation needed } + else { + // find new highest-prio AO ready to run... + p = QP::QF::readySet_.findMax(); + next = QP::QActive::registry_[p]; - // is the next a basic thread? - if (a->m_osObject == nullptr) { - // is the new priority above the initial pre-thre? - if (p > QP::QActive::registry_[prio_in]->m_pthre) { - QXK_attr_.next = a; + // the AO must be registered in QF + Q_ASSERT_ID(710, next != nullptr); + + // is the new priority below the lock ceiling? + if (p <= static_cast(QXK_attr_.lockCeil)) { + p = static_cast(QXK_attr_.lockHolder); + if (p != 0U) { + Q_ASSERT_ID(720, QP::QF::readySet_.hasElement(p)); + } } - else { - QXK_attr_.next = nullptr; + + // is the next a basic thread? + if (next->m_osObject == nullptr) { + // is the next priority above the initial priority? + if (p > QP::QActive::registry_[prio_in]->m_prio) { + #if (defined QXK_ON_CONTEXT_SW) || (defined Q_SPY) + if (p != QXK_attr_.actPrio) { // changing threads? + QXK_contextSw(next); + } + #endif // QXK_ON_CONTEXT_SW || Q_SPY + QXK_attr_.next = next; + } + else { + QXK_attr_.next = nullptr; + p = 0U; // no activation needed + } + } + else { // next is the extended-thread + QXK_attr_.next = next; + QXK_CONTEXT_SWITCH_(); p = 0U; // no activation needed } } - else { // next is the extended thread + } while (p != 0U); // while activation needed - #ifdef Q_SPY - if (asynch != 0U) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_PREEMPT, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(p, QXK_attr_.actPrio); - QS_END_NOCRIT_PRE_() - } - else { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(p, QXK_attr_.actPrio); - QS_END_NOCRIT_PRE_() - } - #endif // Q_SPY - - QXK_attr_.next = a; - p = 0U; // no activation needed - QXK_CONTEXT_SWITCH_(); - } - } while (p != 0U); // while preemption needed - - // restore the active priority and preemption-threshold + // restore the active priority QXK_attr_.actPrio = prio_in; - QXK_attr_.actThre = QP::QActive::registry_[prio_in]->m_pthre; #if (defined QXK_ON_CONTEXT_SW) || (defined Q_SPY) - if (prio_in != 0U) { // resuming an active object? - a = QP::QActive::registry_[prio_in]; // pointer to the preempted AO - - #ifdef Q_SPY - if (asynch != 0U) { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_RESTORE, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(prio_in, pprev); // resumed prio & previous prio - QS_END_NOCRIT_PRE_() - } - else { - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_RESUME, a->m_prio) - QS_TIME_PRE_(); // timestamp - QS_2U8_PRE_(prio_in, pprev); // resumed prio & previous prio - QS_END_NOCRIT_PRE_() - } - #endif // Q_SPY + if (next->m_osObject == nullptr) { + QXK_contextSw((prio_in == 0U) + ? nullptr + : QP::QActive::registry_[prio_in]); } - else { // resuming priority==0 --> idle - a = nullptr; - - QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_IDLE, 0U) - QS_TIME_PRE_(); // timestamp - QS_U8_PRE_(pprev); // previous prio - QS_END_NOCRIT_PRE_() - } - - #ifdef QXK_ON_CONTEXT_SW - // context-switch callback - QXK_onContextSw(QP::QActive::registry_[pprev], a); - #endif // QXK_ON_CONTEXT_SW - #endif // QXK_ON_CONTEXT_SW || Q_SPY } @@ -552,6 +450,41 @@ QP::QActive * QXK_current() noexcept { return curr; } +//${QXK-extern-C::QXK_contextSw} ............................................. +#if defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) +void QXK_contextSw(QP::QActive * const next) { + std::uint8_t const prev_prio = (QXK_attr_.prev != nullptr) + ? QXK_attr_.prev->m_prio + : 0U; + std::uint8_t const next_prio = (next != nullptr) + ? next->m_prio + : QXK_attr_.actPrio; + + if (next_prio == 0U) { // going to idle? + QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_IDLE, 0U) + QS_TIME_PRE_(); // timestamp + QS_U8_PRE_(prev_prio); + QS_END_NOCRIT_PRE_() + + #ifdef QXK_ON_CONTEXT_SW + QXK_onContextSw(QXK_attr_.prev, nullptr); + #endif // QXK_ON_CONTEXT_SW + } + else { + QS_BEGIN_NOCRIT_PRE_(QP::QS_SCHED_NEXT, next_prio) + QS_TIME_PRE_(); // timestamp + QS_2U8_PRE_(next_prio, prev_prio); + QS_END_NOCRIT_PRE_() + + #ifdef QXK_ON_CONTEXT_SW + QXK_onContextSw(QXK_attr_.prev, next); + #endif // QXK_ON_CONTEXT_SW + } + + QXK_attr_.prev = next; // update the previous thread +} +#endif // defined(Q_SPY) || defined(QXK_ON_CONTEXT_SW) + //${QXK-extern-C::QXK_threadExit_} ........................................... void QXK_threadExit_() { QF_CRIT_STAT_ @@ -573,7 +506,7 @@ void QXK_threadExit_() { // remove this thread from the QF QP::QActive::registry_[p] = nullptr; QP::QF::readySet_.remove(p); - static_cast(QXK_sched_(0U)); // synchronous scheduling + static_cast(QXK_sched_()); // synchronous scheduling QF_CRIT_X_(); } //$enddef${QXK-extern-C} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/qxk/qxk_mutex.cpp b/src/qxk/qxk_mutex.cpp index 2eab986a..6123bfb4 100644 --- a/src/qxk/qxk_mutex.cpp +++ b/src/qxk/qxk_mutex.cpp @@ -79,8 +79,11 @@ QXMutex::QXMutex() //${QXK::QXMutex::init} ...................................................... void QXMutex::init(QPrioSpec const prioSpec) noexcept { + //! @pre preemption-threshold must not be used + Q_REQUIRE_ID(100, (prioSpec & 0xFF00U) == 0U); + m_prio = static_cast(prioSpec & 0xFFU); - m_pthre = static_cast(prioSpec >> 8U); + m_pthre = 0U; // preemption-threshold not used if (prioSpec != 0U) { // priority-ceiling protocol used? register_(); // register this mutex as AO @@ -281,7 +284,7 @@ bool QXMutex::lock(std::uint_fast16_t const nTicks) noexcept { // set the blocking object (this mutex) curr->m_temp.obj = QXK_PTR_CAST_(QMState*, this); - curr->teArm_(static_cast(QXK::MUTEX_SIG), nTicks); + curr->teArm_(static_cast(QXK::TIMEOUT_SIG), nTicks); QS_BEGIN_NOCRIT_PRE_(QS_MTX_BLOCK, curr->m_prio) QS_TIME_PRE_(); // timestamp @@ -291,7 +294,7 @@ bool QXMutex::lock(std::uint_fast16_t const nTicks) noexcept { QS_END_NOCRIT_PRE_() // schedule the next thread if multitasking started - static_cast(QXK_sched_(0U)); // synchronous scheduling + static_cast(QXK_sched_()); // synchronous scheduling QF_CRIT_X_(); QF_CRIT_EXIT_NOP(); // BLOCK here !!! @@ -432,8 +435,8 @@ void QXMutex::unlock() noexcept { } // schedule the next thread if multitasking started - if (QXK_sched_(0U) != 0U) { // synchronous preemption needed? - QXK_activate_(0U); // synchronously activate basic threads + if (QXK_sched_() != 0U) { // synchronous preemption needed? + QXK_activate_(); // synchronously activate basic threads } } else { // releasing one level of nested mutex lock diff --git a/src/qxk/qxk_sema.cpp b/src/qxk/qxk_sema.cpp index 8d561deb..9914ee23 100644 --- a/src/qxk/qxk_sema.cpp +++ b/src/qxk/qxk_sema.cpp @@ -125,7 +125,7 @@ bool QXSemaphore::wait(std::uint_fast16_t const nTicks) noexcept { // remember the blocking object (this semaphore) curr->m_temp.obj = QXK_PTR_CAST_(QMState*, this); - curr->teArm_(static_cast(QXK::SEMA_SIG), nTicks); + curr->teArm_(static_cast(QXK::TIMEOUT_SIG), nTicks); QS_BEGIN_NOCRIT_PRE_(QS_SEM_BLOCK, curr->m_prio) QS_TIME_PRE_(); // timestamp @@ -134,7 +134,7 @@ bool QXSemaphore::wait(std::uint_fast16_t const nTicks) noexcept { QS_END_NOCRIT_PRE_() // schedule the next thread if multitasking started - static_cast(QXK_sched_(0U)); // synchronous scheduling + static_cast(QXK_sched_()); // synchronous scheduling QF_CRIT_X_(); QF_CRIT_EXIT_NOP(); // BLOCK here !!! @@ -260,7 +260,7 @@ bool QXSemaphore::signal() noexcept { QS_END_NOCRIT_PRE_() if (!QXK_ISR_CONTEXT_()) { // not inside ISR? - static_cast(QXK_sched_(0U)); // synchronous scheduling + static_cast(QXK_sched_()); // synchronous scheduling } } } diff --git a/src/qxk/qxk_xthr.cpp b/src/qxk/qxk_xthr.cpp index ea2630b5..87f6520c 100644 --- a/src/qxk/qxk_xthr.cpp +++ b/src/qxk/qxk_xthr.cpp @@ -163,10 +163,10 @@ QEvt const * QXThread::queueGet(std::uint_fast16_t const nTicks) noexcept { // remember the blocking object (the thread's queue) thr->m_temp.obj = QXK_PTR_CAST_(QMState*, &thr->m_eQueue); - thr->teArm_(static_cast(QXK::QUEUE_SIG), nTicks); + thr->teArm_(static_cast(QXK::TIMEOUT_SIG), nTicks); QF::readySet_.remove( static_cast(thr->m_prio)); - static_cast(QXK_sched_(0U)); // synchronous scheduling + static_cast(QXK_sched_()); // synchronous scheduling QF_CRIT_X_(); QF_CRIT_EXIT_NOP(); // BLOCK here @@ -269,10 +269,13 @@ void QXThread::start( //! - NOT be called from an ISR; //! - the stack storage must be provided; //! - the thread must be instantiated (see #QXThread). + //! - preemption-threshold is NOT provided (because QXK kernel + //! does not support preemption-threshold scheduling) Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) && (stkSto != nullptr) && (stkSize != 0U) - && (m_state.act == nullptr)); + && (m_state.act == nullptr) + && ((prioSpec & 0xFF00U) == 0U)); // is storage for the queue buffer provided? if (qSto != nullptr) { @@ -284,7 +287,7 @@ void QXThread::start( QXK_stackInit_(this, m_temp.thr, stkSto, stkSize); m_prio = static_cast(prioSpec & 0xFFU); // QF-prio. - m_pthre = static_cast(prioSpec >> 8U); // preemption-thre. + m_pthre = 0U; // preemption-threshold NOT used register_(); // make QF aware of this AO // the new thread is not blocked on any object @@ -296,7 +299,9 @@ void QXThread::start( QF::readySet_.insert(static_cast(m_prio)); // see if this thread needs to be scheduled in case QXK is running - static_cast(QXK_sched_(0U)); // synchronous scheduling + if (QXK_attr_.lockCeil <= QF_MAX_ACTIVE) { + static_cast(QXK_sched_()); // synchronous scheduling + } QF_CRIT_X_(); } @@ -386,7 +391,7 @@ bool QXThread::post_( QF::readySet_.insert( static_cast(m_prio)); if (!QXK_ISR_CONTEXT_()) { - static_cast(QXK_sched_(0U)); + static_cast(QXK_sched_()); } } } @@ -446,7 +451,7 @@ void QXThread::block_() const noexcept { //! @pre the thread holding the lock cannot block! Q_REQUIRE_ID(600, (QXK_attr_.lockHolder != m_prio)); QF::readySet_.remove(static_cast(m_prio)); - static_cast(QXK_sched_(0U)); // synchronous scheduling + static_cast(QXK_sched_()); // synchronous scheduling } //${QXK::QXThread::unblock_} ................................................. @@ -456,7 +461,7 @@ void QXThread::unblock_() const noexcept { if ((!QXK_ISR_CONTEXT_()) // not inside ISR? && (QActive::registry_[0] != nullptr)) // kernel started? { - static_cast(QXK_sched_(0U)); // synchronous scheduling + static_cast(QXK_sched_()); // synchronous scheduling } } diff --git a/test/qk/test_pts/test_pts.py b/test/qk/test_pts/test_pts.py deleted file mode 100644 index fc24108b..00000000 --- a/test/qk/test_pts/test_pts.py +++ /dev/null @@ -1,64 +0,0 @@ -# test-script for QUTest unit testing harness -# see https://www.state-machine.com/qtools/qutest.html/qutest.html - -# preamble -def on_reset(): - expect_pause() - -def Q_PRIO(prio, pthre): - return prio | (pthre << 8) - -test("NO preemption-threshold (scheduler only)") -continue_test() -expect_run() -#---- -glb_filter(GRP_SM, GRP_SC) -current_obj(OBJ_AO, "ObjB::inst[1]") -post("TRIG_SIG") -expect("@timestamp Sch-Next Pri=0->2") -expect("@timestamp Disp===> Obj=ObjB::inst[1],Sig=TRIG_SIG,State=ObjB::active") -expect("@timestamp Sch-Pre Pri=2->4") -expect("@timestamp Disp===> Obj=ObjA::inst,Sig=TEST_SIG,State=ObjA::active") -expect("@timestamp =>Intern Obj=ObjA::inst,Sig=TEST_SIG,State=ObjA::active") -expect("@timestamp Sch-Next Pri=4->3") -expect("@timestamp Disp===> Obj=ObjB::inst[2],Sig=TEST_SIG,State=ObjB::active") -expect("@timestamp =>Intern Obj=ObjB::inst[2],Sig=TEST_SIG,State=ObjB::active") -expect("@timestamp Sch-Rest Pri=3->2") -expect("@timestamp =>Intern Obj=ObjB::inst[1],Sig=TRIG_SIG,State=ObjB::active") -expect("@timestamp Sch-Next Pri=2->2") -expect("@timestamp Disp===> Obj=ObjB::inst[1],Sig=TEST_SIG,State=ObjB::active") -expect("@timestamp =>Intern Obj=ObjB::inst[1],Sig=TEST_SIG,State=ObjB::active") -expect("@timestamp Sch-Next Pri=2->1") -expect("@timestamp Disp===> Obj=ObjB::inst[0],Sig=TEST_SIG,State=ObjB::active") -expect("@timestamp =>Intern Obj=ObjB::inst[0],Sig=TEST_SIG,State=ObjB::active") -expect("@timestamp Sch-Idle Pri=1->0") -expect("@timestamp Trg-Done QS_RX_EVENT") - -test("preemption-threshold (scheduler only)") -current_obj(OBJ_AP, "pspec") -poke(0, 2, pack("2") -expect("@timestamp Disp===> Obj=ObjB::inst[1],Sig=TRIG_SIG,State=ObjB::active") -expect("@timestamp Sch-Pre Pri=2->4") -expect("@timestamp Disp===> Obj=ObjA::inst,Sig=TEST_SIG,State=ObjA::active") -expect("@timestamp =>Intern Obj=ObjA::inst,Sig=TEST_SIG,State=ObjA::active") -expect("@timestamp Sch-Rest Pri=4->2") -expect("@timestamp =>Intern Obj=ObjB::inst[1],Sig=TRIG_SIG,State=ObjB::active") -expect("@timestamp Sch-Next Pri=2->3") -expect("@timestamp Disp===> Obj=ObjB::inst[2],Sig=TEST_SIG,State=ObjB::active") -expect("@timestamp =>Intern Obj=ObjB::inst[2],Sig=TEST_SIG,State=ObjB::active") -expect("@timestamp Sch-Next Pri=3->2") -expect("@timestamp Disp===> Obj=ObjB::inst[1],Sig=TEST_SIG,State=ObjB::active") -expect("@timestamp =>Intern Obj=ObjB::inst[1],Sig=TEST_SIG,State=ObjB::active") -expect("@timestamp Sch-Next Pri=2->1") -expect("@timestamp Disp===> Obj=ObjB::inst[0],Sig=TEST_SIG,State=ObjB::active") -expect("@timestamp =>Intern Obj=ObjB::inst[0],Sig=TEST_SIG,State=ObjB::active") -expect("@timestamp Sch-Idle Pri=1->0") -expect("@timestamp Trg-Done QS_RX_EVENT") diff --git a/test/qk/src/bsp.hpp b/test/qk/test_sched/bsp.hpp similarity index 90% rename from test/qk/src/bsp.hpp rename to test/qk/test_sched/bsp.hpp index a6926e59..dab38994 100644 --- a/test/qk/src/bsp.hpp +++ b/test/qk/test_sched/bsp.hpp @@ -1,7 +1,7 @@ //============================================================================ // Product: BSP for system-testing QXK -// Last updated for version 7.1.1 -// Last updated on 2022-09-04 +// Last updated for version 7.1.2 +// Last updated on 2022-10-06 // // Q u a n t u m L e a P s // ------------------------ @@ -36,12 +36,11 @@ namespace BSP { -enum { TICKS_PER_SEC = 100 }; - void init(void); void terminate(int16_t const result); // for testing... +void trace(QP::QActive const *thr, char const *msg); void wait4PB1(void); void ledOn(void); void ledOff(void); @@ -50,11 +49,12 @@ void trigISR(void); } // namespace BSP enum TestSignals { - TEST_SIG = QP::Q_USER_SIG, + TEST0_SIG = QP::Q_USER_SIG, + TEST1_SIG, + TEST2_SIG, + TEST3_SIG, MAX_PUB_SIG, // the last published signal - TIMEOUT_SIG, - TRIG_SIG, MAX_SIG // the last signal }; diff --git a/test/qk/src/bsp_efm32.cpp b/test/qk/test_sched/bsp_efm32.cpp similarity index 92% rename from test/qk/src/bsp_efm32.cpp rename to test/qk/test_sched/bsp_efm32.cpp index 27c31df9..1c5bf961 100644 --- a/test/qk/src/bsp_efm32.cpp +++ b/test/qk/test_sched/bsp_efm32.cpp @@ -1,7 +1,7 @@ //============================================================================ // Product: BSP for system-testing QK, EFM32-SLSTK3401A board -// Last updated for version 7.1.1 -// Last updated on 2022-09-04 +// Last updated for version 7.1.2 +// Last updated on 2022-10-06 // // Q u a n t u m L e a P s // ------------------------ @@ -60,11 +60,9 @@ namespace BSP { static QP::QSpyId const l_SysTick_Handler = { 0U }; static QP::QSpyId const l_test_ISR = { 0U }; - static USART_TypeDef * const l_USART0 = ((USART_TypeDef *)(0x40010000UL)); - enum AppRecords { // application-specific trace records CONTEXT_SW = QP::QS_USER, - COMMAND_STAT + TRACE_MSG }; #endif @@ -90,8 +88,8 @@ void GPIO_EVEN_IRQHandler(void) { QK_ISR_ENTRY(); // inform QK about entering an ISR // for testing... - QP::QF::PUBLISH(Q_NEW(QP::QEvt, TEST_SIG), // for testing... - &BSP::l_test_ISR); + static QP::QEvt const t1 = { TEST1_SIG, 0U, 0U }; + QP::QF::PUBLISH(&t1, &BSP::l_test_ISR); QK_ISR_EXIT(); // inform QK about exiting an ISR } @@ -130,7 +128,11 @@ void BSP::init(void) { QS_OBJ_DICTIONARY(&l_test_ISR); QS_USR_DICTIONARY(CONTEXT_SW); - QS_USR_DICTIONARY(COMMAND_STAT); + QS_USR_DICTIONARY(TRACE_MSG); +} +//............................................................................ +void BSP::terminate(int16_t result) { + Q_UNUSED_PAR(result); } //............................................................................ void BSP::ledOn(void) { @@ -145,8 +147,11 @@ void BSP::trigISR(void) { NVIC_SetPendingIRQ(GPIO_EVEN_IRQn); } //............................................................................ -void BSP::terminate(int16_t result) { - (void)result; +void BSP::trace(QP::QActive const *thr, char const *msg) { + QS_BEGIN_ID(TRACE_MSG, 0U) + QS_OBJ(thr); + QS_STR(msg); + QS_END() } // namespace QP ============================================================== @@ -175,16 +180,6 @@ void QF::onStartup(void) { void QF::onCleanup(void) { } //............................................................................ -#ifdef QK_ON_CONTEXT_SW -// NOTE: the context-switch callback is called with interrupts DISABLED -void QK::onContextSw(QActive *prev, QActive *next) { - QS_BEGIN_NOCRIT(BSP::CONTEXT_SW, 0U) // no critical section! - QS_OBJ(prev); - QS_OBJ(next); - QS_END_NOCRIT() -} -#endif // QK_ON_CONTEXT_SW -//............................................................................ void QK::onIdle(void) { #ifdef Q_SPY QS::rxParse(); // parse all the received bytes @@ -199,7 +194,6 @@ void QK::onIdle(void) { } // QS callbacks ============================================================== -#ifdef Q_SPY //............................................................................ void QTimeEvt::tick1_( uint_fast8_t const tickRate, @@ -211,8 +205,21 @@ void QTimeEvt::tick1_( QF_INT_ENABLE(); } -#endif // Q_SPY //---------------------------------------------------------------------------- } // namespace QP +extern "C" { +//............................................................................ +#ifdef QK_ON_CONTEXT_SW +// NOTE: the context-switch callback is called with interrupts DISABLED +void QK_onContextSw(QP::QActive *prev, QP::QActive *next) { + QS_BEGIN_NOCRIT(BSP::CONTEXT_SW, 0U) // no critical section! + QS_OBJ(prev); + QS_OBJ(next); + QS_END_NOCRIT() +} +#endif // QK_ON_CONTEXT_SW + +} // extern "C" + diff --git a/test/qk/src/bsp_l053r8.cpp b/test/qk/test_sched/bsp_l053r8.cpp similarity index 92% rename from test/qk/src/bsp_l053r8.cpp rename to test/qk/test_sched/bsp_l053r8.cpp index 2bb31c84..59bb6dca 100644 --- a/test/qk/src/bsp_l053r8.cpp +++ b/test/qk/test_sched/bsp_l053r8.cpp @@ -1,7 +1,7 @@ //============================================================================ // Product: BSP for system-testing QK kernel, NUCLEO-L053R8 board -// Last updated for version 7.1.1 -// Last updated on 2022-09-04 +// Last updated for version 7.1.2 +// Last updated on 2022-10-06 // // Q u a n t u m L e a P s // ------------------------ @@ -57,7 +57,7 @@ namespace BSP { enum AppRecords { // application-specific trace records CONTEXT_SW = QP::QS_USER, - COMMAND_STAT + TRACE_MSG }; #endif @@ -83,8 +83,8 @@ void EXTI0_1_IRQHandler(void) { QK_ISR_ENTRY(); // inform QK about entering an ISR // for testing... - QP::QF::PUBLISH(Q_NEW(QP::QEvt, TEST_SIG), // for testing... - &BSP::l_test_ISR); + static QP::QEvt const t1 = { TEST1_SIG, 0U, 0U }; + QP::QF::PUBLISH(&t1, &BSP::l_test_ISR); QK_ISR_EXIT(); // inform QK about exiting an ISR } @@ -125,7 +125,11 @@ void BSP::init(void) { QS_OBJ_DICTIONARY(&l_test_ISR); QS_USR_DICTIONARY(CONTEXT_SW); - QS_USR_DICTIONARY(COMMAND_STAT); + QS_USR_DICTIONARY(TRACE_MSG); +} +//............................................................................ +void BSP::terminate(int16_t result) { + Q_UNUSED_PAR(result); } //............................................................................ void BSP::ledOn(void) { @@ -140,8 +144,11 @@ void BSP::trigISR(void) { NVIC_SetPendingIRQ(EXTI0_1_IRQn); } //............................................................................ -void BSP::terminate(int16_t result) { - (void)result; +void BSP::trace(QP::QActive const *thr, char const *msg) { + QS_BEGIN_ID(TRACE_MSG, 0U) + QS_OBJ(thr); + QS_STR(msg); + QS_END() } // namespace QP ============================================================== @@ -170,16 +177,6 @@ void QF::onStartup(void) { void QF::onCleanup(void) { } //............................................................................ -#ifdef QK_ON_CONTEXT_SW -// NOTE: the context-switch callback is called with interrupts DISABLED -void QK::onContextSw(QActive *prev, QActive *next) { - QS_BEGIN_NOCRIT(BSP::CONTEXT_SW, 0U) // no critical section! - QS_OBJ(prev); - QS_OBJ(next); - QS_END_NOCRIT() -} -#endif // QK_ON_CONTEXT_SW -//............................................................................ void QK::onIdle(void) { #ifdef Q_SPY QS::rxParse(); // parse all the received bytes @@ -194,7 +191,6 @@ void QK::onIdle(void) { } // QS callbacks ============================================================== -#ifdef Q_SPY //............................................................................ void QTimeEvt::tick1_( uint_fast8_t const tickRate, @@ -206,8 +202,21 @@ void QTimeEvt::tick1_( QF_INT_ENABLE(); } -#endif // Q_SPY //---------------------------------------------------------------------------- } // namespace QP +extern "C" { +//............................................................................ +#ifdef QK_ON_CONTEXT_SW +// NOTE: the context-switch callback is called with interrupts DISABLED +void QK_onContextSw(QP::QActive *prev, QP::QActive *next) { + QS_BEGIN_NOCRIT(BSP::CONTEXT_SW, 0U) // no critical section! + QS_OBJ(prev); + QS_OBJ(next); + QS_END_NOCRIT() +} +#endif // QK_ON_CONTEXT_SW + +} // extern "C" + diff --git a/test/qk/test_pts/make_efm32 b/test/qk/test_sched/make_efm32 similarity index 94% rename from test/qk/test_pts/make_efm32 rename to test/qk/test_sched/make_efm32 index c4387196..7c41ed73 100644 --- a/test/qk/test_pts/make_efm32 +++ b/test/qk/test_sched/make_efm32 @@ -1,7 +1,7 @@ ############################################################################## # Product: Makefile for SYSTEM-Level tests of QP/C++ on EMF32, GNU-ARM -# Last Updated for Version: 7.1.1 -# Date of the Last Update: 2022-09-05 +# Last Updated for Version: 7.1.2 +# Date of the Last Update: 2022-10-05 # # Q u a n t u m L e a P s # ------------------------ @@ -38,6 +38,7 @@ # make -f make_efm32 HOST=localhost:7705 # connect to host:port # make -f make_efm32 norun # only make but not run the tests # make -f make_efm32 clean # cleanup the build +# make -f make_efm32 debug # only run tests in DEBUG mode # # NOTE: # To use this Makefile on Windows, you will need the GNU make utility, which @@ -53,7 +54,7 @@ endif #----------------------------------------------------------------------------- # project name, target name, target directory: # -PROJECT := test_pts +PROJECT := test_sched TARGET := efm32 TARGET_DIR := $(QPCPP)/3rd_party/efm32pg1b/qutest @@ -72,7 +73,6 @@ endif # list of all source directories used by this project VPATH := . \ - ../src \ $(QPCPP)/src/qf \ $(QPCPP)/src/qk \ $(QPCPP)/src/qs \ @@ -83,7 +83,6 @@ VPATH := . \ # list of all include directories needed by this project INCLUDES = -I. \ - -I../src \ -I$(QPCPP)/include \ -I$(QP_PORT_DIR) \ -I$(TARGET_DIR) \ @@ -108,7 +107,7 @@ C_SRCS := \ # C++ source files CPP_SRCS := \ - test_pts.cpp \ + test_sched.cpp \ bsp_efm32.cpp OUTPUT := $(PROJECT) @@ -142,7 +141,8 @@ LIB_DIRS := LIBS := # defines -DEFINES := -DEFM32PG1B200F256GM48=1 +DEFINES := -DEFM32PG1B200F256GM48=1 \ + -DQK_ON_CONTEXT_SW # ARM CPU, ARCH, FPU, and Float-ABI types... # ARM_CPU: [cortex-m0 | cortex-m0plus | cortex-m1 | cortex-m3 | cortex-m4] @@ -247,7 +247,7 @@ endif # rules # -.PHONY : run norun flash +.PHONY : run norun debug flash ifeq ($(MAKECMDGOALS),norun) all : $(TARGET_BIN) @@ -285,15 +285,23 @@ $(BIN_DIR)/%.o : %.c $(BIN_DIR)/%.o : %.cpp $(CPP) $(CPPFLAGS) $< -o $@ -.PHONY : clean show - -# include dependency files only if our goal depends on their existence +# create BIN_DIR and include dependencies only if needed ifneq ($(MAKECMDGOALS),clean) ifneq ($(MAKECMDGOALS),show) + ifneq ($(MAKECMDGOALS),debug) +ifeq ("$(wildcard $(BIN_DIR))","") +$(shell $(MKDIR) $(BIN_DIR)) +endif -include $(C_DEPS_EXT) $(CPP_DEPS_EXT) + endif endif endif +debug : + $(QUTEST) $(TESTS) DEBUG $(HOST) + +.PHONY : clean show + clean : -$(RM) $(BIN_DIR)/*.o \ $(BIN_DIR)/*.d \ diff --git a/test/qk/test_pts/make_nucleo-l053r8 b/test/qk/test_sched/make_nucleo-l053r8 similarity index 94% rename from test/qk/test_pts/make_nucleo-l053r8 rename to test/qk/test_sched/make_nucleo-l053r8 index 7babadd9..236e09a2 100644 --- a/test/qk/test_pts/make_nucleo-l053r8 +++ b/test/qk/test_sched/make_nucleo-l053r8 @@ -1,7 +1,7 @@ ############################################################################## -# Product: Makefile for SYSTEM-Level tests of QP/C++ on NUCLEO-L053R8, GNU-ARM -# Last Updated for Version: 7.1.1 -# Date of the Last Update: 2022-09-05 +# Product: Makefile for SYSTEM-Level tests of QP/C on NUCLEO-L053R8, GNU-ARM +# Last Updated for Version: 7.1.2 +# Date of the Last Update: 2022-10-05 # # Q u a n t u m L e a P s # ------------------------ @@ -38,6 +38,7 @@ # make -f make_nucleo-l053r8 HOST=localhost:7705 # connect to host:port # make -f make_nucleo-l053r8 norun # only make but not run the tests # make -f make_nucleo-l053r8 clean # cleanup the build +# make -f make_nucleo-l053r8 debug # only run tests in DEBUG mode # # NOTE: # To use this Makefile on Windows, you will need the GNU make utility, which @@ -53,7 +54,7 @@ endif #----------------------------------------------------------------------------- # project name, target name, target directory: # -PROJECT := test_pts +PROJECT := test_sched TARGET := nucleo-l053r8 TARGET_DIR := $(QPCPP)/3rd_party/nucleo-l053r8/qutest @@ -72,7 +73,6 @@ endif # list of all source directories used by this project VPATH := . \ - ../src \ $(QPCPP)/src/qf \ $(QPCPP)/src/qk \ $(QPCPP)/src/qs \ @@ -83,7 +83,6 @@ VPATH := . \ # list of all include directories needed by this project INCLUDES = -I. \ - -I../src \ -I$(QPCPP)/include \ -I$(QP_PORT_DIR) \ -I$(TARGET_DIR) \ @@ -104,7 +103,7 @@ C_SRCS := \ # C++ source files CPP_SRCS := \ - test_pts.cpp \ + test_sched.cpp \ bsp_l053r8.cpp OUTPUT := $(PROJECT) @@ -138,7 +137,8 @@ LIB_DIRS := LIBS := # defines -DEFINES := +DEFINES := \ + -DQK_ON_CONTEXT_SW # ARM CPU, ARCH, FPU, and Float-ABI types... # ARM_CPU: [cortex-m0 | cortex-m0plus | cortex-m1 | cortex-m3 | cortex-m4] @@ -247,7 +247,7 @@ endif # rules # -.PHONY : run norun flash +.PHONY : run norun debug flash ifeq ($(MAKECMDGOALS),norun) all : $(TARGET_BIN) @@ -286,15 +286,23 @@ $(BIN_DIR)/%.o : %.c $(BIN_DIR)/%.o : %.cpp $(CPP) $(CPPFLAGS) $< -o $@ -.PHONY : clean show - -# include dependency files only if our goal depends on their existence +# create BIN_DIR and include dependencies only if needed ifneq ($(MAKECMDGOALS),clean) ifneq ($(MAKECMDGOALS),show) + ifneq ($(MAKECMDGOALS),debug) +ifeq ("$(wildcard $(BIN_DIR))","") +$(shell $(MKDIR) $(BIN_DIR)) +endif -include $(C_DEPS_EXT) $(CPP_DEPS_EXT) + endif endif endif +debug : + $(QUTEST) $(TESTS) DEBUG $(HOST) + +.PHONY : clean show + clean : -$(RM) $(BIN_DIR)/*.o \ $(BIN_DIR)/*.d \ @@ -323,6 +331,5 @@ show : @echo QTOOLS = $(QTOOLS) @echo HOST = $(HOST) @echo QUTEST = $(QUTEST) - @echo FLASH = $(FLASH) @echo TESTS = $(TESTS) diff --git a/test/qk/test_pts/test_pts.cpp b/test/qk/test_sched/test_sched.cpp similarity index 54% rename from test/qk/test_pts/test_pts.cpp rename to test/qk/test_sched/test_sched.cpp index a9796228..86affbb4 100644 --- a/test/qk/test_pts/test_pts.cpp +++ b/test/qk/test_sched/test_sched.cpp @@ -1,13 +1,13 @@ //============================================================================ -// System test fixture for QK kernel on the EFM32 target -// Last updated for version 7.1.1 -// Last updated on 2022-09-05 +// Product: System test fixture for QK on the EFM32 target +// Last updated for version 7.1.2 +// Last updated on 2022-10-06 // // Q u a n t u m L e a P s // ------------------------ // Modern Embedded Software // -// Copyright (C) 2005-2020 Quantum Leaps. All rights reserved. +// Copyright (C) 2005 Quantum Leaps. 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 @@ -34,17 +34,18 @@ #include "qpcpp.hpp" #include "bsp.hpp" -namespace { // unnamed namespace - Q_DEFINE_THIS_FILE -enum { NumB = 3 }; +namespace { +//============================================================================ +// AO ObjB +enum { NUM_B = 3 }; //............................................................................ // AO ObjB class ObjB : public QP::QActive { public: - static ObjB inst[NumB]; + static ObjB inst[NUM_B]; public: ObjB() : QActive(&initial) {} @@ -55,28 +56,37 @@ protected: }; // class ObjB Q_STATE_DEF(ObjB, initial) { - for (std::uint8_t n = 0U; n < NumB; ++n) { - QS_OBJ_ARR_DICTIONARY(&ObjB::inst[n], n); + static bool registered = false; // starts off with 0, per C-standard + if (!registered) { + registered = true; + QS_FUN_DICTIONARY(&ObjB::initial); + QS_FUN_DICTIONARY(&ObjB::active); } - QS_FUN_DICTIONARY(&ObjB::initial); - QS_FUN_DICTIONARY(&ObjB::active); - + subscribe(TEST1_SIG); + subscribe(TEST2_SIG); return tran(&active); } Q_STATE_DEF(ObjB, active) { QP::QState status_; switch (e->sig) { - case Q_ENTRY_SIG: { - status_ = Q_RET_HANDLED; - break; - } - case TRIG_SIG: { + case TEST0_SIG: { + BSP::trace(this, "TEST0 1of2"); BSP::trigISR(); + BSP::trace(this, "TEST0 2of2"); status_ = Q_RET_HANDLED; break; } - case TEST_SIG: { + case TEST1_SIG: { + static QP::QEvt const t2 = { TEST2_SIG, 0U, 0U }; + BSP::trace(this, "TEST1 1of2"); + QActive::PUBLISH(&t2, this); + BSP::trace(this, "TEST1 2of2"); + status_ = Q_RET_HANDLED; + break; + } + case TEST2_SIG: { + BSP::trace(this, "TEST2 1of1"); status_ = Q_RET_HANDLED; break; } @@ -87,111 +97,57 @@ Q_STATE_DEF(ObjB, active) { } return status_; } -//............................................................................ -// AO ObjA -class ObjA : public QP::QActive { -public: - static ObjA inst; -public: - ObjA() : QActive(&initial) {} - -protected: - Q_STATE_DECL(initial); - Q_STATE_DECL(active); -}; // class ObjA - -Q_STATE_DEF(ObjA, initial) { - subscribe(TEST_SIG); - - QS_OBJ_DICTIONARY(&ObjA::inst); - QS_FUN_DICTIONARY(&ObjA::initial); - QS_FUN_DICTIONARY(&ObjA::active); - - return tran(&active); -} - -Q_STATE_DEF(ObjA, active) { - QP::QState status_; - switch (e->sig) { - case Q_ENTRY_SIG: { - status_ = Q_RET_HANDLED; - break; - } - case TRIG_SIG: { - BSP::trigISR(); - status_ = Q_RET_HANDLED; - break; - } - case TEST_SIG: { - static QP::QEvt const tste = { TEST_SIG, 0U, 0U }; - BSP::ledOn(); - ObjB::inst[2].POST(&tste, this); - ObjB::inst[1].POST(&tste, this); - ObjB::inst[0].POST(&tste, this); - BSP::ledOff(); - status_ = Q_RET_HANDLED; - break; - } - default: { - status_ = super(&top); - break; - } - } - return status_; -} +ObjB ObjB::inst[NUM_B]; } // unnamed namespace //============================================================================ -ObjB ObjB::inst[NumB]; -ObjA ObjA::inst; - int main() { - QP::QF::init(); // initialize the framework and the underlying QXK kernel + + QP::QF::init(); // initialize the framework and the underlying QXK kernel BSP::init(); // initialize the Board Support Package - // dictionaries - QS_FUN_DICTIONARY(&QP::QHsm::top); - QS_SIG_DICTIONARY(TEST_SIG, nullptr); - QS_SIG_DICTIONARY(TRIG_SIG, nullptr); - - static std::uint16_t pspec[NumB + 1] = { - Q_PRIO(1U, 0U), - Q_PRIO(2U, 0U), - Q_PRIO(3U, 0U), - Q_PRIO(4U, 0U) - }; - QS_OBJ_DICTIONARY(pspec); - // initialize publish-subscribe... static QP::QSubscrList subscrSto[MAX_PUB_SIG]; - QP::QF::psInit(subscrSto, Q_DIM(subscrSto)); + QP::QActive::psInit(subscrSto, Q_DIM(subscrSto)); // initialize event pools... static QF_MPOOL_EL(QP::QEvt) smlPoolSto[10]; // small pool QP::QF::poolInit(smlPoolSto, sizeof(smlPoolSto), sizeof(smlPoolSto[0])); - // pause execution of the test and wait for the test script to continue - QS_TEST_PAUSE(); + // dictionaries + QS_SIG_DICTIONARY(TEST0_SIG, nullptr); + QS_SIG_DICTIONARY(TEST1_SIG, nullptr); + QS_SIG_DICTIONARY(TEST2_SIG, nullptr); + QS_SIG_DICTIONARY(TEST3_SIG, nullptr); - static QP::QEvt const *aoB_queueSto[NumB][5]; - for (std::uint8_t n = 0U; n < NumB; ++n) { - ObjB::inst[n].start( - pspec[n], // QP priority spec - aoB_queueSto[n], // event queue storage - Q_DIM(aoB_queueSto[n]), // event length [events] - nullptr, // no stack storage - 0U); // zero stack size [bytes] + // priority specifications for ObjBs... + static QP::QPrioSpec pspecB[NUM_B]; + QS_OBJ_DICTIONARY(pspecB); + + std::uint8_t n; + + for (n = 0U; n < NUM_B; ++n) { + QS_OBJ_ARR_DICTIONARY(&ObjB::inst[n], n); } - static QP::QEvt const *aoA_queueSto[5]; - ObjA::inst.start( - pspec[NumB], // QP priority spec - aoA_queueSto, // event queue storage - Q_DIM(aoA_queueSto), // event length [events] - nullptr, // no stack storage - 0U); // zero stack size [bytes] + // pause execution of the test and wait for the test script to continue + // NOTE: + // this pause gives the test-script a chance to poke pspecB and pspecX + // variables to start the threads with the desired prio-specifications. + QS_TEST_PAUSE(); + + static QP::QEvt const *aoB_queueSto[NUM_B][5]; + for (n = 0U; n < NUM_B; ++n) { + if (pspecB[n] != 0U) { + ObjB::inst[n].start(pspecB[n], // QF-prio/p-thre. + aoB_queueSto[n], // event queue storage + Q_DIM(aoB_queueSto[n]), // event length [events] + nullptr, // no stack storage + 0U); // zero stack size [bytes] + } + } return QP::QF::run(); // run the QF application } @@ -199,7 +155,6 @@ int main() { //============================================================================ namespace QP { -//............................................................................ void QS::onTestSetup(void) { } //............................................................................ @@ -215,18 +170,16 @@ void QS::onCommand(uint8_t cmdId, Q_UNUSED_PAR(param2); Q_UNUSED_PAR(param3); } -//............................................................................ + +//============================================================================ //! Host callback function to "massage" the event, if necessary void QS::onTestEvt(QEvt *e) { - Q_UNUSED_PAR(e); + (void)e; } //............................................................................ //! callback function to output the posted QP events (not used here) void QS::onTestPost(void const *sender, QActive *recipient, QEvt const *e, bool status) -{ - Q_UNUSED_PAR(sender); - Q_UNUSED_PAR(status); -} +{} } // namespace QP diff --git a/test/qk/test_sched/test_sched.py b/test/qk/test_sched/test_sched.py new file mode 100644 index 00000000..31e7c48f --- /dev/null +++ b/test/qk/test_sched/test_sched.py @@ -0,0 +1,173 @@ +# test-script for QUTest unit testing harness +# see https://www.state-machine.com/qtools/qutest.html/qutest.html + +# preamble +def on_reset(): + expect_pause() + +def Q_PRIO(prio, pthre): + return prio | (pthre << 8) + +test("ao->ao->ao (NO PTS)") +current_obj(OBJ_AP, "pspecB") +poke(0, 2, pack("2") +expect("@timestamp CONTEXT_SW NULL ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST0 1of2") +expect("@timestamp Sch-Next Pri=2->3") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[2]") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->3") +expect("@timestamp Sch-Unlk Ceil=3->0") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST1 2of2") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST2 1of1") +expect("@timestamp Sch-Next Pri=3->2") +expect("@timestamp CONTEXT_SW ObjB::inst[2] ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST0 2of2") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->3") +expect("@timestamp Sch-Unlk Ceil=3->0") +expect("@timestamp Sch-Next Pri=2->3") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[2]") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST2 1of1") +expect("@timestamp Sch-Next Pri=3->2") +expect("@timestamp CONTEXT_SW ObjB::inst[2] ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST1 2of2") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST2 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST2 1of1") +expect("@timestamp Sch-Next Pri=2->1") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[0]") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->3") +expect("@timestamp Sch-Unlk Ceil=3->0") +expect("@timestamp Sch-Next Pri=1->3") +expect("@timestamp CONTEXT_SW ObjB::inst[0] ObjB::inst[2]") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST2 1of1") +expect("@timestamp Sch-Next Pri=3->2") +expect("@timestamp CONTEXT_SW ObjB::inst[2] ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST2 1of1") +expect("@timestamp Sch-Next Pri=2->1") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[0]") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST1 2of2") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp Sch-Idle Pri=1->0") +expect("@timestamp CONTEXT_SW ObjB::inst[0] NULL") +expect("@timestamp Trg-Done QS_RX_EVENT") + + +test("ao->ao->ao (PTS1)") +current_obj(OBJ_AP, "pspecB") +poke(0, 2, pack("2") +expect("@timestamp CONTEXT_SW NULL ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST0 1of2") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST0 2of2") +expect("@timestamp Sch-Next Pri=2->3") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[2]") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->3") +expect("@timestamp Sch-Unlk Ceil=3->0") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST1 2of2") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST2 1of1") +expect("@timestamp Sch-Next Pri=3->2") +expect("@timestamp CONTEXT_SW ObjB::inst[2] ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->3") +expect("@timestamp Sch-Unlk Ceil=3->0") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST1 2of2") +expect("@timestamp Sch-Next Pri=2->3") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[2]") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST2 1of1") +expect("@timestamp Sch-Next Pri=3->2") +expect("@timestamp CONTEXT_SW ObjB::inst[2] ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST2 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST2 1of1") +expect("@timestamp Sch-Next Pri=2->1") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[0]") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->3") +expect("@timestamp Sch-Unlk Ceil=3->0") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST1 2of2") +expect("@timestamp Sch-Next Pri=1->3") +expect("@timestamp CONTEXT_SW ObjB::inst[0] ObjB::inst[2]") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST2 1of1") +expect("@timestamp Sch-Next Pri=3->2") +expect("@timestamp CONTEXT_SW ObjB::inst[2] ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST2 1of1") +expect("@timestamp Sch-Next Pri=2->1") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[0]") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp Sch-Idle Pri=1->0") +expect("@timestamp CONTEXT_SW ObjB::inst[0] NULL") +expect("@timestamp Trg-Done QS_RX_EVENT") + + +test("ao->ao->ao (PTS2)") +current_obj(OBJ_AP, "pspecB") +poke(0, 2, pack("2") +expect("@timestamp CONTEXT_SW NULL ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST0 1of2") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST0 2of2") +expect("@timestamp Sch-Next Pri=2->3") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[2]") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->3") +expect("@timestamp Sch-Unlk Ceil=3->0") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST1 2of2") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST2 1of1") +expect("@timestamp Sch-Next Pri=3->2") +expect("@timestamp CONTEXT_SW ObjB::inst[2] ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->3") +expect("@timestamp Sch-Unlk Ceil=3->0") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST1 2of2") +expect("@timestamp Sch-Next Pri=2->3") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[2]") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST2 1of1") +expect("@timestamp Sch-Next Pri=3->2") +expect("@timestamp CONTEXT_SW ObjB::inst[2] ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST2 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST2 1of1") +expect("@timestamp Sch-Next Pri=2->1") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[0]") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->3") +expect("@timestamp Sch-Unlk Ceil=3->0") +expect("@timestamp Sch-Next Pri=1->3") +expect("@timestamp CONTEXT_SW ObjB::inst[0] ObjB::inst[2]") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST2 1of1") +expect("@timestamp Sch-Next Pri=3->2") +expect("@timestamp CONTEXT_SW ObjB::inst[2] ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST2 1of1") +expect("@timestamp Sch-Next Pri=2->1") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[0]") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST1 2of2") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp Sch-Idle Pri=1->0") +expect("@timestamp CONTEXT_SW ObjB::inst[0] NULL") +expect("@timestamp Trg-Done QS_RX_EVENT") diff --git a/test/qk/test_sched/uvision_efm32.uvoptx b/test/qk/test_sched/uvision_efm32.uvoptx new file mode 100644 index 00000000..9bb06f26 --- /dev/null +++ b/test/qk/test_sched/uvision_efm32.uvoptx @@ -0,0 +1,754 @@ + + + + 1.0 + +
### uVision Project, (C) Keil Software
+ + + *.c + *.s*; *.src; *.a* + *.obj; *.o + *.lib + *.txt; *.h; *.inc; *.md + *.plm + *.cpp + 0 + + + + 0 + 0 + + + + qutest + 0x4 + ARM-ADS + + 12000000 + + 1 + 1 + 1 + 0 + 0 + + + 1 + 65535 + 0 + 0 + 0 + + + 79 + 66 + 8 + .\uvision_emf32\ + + + 1 + 1 + 1 + 0 + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 0 + + + 1 + 0 + 1 + + 3 + + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 0 + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 4 + + + + + + + + + + + Segger\JL2CM3.dll + + + + 0 + DLGUARM + + + + 0 + JL2CM3 + -U440060969 -O206 -S2 -ZTIFSpeedSel5000 -A0 -C0 -JU1 -JI127.0.0.1 -JP0 -RST0 -N00("ARM CoreSight SW-DP") -D00(2BA01477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -TB1 -TFE0 -FO7 -FD20000000 -FC8000 -FN1 -FF0GECKOP2.FLM -FS00 -FL020000 -FP0($$Device:EFM32PG1B200F256GM48$Flash\GECKOP2.FLM) + + + 0 + ARMRTXEVENTFLAGS + -L70 -Z18 -C0 -M0 -T1 + + + 0 + UL2CM3 + UL2CM3(-O207 -S0 -C0 -FO7 -FN1 -FC8000 -FD20000000 -FF0GECKOP2 -FL020000 -FS00 -FP0($$Device:EFM32PG1B200F256GM48$Flash\GECKOP2.FLM) + + + 0 + DLGTARM + (1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)(1012=-1,-1,-1,-1,0) + + + 0 + ARMDBGFLAGS + + + + 0 + lmidk-agdi + -U0E2006F4 -O4622 -S4 -FO61 + + + + + 0 + 0 + 112 + 1 +
25212
+ 0 + 0 + 0 + 0 + 0 + 1 + ..\..\..\src\qs\qutest.c + + \\test\../../../src/qs/qutest.c\112 +
+ + 1 + 0 + 142 + 1 +
136
+ 0 + 0 + 0 + 0 + 0 + 1 + ..\..\..\src\qs\qs.c + + \\test\../../../src/qs/qs.c\142 +
+ + 2 + 0 + 180 + 1 +
27402
+ 0 + 0 + 0 + 0 + 0 + 1 + .\test_pts.c + + \\test\test_pts.c\180 +
+
+ + + 0 + 1 + QF_readySet_ + + + 1 + 1 + QK_attr_ + + + 2 + 1 + QActive_registry_ + + + 3 + 1 + QS_rxPriv_ + + + 4 + 1 + pspec + + + + + 1 + 2 + 0x20000200 + 0 + + + + + 2 + 0 + 0x400 + 0 + + + + 0 + + + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + 0 + 0 + 0 + + + + + + + + +
+
+ + + Applicatioin + 1 + 0 + 0 + 0 + + 1 + 1 + 5 + 0 + 0 + 0 + .\bsp.h + bsp.h + 0 + 0 + + + 1 + 2 + 1 + 0 + 0 + 0 + .\bsp_efm32.c + bsp_efm32.c + 0 + 0 + + + 1 + 3 + 1 + 0 + 0 + 0 + .\test_pts.c + test_pts.c + 0 + 0 + + + + + efm32pg1b + 1 + 0 + 0 + 0 + + 2 + 4 + 2 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\arm\startup_efm32pg1b.s + startup_efm32pg1b.s + 0 + 0 + + + 2 + 5 + 1 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\em_cmu.c + em_cmu.c + 0 + 0 + + + 2 + 6 + 1 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\em_emu.c + em_emu.c + 0 + 0 + + + 2 + 7 + 1 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\em_gpio.c + em_gpio.c + 0 + 0 + + + 2 + 8 + 1 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\system_efm32pg1b.c + system_efm32pg1b.c + 0 + 0 + + + 2 + 9 + 1 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\em_system.c + em_system.c + 0 + 0 + + + 2 + 10 + 1 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\em_usart.c + em_usart.c + 0 + 0 + + + + + QP + 1 + 0 + 0 + 0 + + 3 + 11 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qep_hsm.c + qep_hsm.c + 0 + 0 + + + 3 + 12 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qep_msm.c + qep_msm.c + 0 + 0 + + + 3 + 13 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_act.c + qf_act.c + 0 + 0 + + + 3 + 14 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_actq.c + qf_actq.c + 0 + 0 + + + 3 + 15 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_defer.c + qf_defer.c + 0 + 0 + + + 3 + 16 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_dyn.c + qf_dyn.c + 0 + 0 + + + 3 + 17 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_mem.c + qf_mem.c + 0 + 0 + + + 3 + 18 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_ps.c + qf_ps.c + 0 + 0 + + + 3 + 19 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_qact.c + qf_qact.c + 0 + 0 + + + 3 + 20 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_qeq.c + qf_qeq.c + 0 + 0 + + + 3 + 21 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_qmact.c + qf_qmact.c + 0 + 0 + + + 3 + 22 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_time.c + qf_time.c + 0 + 0 + + + 3 + 23 + 1 + 0 + 0 + 0 + ..\..\..\include\qstamp.c + qstamp.c + 0 + 0 + + + 3 + 24 + 1 + 0 + 0 + 0 + ..\..\..\src\qk\qk.c + qk.c + 0 + 0 + + + + + QP_port + 1 + 0 + 0 + 0 + + 4 + 25 + 5 + 0 + 0 + 0 + ..\..\..\ports\arm-cm\qxk\armclang\qep_port.h + qep_port.h + 0 + 0 + + + 4 + 26 + 5 + 0 + 0 + 0 + ..\..\..\ports\arm-cm\qxk\armclang\qf_port.h + qf_port.h + 0 + 0 + + + 4 + 27 + 5 + 0 + 0 + 0 + ..\..\..\ports\arm-cm\qk\armclang\qk_port.h + qk_port.h + 0 + 0 + + + 4 + 28 + 1 + 0 + 0 + 0 + ..\..\..\ports\arm-cm\qk\armclang\qk_port.c + qk_port.c + 0 + 0 + + + 4 + 29 + 5 + 0 + 0 + 0 + ..\..\..\ports\arm-cm\qxk\armclang\qs_port.h + qs_port.h + 0 + 0 + + + 4 + 30 + 1 + 0 + 0 + 0 + ..\..\..\3rd_party\efm32pg1b\qutest\qutest_port.c + qutest_port.c + 0 + 0 + + + + + QS + 1 + 0 + 0 + 0 + + 5 + 31 + 1 + 0 + 0 + 0 + ..\..\..\src\qs\qs.c + qs.c + 0 + 0 + + + 5 + 32 + 1 + 0 + 0 + 0 + ..\..\..\src\qs\qs_64bit.c + qs_64bit.c + 0 + 0 + + + 5 + 33 + 1 + 0 + 0 + 0 + ..\..\..\src\qs\qs_fp.c + qs_fp.c + 0 + 0 + + + 5 + 34 + 1 + 0 + 0 + 0 + ..\..\..\src\qs\qs_rx.c + qs_rx.c + 0 + 0 + + + 5 + 35 + 1 + 0 + 0 + 0 + ..\..\..\src\qs\qutest.c + qutest.c + 0 + 0 + + + +
diff --git a/test/qk/test_sched/uvision_efm32.uvprojx b/test/qk/test_sched/uvision_efm32.uvprojx new file mode 100644 index 00000000..65e7f24b --- /dev/null +++ b/test/qk/test_sched/uvision_efm32.uvprojx @@ -0,0 +1,602 @@ + + + + 2.1 + +
### uVision Project, (C) Keil Software
+ + + + qutest + 0x4 + ARM-ADS + 6160000::V6.16::ARMCLANG + 1 + + + EFM32PG1B200F256GM48 + Silicon Labs + SiliconLabs.GeckoPlatform_EFM32PG1B_DFP.4.0.0 + https://www.silabs.com/documents/public/cmsis-packs/ + IRAM(0x20000000,0x00008000) IROM(0x00000000,0x00020000) CPUTYPE("Cortex-M4") FPU2 CLOCK(12000000) ELITTLE + + + UL2CM3(-S0 -C0 -P0 -FD20000000 -FC8000 -FN1 -FF0GECKOP2 -FS00 -FL020000 -FP0($$Device:EFM32PG1B200F256GM48$Flash\GECKOP2.FLM)) + 0 + $$Device:EFM32PG1B200F256GM48$Device\EFM32PG1B\Include\em_device.h + + + + + + + + + + $$Device:EFM32PG1B200F256GM48$SVD\EFM32PG1B\EFM32PG1B200F256GM48.svd + 0 + 0 + + + + + + + 0 + 0 + 0 + 0 + 1 + + .\uvision_emf32\ + test + 1 + 0 + 0 + 1 + 1 + .\uvision_emf32\ + 1 + 0 + 0 + + 0 + 0 + + + 0 + 0 + 0 + 0 + + + 1 + 0 + cmd /c "del .\uvision_em32\qstamp.o" + + 0 + 0 + 0 + 0 + + + 1 + 0 + fromelf --bin --output .\uvision_em32\test.bin .\uvision_em32\test.axf + + 0 + 0 + 0 + 0 + + 1 + + + + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 3 + + + 1 + + + SARMCM3.DLL + -MPU + DCM.DLL + -pCM4 + SARMCM3.DLL + -MPU + TCM.DLL + -pCM4 + + + + 1 + 0 + 0 + 0 + 16 + + + + + 1 + 0 + 0 + 1 + 1 + 4096 + + 1 + BIN\UL2CM3.DLL + "" () + + + + + 0 + + + + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 0 + "Cortex-M4" + + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 8 + 0 + 0 + 0 + 0 + 3 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x20000000 + 0x8000 + + + 1 + 0x0 + 0x20000 + + + 0 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x20000 + + + 1 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x20000000 + 0x8000 + + + 0 + 0x0 + 0x0 + + + + + + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 1 + 1 + 0 + 0 + 3 + 3 + 0 + 0 + 0 + 0 + 0 + + + Q_SPY, Q_UTEST=0 + + .;..\..\..\include;..\..\..\ports\arm-cm\qk\armclang;..\..\..\..\3rd_party\CMSIS\Include;..\..\..\..\3rd_party\efm32pg1b + + + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 4 + + + Stack_Size=2048 Heap_Size=16 + + + + + + 1 + 0 + 0 + 0 + 1 + 0 + 0x00000000 + 0x20000000 + + + + + --entry Reset_Handler + + + + + + + + Applicatioin + + + bsp.h + 5 + .\bsp.h + + + bsp_efm32.c + 1 + .\bsp_efm32.c + + + test_pts.c + 1 + .\test_pts.c + + + + + efm32pg1b + + + startup_efm32pg1b.s + 2 + ..\..\..\..\3rd_party\efm32pg1b\arm\startup_efm32pg1b.s + + + em_cmu.c + 1 + ..\..\..\..\3rd_party\efm32pg1b\em_cmu.c + + + em_emu.c + 1 + ..\..\..\..\3rd_party\efm32pg1b\em_emu.c + + + em_gpio.c + 1 + ..\..\..\..\3rd_party\efm32pg1b\em_gpio.c + + + system_efm32pg1b.c + 1 + ..\..\..\..\3rd_party\efm32pg1b\system_efm32pg1b.c + + + em_system.c + 1 + ..\..\..\..\3rd_party\efm32pg1b\em_system.c + + + em_usart.c + 1 + ..\..\..\..\3rd_party\efm32pg1b\em_usart.c + + + + + QP + + + qep_hsm.c + 1 + ..\..\..\src\qf\qep_hsm.c + + + qep_msm.c + 1 + ..\..\..\src\qf\qep_msm.c + + + qf_act.c + 1 + ..\..\..\src\qf\qf_act.c + + + qf_actq.c + 1 + ..\..\..\src\qf\qf_actq.c + + + qf_defer.c + 1 + ..\..\..\src\qf\qf_defer.c + + + qf_dyn.c + 1 + ..\..\..\src\qf\qf_dyn.c + + + qf_mem.c + 1 + ..\..\..\src\qf\qf_mem.c + + + qf_ps.c + 1 + ..\..\..\src\qf\qf_ps.c + + + qf_qact.c + 1 + ..\..\..\src\qf\qf_qact.c + + + qf_qeq.c + 1 + ..\..\..\src\qf\qf_qeq.c + + + qf_qmact.c + 1 + ..\..\..\src\qf\qf_qmact.c + + + qf_time.c + 1 + ..\..\..\src\qf\qf_time.c + + + qstamp.c + 1 + ..\..\..\include\qstamp.c + + + qk.c + 1 + ..\..\..\src\qk\qk.c + + + + + QP_port + + + qep_port.h + 5 + ..\..\..\ports\arm-cm\qxk\armclang\qep_port.h + + + qf_port.h + 5 + ..\..\..\ports\arm-cm\qxk\armclang\qf_port.h + + + qk_port.h + 5 + ..\..\..\ports\arm-cm\qk\armclang\qk_port.h + + + qk_port.c + 1 + ..\..\..\ports\arm-cm\qk\armclang\qk_port.c + + + qs_port.h + 5 + ..\..\..\ports\arm-cm\qxk\armclang\qs_port.h + + + qutest_port.c + 1 + ..\..\..\3rd_party\efm32pg1b\qutest\qutest_port.c + + + + + QS + + + qs.c + 1 + ..\..\..\src\qs\qs.c + + + qs_64bit.c + 1 + ..\..\..\src\qs\qs_64bit.c + + + qs_fp.c + 1 + ..\..\..\src\qs\qs_fp.c + + + qs_rx.c + 1 + ..\..\..\src\qs\qs_rx.c + + + qutest.c + 1 + ..\..\..\src\qs\qutest.c + + + + + + + + + + + + + + + + + test + 1 + + + + +
diff --git a/test/qxk/src/bsp.hpp b/test/qxk/test_sched/bsp.hpp similarity index 90% rename from test/qxk/src/bsp.hpp rename to test/qxk/test_sched/bsp.hpp index a6926e59..dab38994 100644 --- a/test/qxk/src/bsp.hpp +++ b/test/qxk/test_sched/bsp.hpp @@ -1,7 +1,7 @@ //============================================================================ // Product: BSP for system-testing QXK -// Last updated for version 7.1.1 -// Last updated on 2022-09-04 +// Last updated for version 7.1.2 +// Last updated on 2022-10-06 // // Q u a n t u m L e a P s // ------------------------ @@ -36,12 +36,11 @@ namespace BSP { -enum { TICKS_PER_SEC = 100 }; - void init(void); void terminate(int16_t const result); // for testing... +void trace(QP::QActive const *thr, char const *msg); void wait4PB1(void); void ledOn(void); void ledOff(void); @@ -50,11 +49,12 @@ void trigISR(void); } // namespace BSP enum TestSignals { - TEST_SIG = QP::Q_USER_SIG, + TEST0_SIG = QP::Q_USER_SIG, + TEST1_SIG, + TEST2_SIG, + TEST3_SIG, MAX_PUB_SIG, // the last published signal - TIMEOUT_SIG, - TRIG_SIG, MAX_SIG // the last signal }; diff --git a/test/qxk/src/bsp_efm32.cpp b/test/qxk/test_sched/bsp_efm32.cpp similarity index 92% rename from test/qxk/src/bsp_efm32.cpp rename to test/qxk/test_sched/bsp_efm32.cpp index d36f7faa..3f354958 100644 --- a/test/qxk/src/bsp_efm32.cpp +++ b/test/qxk/test_sched/bsp_efm32.cpp @@ -1,7 +1,7 @@ //============================================================================ // Product: BSP for system-testing QXK, EFM32-SLSTK3401A board -// Last updated for version 7.1.1 -// Last updated on 2022-09-04 +// Last updated for version 7.1.2 +// Last updated on 2022-10-06 // // Q u a n t u m L e a P s // ------------------------ @@ -60,11 +60,9 @@ namespace BSP { static QP::QSpyId const l_SysTick_Handler = { 0U }; static QP::QSpyId const l_test_ISR = { 0U }; - static USART_TypeDef * const l_USART0 = ((USART_TypeDef *)(0x40010000UL)); - enum AppRecords { // application-specific trace records CONTEXT_SW = QP::QS_USER, - COMMAND_STAT + TRACE_MSG }; #endif @@ -90,8 +88,8 @@ void GPIO_EVEN_IRQHandler(void) { QXK_ISR_ENTRY(); // inform QXK about entering an ISR // for testing... - QP::QF::PUBLISH(Q_NEW(QP::QEvt, TEST_SIG), // for testing... - &BSP::l_test_ISR); + static QP::QEvt const t1 = { TEST1_SIG, 0U, 0U }; + QP::QF::PUBLISH(&t1, &BSP::l_test_ISR); QXK_ISR_EXIT(); // inform QXK about exiting an ISR } @@ -130,7 +128,11 @@ void BSP::init(void) { QS_OBJ_DICTIONARY(&l_test_ISR); QS_USR_DICTIONARY(CONTEXT_SW); - QS_USR_DICTIONARY(COMMAND_STAT); + QS_USR_DICTIONARY(TRACE_MSG); +} +//............................................................................ +void BSP::terminate(int16_t result) { + Q_UNUSED_PAR(result); } //............................................................................ void BSP::ledOn(void) { @@ -145,8 +147,11 @@ void BSP::trigISR(void) { NVIC_SetPendingIRQ(GPIO_EVEN_IRQn); } //............................................................................ -void BSP::terminate(int16_t result) { - (void)result; +void BSP::trace(QP::QActive const *thr, char const *msg) { + QS_BEGIN_ID(TRACE_MSG, 0U) + QS_OBJ(thr); + QS_STR(msg); + QS_END() } // namespace QP ============================================================== @@ -175,16 +180,6 @@ void QF::onStartup(void) { void QF::onCleanup(void) { } //............................................................................ -#ifdef QXK_ON_CONTEXT_SW -// NOTE: the context-switch callback is called with interrupts DISABLED -void QXK::onContextSw(QActive *prev, QActive *next) { - QS_BEGIN_NOCRIT(BSP::CONTEXT_SW, 0U) // no critical section! - QS_OBJ(prev); - QS_OBJ(next); - QS_END_NOCRIT() -} -#endif // QXK_ON_CONTEXT_SW -//............................................................................ void QXK::onIdle(void) { #ifdef Q_SPY QS::rxParse(); // parse all the received bytes @@ -199,7 +194,6 @@ void QXK::onIdle(void) { } // QS callbacks ============================================================== -#ifdef Q_SPY //............................................................................ void QTimeEvt::tick1_( uint_fast8_t const tickRate, @@ -211,8 +205,21 @@ void QTimeEvt::tick1_( QF_INT_ENABLE(); } -#endif // Q_SPY //---------------------------------------------------------------------------- } // namespace QP +extern "C" { +//............................................................................ +#ifdef QXK_ON_CONTEXT_SW +// NOTE: the context-switch callback is called with interrupts DISABLED +void QXK_onContextSw(QP::QActive *prev, QP::QActive *next) { + QS_BEGIN_NOCRIT(BSP::CONTEXT_SW, 0U) // no critical section! + QS_OBJ(prev); + QS_OBJ(next); + QS_END_NOCRIT() +} +#endif // QXK_ON_CONTEXT_SW + +} // extern "C" + diff --git a/test/qxk/src/bsp_l053r8.cpp b/test/qxk/test_sched/bsp_l053r8.cpp similarity index 92% rename from test/qxk/src/bsp_l053r8.cpp rename to test/qxk/test_sched/bsp_l053r8.cpp index 6ed640ba..0475c8a4 100644 --- a/test/qxk/src/bsp_l053r8.cpp +++ b/test/qxk/test_sched/bsp_l053r8.cpp @@ -1,7 +1,7 @@ //============================================================================ // Product: BSP for system-testing QXK kernel, NUCLEO-L053R8 board -// Last updated for version 7.1.1 -// Last updated on 2022-09-04 +// Last updated for version 7.1.2 +// Last updated on 2022-10-06 // // Q u a n t u m L e a P s // ------------------------ @@ -57,7 +57,7 @@ namespace BSP { enum AppRecords { // application-specific trace records CONTEXT_SW = QP::QS_USER, - COMMAND_STAT + TRACE_MSG }; #endif @@ -83,8 +83,8 @@ void EXTI0_1_IRQHandler(void) { QXK_ISR_ENTRY(); // inform QXK about entering an ISR // for testing... - QP::QF::PUBLISH(Q_NEW(QP::QEvt, TEST_SIG), // for testing... - &BSP::l_test_ISR); + static QP::QEvt const t1 = { TEST1_SIG, 0U, 0U }; + QP::QF::PUBLISH(&t1, &BSP::l_test_ISR); QXK_ISR_EXIT(); // inform QXK about exiting an ISR } @@ -125,7 +125,11 @@ void BSP::init(void) { QS_OBJ_DICTIONARY(&l_test_ISR); QS_USR_DICTIONARY(CONTEXT_SW); - QS_USR_DICTIONARY(COMMAND_STAT); + QS_USR_DICTIONARY(TRACE_MSG); +} +//............................................................................ +void BSP::terminate(int16_t result) { + Q_UNUSED_PAR(result); } //............................................................................ void BSP::ledOn(void) { @@ -140,8 +144,11 @@ void BSP::trigISR(void) { NVIC_SetPendingIRQ(EXTI0_1_IRQn); } //............................................................................ -void BSP::terminate(int16_t result) { - (void)result; +void BSP::trace(QP::QActive const *thr, char const *msg) { + QS_BEGIN_ID(TRACE_MSG, 0U) + QS_OBJ(thr); + QS_STR(msg); + QS_END() } // namespace QP ============================================================== @@ -170,16 +177,6 @@ void QF::onStartup(void) { void QF::onCleanup(void) { } //............................................................................ -#ifdef QXK_ON_CONTEXT_SW -// NOTE: the context-switch callback is called with interrupts DISABLED -void QXK::onContextSw(QActive *prev, QActive *next) { - QS_BEGIN_NOCRIT(BSP::CONTEXT_SW, 0U) // no critical section! - QS_OBJ(prev); - QS_OBJ(next); - QS_END_NOCRIT() -} -#endif // QXK_ON_CONTEXT_SW -//............................................................................ void QXK::onIdle(void) { #ifdef Q_SPY QS::rxParse(); // parse all the received bytes @@ -194,7 +191,6 @@ void QXK::onIdle(void) { } // QS callbacks ============================================================== -#ifdef Q_SPY //............................................................................ void QTimeEvt::tick1_( uint_fast8_t const tickRate, @@ -206,8 +202,21 @@ void QTimeEvt::tick1_( QF_INT_ENABLE(); } -#endif // Q_SPY //---------------------------------------------------------------------------- } // namespace QP +extern "C" { +//............................................................................ +#ifdef QXK_ON_CONTEXT_SW +// NOTE: the context-switch callback is called with interrupts DISABLED +void QXK_onContextSw(QP::QActive *prev, QP::QActive *next) { + QS_BEGIN_NOCRIT(BSP::CONTEXT_SW, 0U) // no critical section! + QS_OBJ(prev); + QS_OBJ(next); + QS_END_NOCRIT() +} +#endif // QXK_ON_CONTEXT_SW + +} // extern "C" + diff --git a/test/qxk/test_xthr/make_efm32 b/test/qxk/test_sched/make_efm32 similarity index 94% rename from test/qxk/test_xthr/make_efm32 rename to test/qxk/test_sched/make_efm32 index ae802155..4f810e9b 100644 --- a/test/qxk/test_xthr/make_efm32 +++ b/test/qxk/test_sched/make_efm32 @@ -1,7 +1,7 @@ ############################################################################## # Product: Makefile for SYSTEM-Level tests of QP/C++ on EMF32, GNU-ARM -# Last Updated for Version: 7.1.1 -# Date of the Last Update: 2022-09-05 +# Last Updated for Version: 7.1.2 +# Date of the Last Update: 2022-10-05 # # Q u a n t u m L e a P s # ------------------------ @@ -38,6 +38,7 @@ # make -f make_efm32 HOST=localhost:7705 # connect to host:port # make -f make_efm32 norun # only make but not run the tests # make -f make_efm32 clean # cleanup the build +# make -f make_efm32 debug # only run tests in DEBUG mode # # NOTE: # To use this Makefile on Windows, you will need the GNU make utility, which @@ -53,7 +54,7 @@ endif #----------------------------------------------------------------------------- # project name, target name, target directory: # -PROJECT := test_xthr +PROJECT := test_sched TARGET := efm32 TARGET_DIR := $(QPCPP)/3rd_party/efm32pg1b/qutest @@ -72,7 +73,6 @@ endif # list of all source directories used by this project VPATH := . \ - ../src \ $(QPCPP)/src/qf \ $(QPCPP)/src/qxk \ $(QPCPP)/src/qs \ @@ -83,7 +83,6 @@ VPATH := . \ # list of all include directories needed by this project INCLUDES = -I. \ - -I../src \ -I$(QPCPP)/include \ -I$(QP_PORT_DIR) \ -I$(TARGET_DIR) \ @@ -108,7 +107,7 @@ C_SRCS := \ # C++ source files CPP_SRCS := \ - test_xthr.cpp \ + test_sched.cpp \ bsp_efm32.cpp OUTPUT := $(PROJECT) @@ -145,7 +144,8 @@ LIB_DIRS := LIBS := # defines -DEFINES := -DEFM32PG1B200F256GM48=1 +DEFINES := -DEFM32PG1B200F256GM48=1 \ + -DQXK_ON_CONTEXT_SW # ARM CPU, ARCH, FPU, and Float-ABI types... # ARM_CPU: [cortex-m0 | cortex-m0plus | cortex-m1 | cortex-m3 | cortex-m4] @@ -250,7 +250,7 @@ endif # rules # -.PHONY : run norun flash +.PHONY : run norun debug flash ifeq ($(MAKECMDGOALS),norun) all : $(TARGET_BIN) @@ -288,15 +288,23 @@ $(BIN_DIR)/%.o : %.c $(BIN_DIR)/%.o : %.cpp $(CPP) $(CPPFLAGS) $< -o $@ -.PHONY : clean show - -# include dependency files only if our goal depends on their existence +# create BIN_DIR and include dependencies only if needed ifneq ($(MAKECMDGOALS),clean) ifneq ($(MAKECMDGOALS),show) + ifneq ($(MAKECMDGOALS),debug) +ifeq ("$(wildcard $(BIN_DIR))","") +$(shell $(MKDIR) $(BIN_DIR)) +endif -include $(C_DEPS_EXT) $(CPP_DEPS_EXT) + endif endif endif +debug : + $(QUTEST) $(TESTS) DEBUG $(HOST) + +.PHONY : clean show + clean : -$(RM) $(BIN_DIR)/*.o \ $(BIN_DIR)/*.d \ diff --git a/test/qxk/test_xthr/make_nucleo-l053r8 b/test/qxk/test_sched/make_nucleo-l053r8 similarity index 94% rename from test/qxk/test_xthr/make_nucleo-l053r8 rename to test/qxk/test_sched/make_nucleo-l053r8 index 6bb3d797..364dacb3 100644 --- a/test/qxk/test_xthr/make_nucleo-l053r8 +++ b/test/qxk/test_sched/make_nucleo-l053r8 @@ -1,7 +1,7 @@ ############################################################################## -# Product: Makefile for SYSTEM-Level tests of QP/C++ on NUCLEO-L053R8, GNU-ARM -# Last Updated for Version: 7.1.1 -# Date of the Last Update: 2022-09-05 +# Product: Makefile for SYSTEM-Level tests of QP/C on NUCLEO-L053R8, GNU-ARM +# Last Updated for Version: 7.1.2 +# Date of the Last Update: 2022-10-05 # # Q u a n t u m L e a P s # ------------------------ @@ -38,6 +38,7 @@ # make -f make_nucleo-l053r8 HOST=localhost:7705 # connect to host:port # make -f make_nucleo-l053r8 norun # only make but not run the tests # make -f make_nucleo-l053r8 clean # cleanup the build +# make -f make_nucleo-l053r8 debug # only run tests in DEBUG mode # # NOTE: # To use this Makefile on Windows, you will need the GNU make utility, which @@ -53,7 +54,7 @@ endif #----------------------------------------------------------------------------- # project name, target name, target directory: # -PROJECT := test_xthr +PROJECT := test_sched TARGET := nucleo-l053r8 TARGET_DIR := $(QPCPP)/3rd_party/nucleo-l053r8/qutest @@ -72,7 +73,6 @@ endif # list of all source directories used by this project VPATH := . \ - ../src \ $(QPCPP)/src/qf \ $(QPCPP)/src/qxk \ $(QPCPP)/src/qs \ @@ -83,7 +83,6 @@ VPATH := . \ # list of all include directories needed by this project INCLUDES = -I. \ - -I../src \ -I$(QPCPP)/include \ -I$(QP_PORT_DIR) \ -I$(TARGET_DIR) \ @@ -104,7 +103,7 @@ C_SRCS := \ # C++ source files CPP_SRCS := \ - test_xthr.cpp \ + test_sched.cpp \ bsp_l053r8.cpp OUTPUT := $(PROJECT) @@ -141,7 +140,8 @@ LIB_DIRS := LIBS := # defines -DEFINES := +DEFINES := \ + -DQXK_ON_CONTEXT_SW # ARM CPU, ARCH, FPU, and Float-ABI types... # ARM_CPU: [cortex-m0 | cortex-m0plus | cortex-m1 | cortex-m3 | cortex-m4] @@ -250,7 +250,7 @@ endif # rules # -.PHONY : run norun flash +.PHONY : run norun debug flash ifeq ($(MAKECMDGOALS),norun) all : $(TARGET_BIN) @@ -289,15 +289,23 @@ $(BIN_DIR)/%.o : %.c $(BIN_DIR)/%.o : %.cpp $(CPP) $(CPPFLAGS) $< -o $@ -.PHONY : clean show - -# include dependency files only if our goal depends on their existence +# create BIN_DIR and include dependencies only if needed ifneq ($(MAKECMDGOALS),clean) ifneq ($(MAKECMDGOALS),show) + ifneq ($(MAKECMDGOALS),debug) +ifeq ("$(wildcard $(BIN_DIR))","") +$(shell $(MKDIR) $(BIN_DIR)) +endif -include $(C_DEPS_EXT) $(CPP_DEPS_EXT) + endif endif endif +debug : + $(QUTEST) $(TESTS) DEBUG $(HOST) + +.PHONY : clean show + clean : -$(RM) $(BIN_DIR)/*.o \ $(BIN_DIR)/*.d \ @@ -326,6 +334,5 @@ show : @echo QTOOLS = $(QTOOLS) @echo HOST = $(HOST) @echo QUTEST = $(QUTEST) - @echo FLASH = $(FLASH) @echo TESTS = $(TESTS) diff --git a/test/qxk/test_sched/test_sched.cpp b/test/qxk/test_sched/test_sched.cpp new file mode 100644 index 00000000..58fad133 --- /dev/null +++ b/test/qxk/test_sched/test_sched.cpp @@ -0,0 +1,245 @@ +//============================================================================ +// Product: System test fixture for QXK on the EFM32 target +// Last updated for version 7.1.2 +// Last updated on 2022-10-06 +// +// Q u a n t u m L e a P s +// ------------------------ +// Modern Embedded Software +// +// Copyright (C) 2005 Quantum Leaps. 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 +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Alternatively, this program may be distributed and modified under the +// terms of Quantum Leaps commercial licenses, which expressly supersede +// the GNU General Public License and are specifically designed for +// licensees interested in retaining the proprietary status of their code. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// Contact information: +// +// +//============================================================================ +#include "qpcpp.hpp" +#include "bsp.hpp" + +Q_DEFINE_THIS_FILE + +namespace { +//============================================================================ +// AO ObjB +enum { NUM_B = 3 }; + +//............................................................................ +// AO ObjB +class ObjB : public QP::QActive { +public: + static ObjB inst[NUM_B]; + +public: + ObjB() : QActive(&initial) {} + +protected: + Q_STATE_DECL(initial); + Q_STATE_DECL(active); +}; // class ObjB + +Q_STATE_DEF(ObjB, initial) { + static bool registered = false; // starts off with 0, per C-standard + if (!registered) { + registered = true; + QS_FUN_DICTIONARY(&ObjB::initial); + QS_FUN_DICTIONARY(&ObjB::active); + } + subscribe(TEST1_SIG); + subscribe(TEST2_SIG); + return tran(&active); +} + +Q_STATE_DEF(ObjB, active) { + QP::QState status_; + switch (e->sig) { + case TEST0_SIG: { + BSP::trace(this, "TEST0 1of2"); + BSP::trigISR(); + BSP::trace(this, "TEST0 2of2"); + status_ = Q_RET_HANDLED; + break; + } + case TEST1_SIG: { + BSP::trace(this, "TEST1 1of1"); + status_ = Q_RET_HANDLED; + break; + } + case TEST2_SIG: { + BSP::trace(this, "TEST2 1of1"); + status_ = Q_RET_HANDLED; + break; + } + default: { + status_ = super(&top); + break; + } + } + return status_; +} + +ObjB ObjB::inst[NUM_B]; + +/*==========================================================================*/ +enum { NUM_X = 3 }; + +static void ThrX_run(QP::QXThread * const me) { + me->subscribe(TEST1_SIG); + me->subscribe(TEST2_SIG); + + for (;;) { + QP::QEvt const *e = me->queueGet(QP::QXTHREAD_NO_TIMEOUT); + switch (e->sig) { + case TEST0_SIG: { + BSP::trace(me, "TEST0 1of2"); + BSP::trigISR(); + BSP::trace(me, "TEST0 2of2"); + break; + } + case TEST1_SIG: { + static QP::QEvt const t2 = { TEST2_SIG, 0U, 0U }; + BSP::trace(me, "TEST1 1of2"); + QP::QActive::PUBLISH(&t2, me); + BSP::trace(me, "TEST1 2of2"); + break; + } + case TEST2_SIG: { + BSP::trace(me, "TEST2 1of1"); + break; + } + default: { + break; + } + } + } +} + +class ThrX : public QP::QXThread { +public: + static ThrX inst[NUM_X]; + +public: + ThrX() : QXThread(&ThrX_run) {} +}; + +ThrX ThrX::inst[NUM_X]; + +} // unnamed namespace + +//============================================================================ +int main() { + + QP::QF::init(); // initialize the framework and the underlying QXK kernel + BSP::init(); // initialize the Board Support Package + + // initialize publish-subscribe... + static QP::QSubscrList subscrSto[MAX_PUB_SIG]; + QP::QActive::psInit(subscrSto, Q_DIM(subscrSto)); + + // initialize event pools... + static QF_MPOOL_EL(QP::QEvt) smlPoolSto[10]; // small pool + QP::QF::poolInit(smlPoolSto, sizeof(smlPoolSto), sizeof(smlPoolSto[0])); + + // dictionaries + QS_SIG_DICTIONARY(TEST0_SIG, nullptr); + QS_SIG_DICTIONARY(TEST1_SIG, nullptr); + QS_SIG_DICTIONARY(TEST2_SIG, nullptr); + QS_SIG_DICTIONARY(TEST3_SIG, nullptr); + + // priority specifications for ObjBs... + static QP::QPrioSpec pspecB[NUM_B]; + QS_OBJ_DICTIONARY(pspecB); + + // priority specifications for ThrXs... + static QP::QPrioSpec pspecX[NUM_X]; + QS_OBJ_DICTIONARY(pspecX); + + std::uint8_t n; + + for (n = 0U; n < NUM_B; ++n) { + QS_OBJ_ARR_DICTIONARY(&ObjB::inst[n], n); + } + for (n = 0U; n < NUM_X; ++n) { + QS_OBJ_ARR_DICTIONARY(&ThrX::inst[n], n); + } + + // pause execution of the test and wait for the test script to continue + // NOTE: + // this pause gives the test-script a chance to poke pspecB and pspecX + // variables to start the threads with the desired prio-specifications. + QS_TEST_PAUSE(); + + static QP::QEvt const *aoB_queueSto[NUM_B][5]; + for (n = 0U; n < NUM_B; ++n) { + if (pspecB[n] != 0U) { + ObjB::inst[n].start(pspecB[n], // QF-prio/p-thre. + aoB_queueSto[n], // event queue storage + Q_DIM(aoB_queueSto[n]), // event length [events] + nullptr, // no stack storage + 0U); // zero stack size [bytes] + } + } + + static QP::QEvt const *thrX_queueSto[NUM_X][5]; + static std::uint64_t thrXStackSto[NUM_X][32]; + for (n = 0U; n < NUM_X; ++n) { + if (pspecX[n] != 0U) { + ThrX::inst[n].start(pspecX[n], // QF-prio/p-thre. + thrX_queueSto[n], // event queue storage + Q_DIM(thrX_queueSto[n]), // event length [events] + thrXStackSto[n], // stack storage + sizeof(thrXStackSto[n]));// stack size [bytes] + } + } + + return QP::QF::run(); // run the QF application +} + +//============================================================================ +namespace QP { + +void QS::onTestSetup(void) { +} +//............................................................................ +void QS::onTestTeardown(void) { +} +//............................................................................ +//! callback function to execute user commands +void QS::onCommand(uint8_t cmdId, + uint32_t param1, uint32_t param2, uint32_t param3) +{ + Q_UNUSED_PAR(cmdId); + Q_UNUSED_PAR(param1); + Q_UNUSED_PAR(param2); + Q_UNUSED_PAR(param3); +} + +//============================================================================ +//! Host callback function to "massage" the event, if necessary +void QS::onTestEvt(QEvt *e) { + (void)e; +} +//............................................................................ +//! callback function to output the posted QP events (not used here) +void QS::onTestPost(void const *sender, QActive *recipient, + QEvt const *e, bool status) +{} + +} // namespace QP diff --git a/test/qxk/test_sched/test_sched.py b/test/qxk/test_sched/test_sched.py new file mode 100644 index 00000000..7f56e362 --- /dev/null +++ b/test/qxk/test_sched/test_sched.py @@ -0,0 +1,141 @@ +# test-script for QUTest unit testing harness +# see https://www.state-machine.com/qtools/qutest.html/qutest.html + +# preamble +def on_reset(): + expect_pause() + +test("extened->basic") +current_obj(OBJ_AP, "pspecB") +poke(0, 2, pack("1") +expect("@timestamp CONTEXT_SW NULL ThrX::inst[0]") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST0 1of2") +expect("@timestamp Sch-Next Pri=1->4") +expect("@timestamp CONTEXT_SW ThrX::inst[0] ObjB::inst[0]") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST1 1of1") +expect("@timestamp Sch-Next Pri=4->1") +expect("@timestamp CONTEXT_SW ObjB::inst[0] ThrX::inst[0]") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST0 2of2") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->4") +expect("@timestamp Sch-Unlk Ceil=4->0") +expect("@timestamp Sch-Next Pri=1->4") +expect("@timestamp CONTEXT_SW ThrX::inst[0] ObjB::inst[0]") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp Sch-Next Pri=4->1") +expect("@timestamp CONTEXT_SW ObjB::inst[0] ThrX::inst[0]") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST1 2of2") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST2 1of1") +expect("@timestamp Sch-Idle Pri=1->0") +expect("@timestamp CONTEXT_SW ThrX::inst[0] NULL") +expect("@timestamp Trg-Done QS_RX_EVENT") + +test("extended->extened->basic") +current_obj(OBJ_AP, "pspecB") +poke(0, 2, pack("4") +expect("@timestamp CONTEXT_SW NULL ThrX::inst[0]") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST0 1of2") +expect("@timestamp Sch-Next Pri=4->5") +expect("@timestamp CONTEXT_SW ThrX::inst[0] ThrX::inst[1]") +expect("@timestamp TRACE_MSG ThrX::inst[1] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->5") +expect("@timestamp Sch-Unlk Ceil=5->0") +expect("@timestamp TRACE_MSG ThrX::inst[1] TEST1 2of2") +expect("@timestamp TRACE_MSG ThrX::inst[1] TEST2 1of1") +expect("@timestamp Sch-Next Pri=5->4") +expect("@timestamp CONTEXT_SW ThrX::inst[1] ThrX::inst[0]") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST0 2of2") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->5") +expect("@timestamp Sch-Unlk Ceil=5->0") +expect("@timestamp Sch-Next Pri=4->5") +expect("@timestamp CONTEXT_SW ThrX::inst[0] ThrX::inst[1]") +expect("@timestamp TRACE_MSG ThrX::inst[1] TEST2 1of1") +expect("@timestamp Sch-Next Pri=5->4") +expect("@timestamp CONTEXT_SW ThrX::inst[1] ThrX::inst[0]") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST1 2of2") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST2 1of1") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST2 1of1") +expect("@timestamp Sch-Next Pri=4->3") +expect("@timestamp CONTEXT_SW ThrX::inst[0] ObjB::inst[2]") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST1 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST2 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[2] TEST2 1of1") +expect("@timestamp Sch-Next Pri=3->2") +expect("@timestamp CONTEXT_SW ObjB::inst[2] ObjB::inst[1]") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST1 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST2 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[1] TEST2 1of1") +expect("@timestamp Sch-Next Pri=2->1") +expect("@timestamp CONTEXT_SW ObjB::inst[1] ObjB::inst[0]") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST1 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp Sch-Idle Pri=1->0") +expect("@timestamp CONTEXT_SW ObjB::inst[0] NULL") +expect("@timestamp Trg-Done QS_RX_EVENT") + + +test("extened->basic->extended") +current_obj(OBJ_AP, "pspecB") +poke(0, 2, pack("1") +expect("@timestamp CONTEXT_SW NULL ThrX::inst[0]") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST0 1of2") +expect("@timestamp Sch-Next Pri=1->5") +expect("@timestamp CONTEXT_SW ThrX::inst[0] ThrX::inst[1]") +expect("@timestamp TRACE_MSG ThrX::inst[1] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->5") +expect("@timestamp Sch-Unlk Ceil=5->0") +expect("@timestamp TRACE_MSG ThrX::inst[1] TEST1 2of2") +expect("@timestamp TRACE_MSG ThrX::inst[1] TEST2 1of1") +expect("@timestamp Sch-Next Pri=5->4") +expect("@timestamp CONTEXT_SW ThrX::inst[1] ObjB::inst[0]") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST1 1of1") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp Sch-Next Pri=4->1") +expect("@timestamp CONTEXT_SW ObjB::inst[0] ThrX::inst[0]") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST0 2of2") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST1 1of2") +expect("@timestamp Sch-Lock Ceil=0->5") +expect("@timestamp Sch-Unlk Ceil=5->0") +expect("@timestamp Sch-Next Pri=1->5") +expect("@timestamp CONTEXT_SW ThrX::inst[0] ThrX::inst[1]") +expect("@timestamp TRACE_MSG ThrX::inst[1] TEST2 1of1") +expect("@timestamp Sch-Next Pri=5->4") +expect("@timestamp CONTEXT_SW ThrX::inst[1] ObjB::inst[0]") +expect("@timestamp TRACE_MSG ObjB::inst[0] TEST2 1of1") +expect("@timestamp Sch-Next Pri=4->1") +expect("@timestamp CONTEXT_SW ObjB::inst[0] ThrX::inst[0]") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST1 2of2") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST2 1of1") +expect("@timestamp TRACE_MSG ThrX::inst[0] TEST2 1of1") +expect("@timestamp Sch-Idle Pri=1->0") +expect("@timestamp CONTEXT_SW ThrX::inst[0] NULL") +expect("@timestamp Trg-Done QS_RX_EVENT") diff --git a/test/qxk/test_sched/uvision_efm32.uvoptx b/test/qxk/test_sched/uvision_efm32.uvoptx new file mode 100644 index 00000000..f802e499 --- /dev/null +++ b/test/qxk/test_sched/uvision_efm32.uvoptx @@ -0,0 +1,801 @@ + + + + 1.0 + +
### uVision Project, (C) Keil Software
+ + + *.c + *.s*; *.src; *.a* + *.obj; *.o + *.lib + *.txt; *.h; *.inc; *.md + *.plm + *.cpp + 0 + + + + 0 + 0 + + + + qutest + 0x4 + ARM-ADS + + 12000000 + + 1 + 1 + 1 + 0 + 0 + + + 1 + 65535 + 0 + 0 + 0 + + + 79 + 66 + 8 + .\uvision_emf32\ + + + 1 + 1 + 1 + 0 + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 0 + + + 1 + 0 + 1 + + 3 + + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 0 + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 4 + + + + + + + + + + + Segger\JL2CM3.dll + + + + 0 + DLGUARM + + + + 0 + JL2CM3 + -U440060969 -O206 -S2 -ZTIFSpeedSel5000 -A0 -C0 -JU1 -JI127.0.0.1 -JP0 -RST0 -N00("ARM CoreSight SW-DP") -D00(2BA01477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -TB1 -TFE0 -FO7 -FD20000000 -FC8000 -FN1 -FF0GECKOP2.FLM -FS00 -FL020000 -FP0($$Device:EFM32PG1B200F256GM48$Flash\GECKOP2.FLM) + + + 0 + ARMRTXEVENTFLAGS + -L70 -Z18 -C0 -M0 -T1 + + + 0 + UL2CM3 + UL2CM3(-O207 -S0 -C0 -FO7 -FN1 -FC8000 -FD20000000 -FF0GECKOP2 -FL020000 -FS00 -FP0($$Device:EFM32PG1B200F256GM48$Flash\GECKOP2.FLM) + + + 0 + DLGTARM + (1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)(1012=-1,-1,-1,-1,0) + + + 0 + ARMDBGFLAGS + + + + 0 + lmidk-agdi + -U0E2006F4 -O4622 -S4 -FO61 + + + + + 0 + 0 + 142 + 1 +
136
+ 0 + 0 + 0 + 0 + 0 + 1 + ..\..\..\src\qs\qs.c + + \\test\../../../src/qs/qs.c\142 +
+ + 1 + 0 + 113 + 1 +
29538
+ 0 + 0 + 0 + 0 + 0 + 1 + ..\..\..\src\qs\qutest.c + + \\test\../../../src/qs/qutest.c\113 +
+ + 2 + 0 + 259 + 1 +
26664
+ 0 + 0 + 0 + 0 + 0 + 1 + ..\..\..\src\qxk\qxk.c + + \\test\../../../src/qxk/qxk.c\259 +
+ + 3 + 0 + 103 + 1 +
29984
+ 0 + 0 + 0 + 0 + 0 + 1 + .\test_sched.c + + \\test\test_sched.c\103 +
+
+ + + 0 + 1 + QF_readySet_ + + + 1 + 1 + QXK_attr_ + + + 2 + 1 + QActive_registry_ + + + 3 + 1 + QS_rxPriv_ + + + + + 1 + 2 + 0x20000200 + 0 + + + + + 2 + 0 + 0x400 + 0 + + + + 0 + + + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + 0 + 0 + 0 + + + + + + + + +
+
+ + + Applicatioin + 1 + 0 + 0 + 0 + + 1 + 1 + 5 + 0 + 0 + 0 + .\bsp.h + bsp.h + 0 + 0 + + + 1 + 2 + 1 + 0 + 0 + 0 + .\bsp_efm32.c + bsp_efm32.c + 0 + 0 + + + 1 + 3 + 1 + 0 + 0 + 0 + .\test_sched.c + test_sched.c + 0 + 0 + + + + + efm32pg1b + 1 + 0 + 0 + 0 + + 2 + 4 + 2 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\arm\startup_efm32pg1b.s + startup_efm32pg1b.s + 0 + 0 + + + 2 + 5 + 1 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\em_cmu.c + em_cmu.c + 0 + 0 + + + 2 + 6 + 1 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\em_emu.c + em_emu.c + 0 + 0 + + + 2 + 7 + 1 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\em_gpio.c + em_gpio.c + 0 + 0 + + + 2 + 8 + 1 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\system_efm32pg1b.c + system_efm32pg1b.c + 0 + 0 + + + 2 + 9 + 1 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\em_system.c + em_system.c + 0 + 0 + + + 2 + 10 + 1 + 0 + 0 + 0 + ..\..\..\..\3rd_party\efm32pg1b\em_usart.c + em_usart.c + 0 + 0 + + + + + QP + 1 + 0 + 0 + 0 + + 3 + 11 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qep_hsm.c + qep_hsm.c + 0 + 0 + + + 3 + 12 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qep_msm.c + qep_msm.c + 0 + 0 + + + 3 + 13 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_act.c + qf_act.c + 0 + 0 + + + 3 + 14 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_actq.c + qf_actq.c + 0 + 0 + + + 3 + 15 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_defer.c + qf_defer.c + 0 + 0 + + + 3 + 16 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_dyn.c + qf_dyn.c + 0 + 0 + + + 3 + 17 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_mem.c + qf_mem.c + 0 + 0 + + + 3 + 18 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_ps.c + qf_ps.c + 0 + 0 + + + 3 + 19 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_qact.c + qf_qact.c + 0 + 0 + + + 3 + 20 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_qeq.c + qf_qeq.c + 0 + 0 + + + 3 + 21 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_qmact.c + qf_qmact.c + 0 + 0 + + + 3 + 22 + 1 + 0 + 0 + 0 + ..\..\..\src\qf\qf_time.c + qf_time.c + 0 + 0 + + + 3 + 23 + 1 + 0 + 0 + 0 + ..\..\..\src\qxk\qxk.c + qxk.c + 0 + 0 + + + 3 + 24 + 1 + 0 + 0 + 0 + ..\..\..\src\qxk\qxk_mutex.c + qxk_mutex.c + 0 + 0 + + + 3 + 25 + 1 + 0 + 0 + 0 + ..\..\..\src\qxk\qxk_sema.c + qxk_sema.c + 0 + 0 + + + 3 + 26 + 1 + 0 + 0 + 0 + ..\..\..\src\qxk\qxk_xthr.c + qxk_xthr.c + 0 + 0 + + + 3 + 27 + 1 + 0 + 0 + 0 + ..\..\..\include\qstamp.c + qstamp.c + 0 + 0 + + + + + QP_port + 1 + 0 + 0 + 0 + + 4 + 28 + 5 + 0 + 0 + 0 + ..\..\..\ports\arm-cm\qxk\armclang\qep_port.h + qep_port.h + 0 + 0 + + + 4 + 29 + 5 + 0 + 0 + 0 + ..\..\..\ports\arm-cm\qxk\armclang\qf_port.h + qf_port.h + 0 + 0 + + + 4 + 30 + 5 + 0 + 0 + 0 + ..\..\..\ports\arm-cm\qxk\armclang\qs_port.h + qs_port.h + 0 + 0 + + + 4 + 31 + 1 + 0 + 0 + 0 + ..\..\..\ports\arm-cm\qxk\armclang\qxk_port.c + qxk_port.c + 0 + 0 + + + 4 + 32 + 5 + 0 + 0 + 0 + ..\..\..\ports\arm-cm\qxk\armclang\qxk_port.h + qxk_port.h + 0 + 0 + + + 4 + 33 + 1 + 0 + 0 + 0 + ..\..\..\3rd_party\efm32pg1b\qutest\qutest_port.c + qutest_port.c + 0 + 0 + + + + + QS + 1 + 0 + 0 + 0 + + 5 + 34 + 1 + 0 + 0 + 0 + ..\..\..\src\qs\qs.c + qs.c + 0 + 0 + + + 5 + 35 + 1 + 0 + 0 + 0 + ..\..\..\src\qs\qs_64bit.c + qs_64bit.c + 0 + 0 + + + 5 + 36 + 1 + 0 + 0 + 0 + ..\..\..\src\qs\qs_fp.c + qs_fp.c + 0 + 0 + + + 5 + 37 + 1 + 0 + 0 + 0 + ..\..\..\src\qs\qs_rx.c + qs_rx.c + 0 + 0 + + + 5 + 38 + 1 + 0 + 0 + 0 + ..\..\..\src\qs\qutest.c + qutest.c + 0 + 0 + + + +
diff --git a/test/qxk/test_sched/uvision_efm32.uvprojx b/test/qxk/test_sched/uvision_efm32.uvprojx new file mode 100644 index 00000000..8c1c944b --- /dev/null +++ b/test/qxk/test_sched/uvision_efm32.uvprojx @@ -0,0 +1,617 @@ + + + + 2.1 + +
### uVision Project, (C) Keil Software
+ + + + qutest + 0x4 + ARM-ADS + 6160000::V6.16::ARMCLANG + 1 + + + EFM32PG1B200F256GM48 + Silicon Labs + SiliconLabs.GeckoPlatform_EFM32PG1B_DFP.4.0.0 + https://www.silabs.com/documents/public/cmsis-packs/ + IRAM(0x20000000,0x00008000) IROM(0x00000000,0x00020000) CPUTYPE("Cortex-M4") FPU2 CLOCK(12000000) ELITTLE + + + UL2CM3(-S0 -C0 -P0 -FD20000000 -FC8000 -FN1 -FF0GECKOP2 -FS00 -FL020000 -FP0($$Device:EFM32PG1B200F256GM48$Flash\GECKOP2.FLM)) + 0 + $$Device:EFM32PG1B200F256GM48$Device\EFM32PG1B\Include\em_device.h + + + + + + + + + + $$Device:EFM32PG1B200F256GM48$SVD\EFM32PG1B\EFM32PG1B200F256GM48.svd + 0 + 0 + + + + + + + 0 + 0 + 0 + 0 + 1 + + .\uvision_emf32\ + test + 1 + 0 + 0 + 1 + 1 + .\uvision_emf32\ + 1 + 0 + 0 + + 0 + 0 + + + 0 + 0 + 0 + 0 + + + 1 + 0 + cmd /c "del .\uvision_em32\qstamp.o" + + 0 + 0 + 0 + 0 + + + 0 + 0 + + + 0 + 0 + 0 + 0 + + 1 + + + + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 3 + + + 1 + + + SARMCM3.DLL + -MPU + DCM.DLL + -pCM4 + SARMCM3.DLL + -MPU + TCM.DLL + -pCM4 + + + + 1 + 0 + 0 + 0 + 16 + + + + + 1 + 0 + 0 + 1 + 1 + 4096 + + 1 + BIN\UL2CM3.DLL + "" () + + + + + 0 + + + + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 0 + "Cortex-M4" + + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 8 + 0 + 0 + 0 + 0 + 3 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x20000000 + 0x8000 + + + 1 + 0x0 + 0x20000 + + + 0 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x20000 + + + 1 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x20000000 + 0x8000 + + + 0 + 0x0 + 0x0 + + + + + + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 1 + 1 + 0 + 0 + 3 + 3 + 0 + 0 + 0 + 0 + 0 + + + Q_SPY, Q_UTEST=0, QXK_ON_CONTEXT_SW + + .;..\..\..\include;..\..\..\ports\arm-cm\qxk\armclang;..\..\..\..\3rd_party\CMSIS\Include;..\..\..\..\3rd_party\efm32pg1b + + + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 4 + + + Stack_Size=2048 Heap_Size=16 + + + + + + 1 + 0 + 0 + 0 + 1 + 0 + 0x00000000 + 0x20000000 + + + + + --entry Reset_Handler + + + + + + + + Applicatioin + + + bsp.h + 5 + .\bsp.h + + + bsp_efm32.c + 1 + .\bsp_efm32.c + + + test_sched.c + 1 + .\test_sched.c + + + + + efm32pg1b + + + startup_efm32pg1b.s + 2 + ..\..\..\..\3rd_party\efm32pg1b\arm\startup_efm32pg1b.s + + + em_cmu.c + 1 + ..\..\..\..\3rd_party\efm32pg1b\em_cmu.c + + + em_emu.c + 1 + ..\..\..\..\3rd_party\efm32pg1b\em_emu.c + + + em_gpio.c + 1 + ..\..\..\..\3rd_party\efm32pg1b\em_gpio.c + + + system_efm32pg1b.c + 1 + ..\..\..\..\3rd_party\efm32pg1b\system_efm32pg1b.c + + + em_system.c + 1 + ..\..\..\..\3rd_party\efm32pg1b\em_system.c + + + em_usart.c + 1 + ..\..\..\..\3rd_party\efm32pg1b\em_usart.c + + + + + QP + + + qep_hsm.c + 1 + ..\..\..\src\qf\qep_hsm.c + + + qep_msm.c + 1 + ..\..\..\src\qf\qep_msm.c + + + qf_act.c + 1 + ..\..\..\src\qf\qf_act.c + + + qf_actq.c + 1 + ..\..\..\src\qf\qf_actq.c + + + qf_defer.c + 1 + ..\..\..\src\qf\qf_defer.c + + + qf_dyn.c + 1 + ..\..\..\src\qf\qf_dyn.c + + + qf_mem.c + 1 + ..\..\..\src\qf\qf_mem.c + + + qf_ps.c + 1 + ..\..\..\src\qf\qf_ps.c + + + qf_qact.c + 1 + ..\..\..\src\qf\qf_qact.c + + + qf_qeq.c + 1 + ..\..\..\src\qf\qf_qeq.c + + + qf_qmact.c + 1 + ..\..\..\src\qf\qf_qmact.c + + + qf_time.c + 1 + ..\..\..\src\qf\qf_time.c + + + qxk.c + 1 + ..\..\..\src\qxk\qxk.c + + + qxk_mutex.c + 1 + ..\..\..\src\qxk\qxk_mutex.c + + + qxk_sema.c + 1 + ..\..\..\src\qxk\qxk_sema.c + + + qxk_xthr.c + 1 + ..\..\..\src\qxk\qxk_xthr.c + + + qstamp.c + 1 + ..\..\..\include\qstamp.c + + + + + QP_port + + + qep_port.h + 5 + ..\..\..\ports\arm-cm\qxk\armclang\qep_port.h + + + qf_port.h + 5 + ..\..\..\ports\arm-cm\qxk\armclang\qf_port.h + + + qs_port.h + 5 + ..\..\..\ports\arm-cm\qxk\armclang\qs_port.h + + + qxk_port.c + 1 + ..\..\..\ports\arm-cm\qxk\armclang\qxk_port.c + + + qxk_port.h + 5 + ..\..\..\ports\arm-cm\qxk\armclang\qxk_port.h + + + qutest_port.c + 1 + ..\..\..\3rd_party\efm32pg1b\qutest\qutest_port.c + + + + + QS + + + qs.c + 1 + ..\..\..\src\qs\qs.c + + + qs_64bit.c + 1 + ..\..\..\src\qs\qs_64bit.c + + + qs_fp.c + 1 + ..\..\..\src\qs\qs_fp.c + + + qs_rx.c + 1 + ..\..\..\src\qs\qs_rx.c + + + qutest.c + 1 + ..\..\..\src\qs\qutest.c + + + + + + + + + + + + + + + + + test + 1 + + + + +
diff --git a/test/qxk/test_xthr/test_xthr.cpp b/test/qxk/test_xthr/test_xthr.cpp deleted file mode 100644 index c4eddc0f..00000000 --- a/test/qxk/test_xthr/test_xthr.cpp +++ /dev/null @@ -1,126 +0,0 @@ -//============================================================================ -// Product: System test fixture for QXK on the EFM32 target -// Last updated for version 7.1.1 -// Last updated on 2022-09-23 -// -// Q u a n t u m L e a P s -// ------------------------ -// Modern Embedded Software -// -// Copyright (C) 2005 Quantum Leaps. 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 -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Alternatively, this program may be distributed and modified under the -// terms of Quantum Leaps commercial licenses, which expressly supersede -// the GNU General Public License and are specifically designed for -// licensees interested in retaining the proprietary status of their code. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// Contact information: -// -// -//============================================================================ -#include "qpcpp.hpp" -#include "bsp.hpp" - -Q_DEFINE_THIS_FILE - -//============================================================================ -namespace { -static void Thread1_run(QP::QXThread * const me) { - - for (;;) { - BSP::ledOn(); - QP::QXThread::delay(1U); // BLOCK! - BSP::ledOff(); - QP::QXThread::delay(1U); // BLOCK! - } -} -static QP::QXThread thr1(&Thread1_run, 0U); -} - -//============================================================================ -namespace QP { - -void QS::onTestSetup(void) { -} -//............................................................................ -void QS::onTestTeardown(void) { -} -//............................................................................ -//! callback function to execute user commands -void QS::onCommand(uint8_t cmdId, - uint32_t param1, uint32_t param2, uint32_t param3) -{ - switch (cmdId) { - case 0U: { - break; - } - case 1U: { - break; - } - default: - break; - } -} - -//============================================================================ -//! Host callback function to "massage" the event, if necessary -void QS::onTestEvt(QEvt *e) { - (void)e; -} -//............................................................................ -//! callback function to output the posted QP events (not used here) -void QS::onTestPost(void const *sender, QActive *recipient, - QEvt const *e, bool status) -{ -} - -} // namespace QP - -//============================================================================ -int main() { - - QP::QF::init(); // initialize the framework and the underlying QXK kernel - BSP::init(); // initialize the Board Support Package - - // dictionaries - QS_OBJ_DICTIONARY(&thr1); - QS_OBJ_DICTIONARY(thr1.getTimeEvt()); - QS_SIG_DICTIONARY(TEST_SIG, nullptr); - QS_SIG_DICTIONARY(TRIG_SIG, nullptr); - QS_SIG_DICTIONARY(TIMEOUT_SIG, nullptr); - - // setup the QS filters... - QS_GLB_FILTER(QP::QS_ALL_RECORDS); // all records - - // initialize publish-subscribe... - static QP::QSubscrList subscrSto[MAX_PUB_SIG]; - QP::QActive::psInit(subscrSto, Q_DIM(subscrSto)); - - // initialize event pools... - static QF_MPOOL_EL(QP::QEvt) smlPoolSto[10]; // small pool - QP::QF::poolInit(smlPoolSto, sizeof(smlPoolSto), sizeof(smlPoolSto[0])); - - // start the extended thread1 - static QP::QEvt const *test1QueueSto[5]; - static uint64_t test1StackSto[64]; - thr1.start(1U, // QF-priority/preemption-threshold - test1QueueSto, // message queue storage - Q_DIM(test1QueueSto), // message length [events] - test1StackSto, // stack storage - sizeof(test1StackSto)); // stack size [bytes] - - return QP::QF::run(); // run the QF application -} diff --git a/test/qxk/test_xthr/tick_tick.py b/test/qxk/test_xthr/tick_tick.py deleted file mode 100644 index a9b6fc7a..00000000 --- a/test/qxk/test_xthr/tick_tick.py +++ /dev/null @@ -1,27 +0,0 @@ -# test-script for QUTest unit testing harness -# see https://www.state-machine.com/qtools/qutest.html/qutest.html - -# preamble... -def on_reset(): - expect("@timestamp Sch-Next Pri=0->1") - expect_run() - expect("@timestamp Sch-Idle Pri=1->0") - -test("extended thread tick-tick") -current_obj(OBJ_AP,"thr1") -query_curr(OBJ_AP) -expect("@timestamp Query-AP Obj=thr1") -tick() -expect(" Tick<0> Ctr=0000000001") -expect(" TE0-ADis Obj=thr1.getTimeEvt(),AO=thr1") -expect("@timestamp TE0-Post Obj=thr1.getTimeEvt(),Sig=TEST_SIG,AO=thr1") -expect("@timestamp Sch-Pre Pri=0->1") -expect("@timestamp Sch-Idle Pri=1->0") -expect("@timestamp Trg-Done QS_RX_TICK") -tick() -expect(" Tick<0> Ctr=0000000002") -expect(" TE0-ADis Obj=thr1.getTimeEvt(),AO=thr1") -expect("@timestamp TE0-Post Obj=thr1.getTimeEvt(),Sig=TEST_SIG,AO=thr1") -expect("@timestamp Sch-Pre Pri=0->1") -expect("@timestamp Sch-Idle Pri=1->0") -expect("@timestamp Trg-Done QS_RX_TICK")