diff --git a/site/404.html b/site/404.html index 79a7a1b..d8ff238 100644 --- a/site/404.html +++ b/site/404.html @@ -842,7 +842,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/advancing/cli/index.html b/site/advancing/cli/index.html index ef42dd0..4297cf4 100644 --- a/site/advancing/cli/index.html +++ b/site/advancing/cli/index.html @@ -876,7 +876,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/advancing/coremark/index.html b/site/advancing/coremark/index.html index ef15136..52a8eba 100644 --- a/site/advancing/coremark/index.html +++ b/site/advancing/coremark/index.html @@ -978,7 +978,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/advancing/emmark/index.html b/site/advancing/emmark/index.html index 8dab0c6..5241ee2 100644 --- a/site/advancing/emmark/index.html +++ b/site/advancing/emmark/index.html @@ -20,7 +20,7 @@ - EM&•Mark Results - Platform Documentation + EM•Mark Results - Platform Documentation @@ -134,7 +134,7 @@
- EM&•Mark Results + EM•Mark Results
@@ -875,7 +875,7 @@ - EM&•Mark Results + EM•Mark Results @@ -886,7 +886,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/advancing/energy/index.html b/site/advancing/energy/index.html index 4ee089a..36ed119 100644 --- a/site/advancing/energy/index.html +++ b/site/advancing/energy/index.html @@ -866,7 +866,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/advancing/index.html b/site/advancing/index.html index ea2b370..a0b1344 100644 --- a/site/advancing/index.html +++ b/site/advancing/index.html @@ -866,7 +866,7 @@ - EM&•Mark Results + EM•Mark Results @@ -5647,7 +5647,7 @@

Deep-dive into different facets o Managing EM from within the shell -🆕CoreMark® Reimagined +🆕CoreMark Reimagined Transforming legacy C code into EM diff --git a/site/advancing/syntax/index.html b/site/advancing/syntax/index.html index dfb5a31..d7db42f 100644 --- a/site/advancing/syntax/index.html +++ b/site/advancing/syntax/index.html @@ -866,7 +866,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/ActiveRunnerP/index.html b/site/cargo/em.bench/em.coremark/ActiveRunnerP/index.html index 7a09394..969c8df 100644 --- a/site/cargo/em.bench/em.coremark/ActiveRunnerP/index.html +++ b/site/cargo/em.bench/em.coremark/ActiveRunnerP/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/BenchAlgI/index.html b/site/cargo/em.bench/em.coremark/BenchAlgI/index.html index 997cd15..4be2b1e 100644 --- a/site/cargo/em.bench/em.coremark/BenchAlgI/index.html +++ b/site/cargo/em.bench/em.coremark/BenchAlgI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/ComparatorI/index.html b/site/cargo/em.bench/em.coremark/ComparatorI/index.html index 66c5754..f83c62d 100644 --- a/site/cargo/em.bench/em.coremark/ComparatorI/index.html +++ b/site/cargo/em.bench/em.coremark/ComparatorI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/CoreBench/index.html b/site/cargo/em.bench/em.coremark/CoreBench/index.html index 7332e65..24879c4 100644 --- a/site/cargo/em.bench/em.coremark/CoreBench/index.html +++ b/site/cargo/em.bench/em.coremark/CoreBench/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/Crc/index.html b/site/cargo/em.bench/em.coremark/Crc/index.html index c0283eb..e89ee8a 100644 --- a/site/cargo/em.bench/em.coremark/Crc/index.html +++ b/site/cargo/em.bench/em.coremark/Crc/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/IdxComparator/index.html b/site/cargo/em.bench/em.coremark/IdxComparator/index.html index 9709260..bf95f8a 100644 --- a/site/cargo/em.bench/em.coremark/IdxComparator/index.html +++ b/site/cargo/em.bench/em.coremark/IdxComparator/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/ListBench/index.html b/site/cargo/em.bench/em.coremark/ListBench/index.html index f1a5f4f..72bc8fa 100644 --- a/site/cargo/em.bench/em.coremark/ListBench/index.html +++ b/site/cargo/em.bench/em.coremark/ListBench/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/MatrixBench/index.html b/site/cargo/em.bench/em.coremark/MatrixBench/index.html index 9a0acdd..a06db86 100644 --- a/site/cargo/em.bench/em.coremark/MatrixBench/index.html +++ b/site/cargo/em.bench/em.coremark/MatrixBench/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/SleepyRunnerP/index.html b/site/cargo/em.bench/em.coremark/SleepyRunnerP/index.html index 87999c5..e6d628e 100644 --- a/site/cargo/em.bench/em.coremark/SleepyRunnerP/index.html +++ b/site/cargo/em.bench/em.coremark/SleepyRunnerP/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/StateBench/index.html b/site/cargo/em.bench/em.coremark/StateBench/index.html index 207e7b7..a0c4800 100644 --- a/site/cargo/em.bench/em.coremark/StateBench/index.html +++ b/site/cargo/em.bench/em.coremark/StateBench/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/Utils/index.html b/site/cargo/em.bench/em.coremark/Utils/index.html index e193d2d..c86fa37 100644 --- a/site/cargo/em.bench/em.coremark/Utils/index.html +++ b/site/cargo/em.bench/em.coremark/Utils/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/ValComparator/index.html b/site/cargo/em.bench/em.coremark/ValComparator/index.html index 790b8a0..4eae1b7 100644 --- a/site/cargo/em.bench/em.coremark/ValComparator/index.html +++ b/site/cargo/em.bench/em.coremark/ValComparator/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/em.coremark/index.html b/site/cargo/em.bench/em.coremark/index.html index 88edc72..f8233c7 100644 --- a/site/cargo/em.bench/em.coremark/index.html +++ b/site/cargo/em.bench/em.coremark/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.bench/index.html b/site/cargo/em.bench/index.html index f554543..81e4fc9 100644 --- a/site/cargo/em.bench/index.html +++ b/site/cargo/em.bench/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/BusyWaitI/index.html b/site/cargo/em.core/em.hal/BusyWaitI/index.html index c9f2f96..1c127f7 100644 --- a/site/cargo/em.core/em.hal/BusyWaitI/index.html +++ b/site/cargo/em.core/em.hal/BusyWaitI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/BusyWaitN/index.html b/site/cargo/em.core/em.hal/BusyWaitN/index.html index acbd217..e506f19 100644 --- a/site/cargo/em.core/em.hal/BusyWaitN/index.html +++ b/site/cargo/em.core/em.hal/BusyWaitN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/ButtonI/index.html b/site/cargo/em.core/em.hal/ButtonI/index.html index b604728..dc726e2 100644 --- a/site/cargo/em.core/em.hal/ButtonI/index.html +++ b/site/cargo/em.core/em.hal/ButtonI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/ButtonN/index.html b/site/cargo/em.core/em.hal/ButtonN/index.html index 5f93956..d445773 100644 --- a/site/cargo/em.core/em.hal/ButtonN/index.html +++ b/site/cargo/em.core/em.hal/ButtonN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/ConsoleUartI/index.html b/site/cargo/em.core/em.hal/ConsoleUartI/index.html index c533c35..f3e8526 100644 --- a/site/cargo/em.core/em.hal/ConsoleUartI/index.html +++ b/site/cargo/em.core/em.hal/ConsoleUartI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/ConsoleUartN/index.html b/site/cargo/em.core/em.hal/ConsoleUartN/index.html index 1036eb6..57cfc43 100644 --- a/site/cargo/em.core/em.hal/ConsoleUartN/index.html +++ b/site/cargo/em.core/em.hal/ConsoleUartN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/CopierI/index.html b/site/cargo/em.core/em.hal/CopierI/index.html index a4e63c5..868b566 100644 --- a/site/cargo/em.core/em.hal/CopierI/index.html +++ b/site/cargo/em.core/em.hal/CopierI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/FlashI/index.html b/site/cargo/em.core/em.hal/FlashI/index.html index fdfb6e8..8761120 100644 --- a/site/cargo/em.core/em.hal/FlashI/index.html +++ b/site/cargo/em.core/em.hal/FlashI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/FlashN/index.html b/site/cargo/em.core/em.hal/FlashN/index.html index 2cfd3e1..a0ac48f 100644 --- a/site/cargo/em.core/em.hal/FlashN/index.html +++ b/site/cargo/em.core/em.hal/FlashN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/GlobalInterruptsI/index.html b/site/cargo/em.core/em.hal/GlobalInterruptsI/index.html index 22649c7..7bdd255 100644 --- a/site/cargo/em.core/em.hal/GlobalInterruptsI/index.html +++ b/site/cargo/em.core/em.hal/GlobalInterruptsI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/GlobalInterruptsN/index.html b/site/cargo/em.core/em.hal/GlobalInterruptsN/index.html index b89e94b..8f1dd54 100644 --- a/site/cargo/em.core/em.hal/GlobalInterruptsN/index.html +++ b/site/cargo/em.core/em.hal/GlobalInterruptsN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/GpioEdgeDetectMinI/index.html b/site/cargo/em.core/em.hal/GpioEdgeDetectMinI/index.html index e4b7616..a8f180a 100644 --- a/site/cargo/em.core/em.hal/GpioEdgeDetectMinI/index.html +++ b/site/cargo/em.core/em.hal/GpioEdgeDetectMinI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/GpioEdgeDetectMinN/index.html b/site/cargo/em.core/em.hal/GpioEdgeDetectMinN/index.html index 0409574..9a26f56 100644 --- a/site/cargo/em.core/em.hal/GpioEdgeDetectMinN/index.html +++ b/site/cargo/em.core/em.hal/GpioEdgeDetectMinN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/GpioI/index.html b/site/cargo/em.core/em.hal/GpioI/index.html index b71fb11..9b25d58 100644 --- a/site/cargo/em.core/em.hal/GpioI/index.html +++ b/site/cargo/em.core/em.hal/GpioI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/GpioN/index.html b/site/cargo/em.core/em.hal/GpioN/index.html index 04a6ff8..8f88b43 100644 --- a/site/cargo/em.core/em.hal/GpioN/index.html +++ b/site/cargo/em.core/em.hal/GpioN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/HostUartI/index.html b/site/cargo/em.core/em.hal/HostUartI/index.html index 3792834..c5d6237 100644 --- a/site/cargo/em.core/em.hal/HostUartI/index.html +++ b/site/cargo/em.core/em.hal/HostUartI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/HostUartN/index.html b/site/cargo/em.core/em.hal/HostUartN/index.html index 196eb49..ed5706b 100644 --- a/site/cargo/em.core/em.hal/HostUartN/index.html +++ b/site/cargo/em.core/em.hal/HostUartN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/IdleI/index.html b/site/cargo/em.core/em.hal/IdleI/index.html index 0c56519..22e6e50 100644 --- a/site/cargo/em.core/em.hal/IdleI/index.html +++ b/site/cargo/em.core/em.hal/IdleI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/IdleN/index.html b/site/cargo/em.core/em.hal/IdleN/index.html index da55eb5..01c7116 100644 --- a/site/cargo/em.core/em.hal/IdleN/index.html +++ b/site/cargo/em.core/em.hal/IdleN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/InterruptSourceI/index.html b/site/cargo/em.core/em.hal/InterruptSourceI/index.html index 484d323..27321c0 100644 --- a/site/cargo/em.core/em.hal/InterruptSourceI/index.html +++ b/site/cargo/em.core/em.hal/InterruptSourceI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/IntrVecI/index.html b/site/cargo/em.core/em.hal/IntrVecI/index.html index 80267ff..aef4fa3 100644 --- a/site/cargo/em.core/em.hal/IntrVecI/index.html +++ b/site/cargo/em.core/em.hal/IntrVecI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/LedI/index.html b/site/cargo/em.core/em.hal/LedI/index.html index 13ce021..1b1963d 100644 --- a/site/cargo/em.core/em.hal/LedI/index.html +++ b/site/cargo/em.core/em.hal/LedI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/LedN/index.html b/site/cargo/em.core/em.hal/LedN/index.html index bd99661..bb2f118 100644 --- a/site/cargo/em.core/em.hal/LedN/index.html +++ b/site/cargo/em.core/em.hal/LedN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/McuI/index.html b/site/cargo/em.core/em.hal/McuI/index.html index 9b858bb..e2aa429 100644 --- a/site/cargo/em.core/em.hal/McuI/index.html +++ b/site/cargo/em.core/em.hal/McuI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/McuInfoI/index.html b/site/cargo/em.core/em.hal/McuInfoI/index.html index 4f659a7..48cb81c 100644 --- a/site/cargo/em.core/em.hal/McuInfoI/index.html +++ b/site/cargo/em.core/em.hal/McuInfoI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/McuInfoN/index.html b/site/cargo/em.core/em.hal/McuInfoN/index.html index 887da13..fdbd6e6 100644 --- a/site/cargo/em.core/em.hal/McuInfoN/index.html +++ b/site/cargo/em.core/em.hal/McuInfoN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/McuN/index.html b/site/cargo/em.core/em.hal/McuN/index.html index 63429db..29d9c32 100644 --- a/site/cargo/em.core/em.hal/McuN/index.html +++ b/site/cargo/em.core/em.hal/McuN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/MsCounterI/index.html b/site/cargo/em.core/em.hal/MsCounterI/index.html index fb6244b..1e2010d 100644 --- a/site/cargo/em.core/em.hal/MsCounterI/index.html +++ b/site/cargo/em.core/em.hal/MsCounterI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/MsCounterN/index.html b/site/cargo/em.core/em.hal/MsCounterN/index.html index 9f019bd..40c989e 100644 --- a/site/cargo/em.core/em.hal/MsCounterN/index.html +++ b/site/cargo/em.core/em.hal/MsCounterN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/OneShotMilliI/index.html b/site/cargo/em.core/em.hal/OneShotMilliI/index.html index 6f86088..11bf9a6 100644 --- a/site/cargo/em.core/em.hal/OneShotMilliI/index.html +++ b/site/cargo/em.core/em.hal/OneShotMilliI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/OneShotMilliN/index.html b/site/cargo/em.core/em.hal/OneShotMilliN/index.html index b6791f8..088390a 100644 --- a/site/cargo/em.core/em.hal/OneShotMilliN/index.html +++ b/site/cargo/em.core/em.hal/OneShotMilliN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/PollerI/index.html b/site/cargo/em.core/em.hal/PollerI/index.html index f77edcc..411318e 100644 --- a/site/cargo/em.core/em.hal/PollerI/index.html +++ b/site/cargo/em.core/em.hal/PollerI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/PollerN/index.html b/site/cargo/em.core/em.hal/PollerN/index.html index 1af84a9..8a76016 100644 --- a/site/cargo/em.core/em.hal/PollerN/index.html +++ b/site/cargo/em.core/em.hal/PollerN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/RandI/index.html b/site/cargo/em.core/em.hal/RandI/index.html index 5eb426f..553f07b 100644 --- a/site/cargo/em.core/em.hal/RandI/index.html +++ b/site/cargo/em.core/em.hal/RandI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/RandN/index.html b/site/cargo/em.core/em.hal/RandN/index.html index a9300b2..61a661a 100644 --- a/site/cargo/em.core/em.hal/RandN/index.html +++ b/site/cargo/em.core/em.hal/RandN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/SpiMasterI/index.html b/site/cargo/em.core/em.hal/SpiMasterI/index.html index 41e03b2..48459dd 100644 --- a/site/cargo/em.core/em.hal/SpiMasterI/index.html +++ b/site/cargo/em.core/em.hal/SpiMasterI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/TimeoutI/index.html b/site/cargo/em.core/em.hal/TimeoutI/index.html index c32aa33..f2bf83b 100644 --- a/site/cargo/em.core/em.hal/TimeoutI/index.html +++ b/site/cargo/em.core/em.hal/TimeoutI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/TimeoutN/index.html b/site/cargo/em.core/em.hal/TimeoutN/index.html index 6907d9a..97bd4d8 100644 --- a/site/cargo/em.core/em.hal/TimeoutN/index.html +++ b/site/cargo/em.core/em.hal/TimeoutN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/UptimerI/index.html b/site/cargo/em.core/em.hal/UptimerI/index.html index 8091606..32dba0b 100644 --- a/site/cargo/em.core/em.hal/UptimerI/index.html +++ b/site/cargo/em.core/em.hal/UptimerI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/UptimerN/index.html b/site/cargo/em.core/em.hal/UptimerN/index.html index 9e9e343..173706f 100644 --- a/site/cargo/em.core/em.hal/UptimerN/index.html +++ b/site/cargo/em.core/em.hal/UptimerN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/UsCounterI/index.html b/site/cargo/em.core/em.hal/UsCounterI/index.html index 5c62836..98dc332 100644 --- a/site/cargo/em.core/em.hal/UsCounterI/index.html +++ b/site/cargo/em.core/em.hal/UsCounterI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/UsCounterN/index.html b/site/cargo/em.core/em.hal/UsCounterN/index.html index 7a79680..c1e7a07 100644 --- a/site/cargo/em.core/em.hal/UsCounterN/index.html +++ b/site/cargo/em.core/em.hal/UsCounterN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/UsThreshI/index.html b/site/cargo/em.core/em.hal/UsThreshI/index.html index 5b1a7a6..dbaa804 100644 --- a/site/cargo/em.core/em.hal/UsThreshI/index.html +++ b/site/cargo/em.core/em.hal/UsThreshI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/WakeupTimerI/index.html b/site/cargo/em.core/em.hal/WakeupTimerI/index.html index efaa65d..7ac9a84 100644 --- a/site/cargo/em.core/em.hal/WakeupTimerI/index.html +++ b/site/cargo/em.core/em.hal/WakeupTimerI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/WakeupTimerN/index.html b/site/cargo/em.core/em.hal/WakeupTimerN/index.html index 4385cf4..eed0ddc 100644 --- a/site/cargo/em.core/em.hal/WakeupTimerN/index.html +++ b/site/cargo/em.core/em.hal/WakeupTimerN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/WatchdogI/index.html b/site/cargo/em.core/em.hal/WatchdogI/index.html index aff2c7c..736e0c5 100644 --- a/site/cargo/em.core/em.hal/WatchdogI/index.html +++ b/site/cargo/em.core/em.hal/WatchdogI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/WatchdogN/index.html b/site/cargo/em.core/em.hal/WatchdogN/index.html index f432005..c80cc7b 100644 --- a/site/cargo/em.core/em.hal/WatchdogN/index.html +++ b/site/cargo/em.core/em.hal/WatchdogN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.hal/index.html b/site/cargo/em.core/em.hal/index.html index c5836cf..ff374f0 100644 --- a/site/cargo/em.core/em.hal/index.html +++ b/site/cargo/em.core/em.hal/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/Assert/index.html b/site/cargo/em.core/em.lang/Assert/index.html index d1a3bc0..a85c453 100644 --- a/site/cargo/em.core/em.lang/Assert/index.html +++ b/site/cargo/em.core/em.lang/Assert/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/AssertProviderI/index.html b/site/cargo/em.core/em.lang/AssertProviderI/index.html index 99c560d..2492714 100644 --- a/site/cargo/em.core/em.lang/AssertProviderI/index.html +++ b/site/cargo/em.core/em.lang/AssertProviderI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/AssertProviderN/index.html b/site/cargo/em.core/em.lang/AssertProviderN/index.html index 0568e49..d6a775c 100644 --- a/site/cargo/em.core/em.lang/AssertProviderN/index.html +++ b/site/cargo/em.core/em.lang/AssertProviderN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/Atom/index.html b/site/cargo/em.core/em.lang/Atom/index.html index 2f77624..2fc993e 100644 --- a/site/cargo/em.core/em.lang/Atom/index.html +++ b/site/cargo/em.core/em.lang/Atom/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/BuildC/index.html b/site/cargo/em.core/em.lang/BuildC/index.html index 64fa441..95767ca 100644 --- a/site/cargo/em.core/em.lang/BuildC/index.html +++ b/site/cargo/em.core/em.lang/BuildC/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/BuilderI/index.html b/site/cargo/em.core/em.lang/BuilderI/index.html index 6fd0215..b8ed6e5 100644 --- a/site/cargo/em.core/em.lang/BuilderI/index.html +++ b/site/cargo/em.core/em.lang/BuilderI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/CompositeI/index.html b/site/cargo/em.core/em.lang/CompositeI/index.html index d4c983e..131c079 100644 --- a/site/cargo/em.core/em.lang/CompositeI/index.html +++ b/site/cargo/em.core/em.lang/CompositeI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/Console/index.html b/site/cargo/em.core/em.lang/Console/index.html index 74f8a7e..24692d4 100644 --- a/site/cargo/em.core/em.lang/Console/index.html +++ b/site/cargo/em.core/em.lang/Console/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/ConsoleProviderI/index.html b/site/cargo/em.core/em.lang/ConsoleProviderI/index.html index 3235556..d776b1e 100644 --- a/site/cargo/em.core/em.lang/ConsoleProviderI/index.html +++ b/site/cargo/em.core/em.lang/ConsoleProviderI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/ConsoleProviderN/index.html b/site/cargo/em.core/em.lang/ConsoleProviderN/index.html index f8ad3c1..69c2da1 100644 --- a/site/cargo/em.core/em.lang/ConsoleProviderN/index.html +++ b/site/cargo/em.core/em.lang/ConsoleProviderN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/Debug/index.html b/site/cargo/em.core/em.lang/Debug/index.html index cf3424a..5132396 100644 --- a/site/cargo/em.core/em.lang/Debug/index.html +++ b/site/cargo/em.core/em.lang/Debug/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/DebugPinI/index.html b/site/cargo/em.core/em.lang/DebugPinI/index.html index 0e87cd2..1642a5c 100644 --- a/site/cargo/em.core/em.lang/DebugPinI/index.html +++ b/site/cargo/em.core/em.lang/DebugPinI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/DebugPinN/index.html b/site/cargo/em.core/em.lang/DebugPinN/index.html index d261fea..e2c9e81 100644 --- a/site/cargo/em.core/em.lang/DebugPinN/index.html +++ b/site/cargo/em.core/em.lang/DebugPinN/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/Math/index.html b/site/cargo/em.core/em.lang/Math/index.html index f35dd01..2e9a7dc 100644 --- a/site/cargo/em.core/em.lang/Math/index.html +++ b/site/cargo/em.core/em.lang/Math/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/ModuleI/index.html b/site/cargo/em.core/em.lang/ModuleI/index.html index 472ebb9..b8879cc 100644 --- a/site/cargo/em.core/em.lang/ModuleI/index.html +++ b/site/cargo/em.core/em.lang/ModuleI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/RunC/index.html b/site/cargo/em.core/em.lang/RunC/index.html index eb8f1be..62b2694 100644 --- a/site/cargo/em.core/em.lang/RunC/index.html +++ b/site/cargo/em.core/em.lang/RunC/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/TemplateI/index.html b/site/cargo/em.core/em.lang/TemplateI/index.html index 87ff44e..f8cf28e 100644 --- a/site/cargo/em.core/em.lang/TemplateI/index.html +++ b/site/cargo/em.core/em.lang/TemplateI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.lang/index.html b/site/cargo/em.core/em.lang/index.html index d75a8f4..2c3dc0b 100644 --- a/site/cargo/em.core/em.lang/index.html +++ b/site/cargo/em.core/em.lang/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.mcu/Common/index.html b/site/cargo/em.core/em.mcu/Common/index.html index 2582f4e..57da367 100644 --- a/site/cargo/em.core/em.mcu/Common/index.html +++ b/site/cargo/em.core/em.mcu/Common/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.mcu/CommonC/index.html b/site/cargo/em.core/em.mcu/CommonC/index.html index a2b218b..a5f13b5 100644 --- a/site/cargo/em.core/em.mcu/CommonC/index.html +++ b/site/cargo/em.core/em.mcu/CommonC/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.mcu/ConsoleUart/index.html b/site/cargo/em.core/em.mcu/ConsoleUart/index.html index f2009b0..520b813 100644 --- a/site/cargo/em.core/em.mcu/ConsoleUart/index.html +++ b/site/cargo/em.core/em.mcu/ConsoleUart/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.mcu/Copier/index.html b/site/cargo/em.core/em.mcu/Copier/index.html index 245da63..276afc2 100644 --- a/site/cargo/em.core/em.mcu/Copier/index.html +++ b/site/cargo/em.core/em.mcu/Copier/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.mcu/Info/index.html b/site/cargo/em.core/em.mcu/Info/index.html index 5386308..3e4af9b 100644 --- a/site/cargo/em.core/em.mcu/Info/index.html +++ b/site/cargo/em.core/em.mcu/Info/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.mcu/Poller/index.html b/site/cargo/em.core/em.mcu/Poller/index.html index a278a4e..c627f7b 100644 --- a/site/cargo/em.core/em.mcu/Poller/index.html +++ b/site/cargo/em.core/em.mcu/Poller/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.mcu/Timeout/index.html b/site/cargo/em.core/em.mcu/Timeout/index.html index cfdbb0b..f2e1b3b 100644 --- a/site/cargo/em.core/em.mcu/Timeout/index.html +++ b/site/cargo/em.core/em.mcu/Timeout/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.mcu/index.html b/site/cargo/em.core/em.mcu/index.html index 2eec1f8..ebfc6c1 100644 --- a/site/cargo/em.core/em.mcu/index.html +++ b/site/cargo/em.core/em.mcu/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/AlarmMgr/index.html b/site/cargo/em.core/em.utils/AlarmMgr/index.html index 31739fe..5694d16 100644 --- a/site/cargo/em.core/em.utils/AlarmMgr/index.html +++ b/site/cargo/em.core/em.utils/AlarmMgr/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/AppControl/index.html b/site/cargo/em.core/em.utils/AppControl/index.html index 1420620..511ad2e 100644 --- a/site/cargo/em.core/em.utils/AppControl/index.html +++ b/site/cargo/em.core/em.utils/AppControl/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/AssertProvider/index.html b/site/cargo/em.core/em.utils/AssertProvider/index.html index 6313fbd..bbc9ae0 100644 --- a/site/cargo/em.core/em.utils/AssertProvider/index.html +++ b/site/cargo/em.core/em.utils/AssertProvider/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/BasicListManager/index.html b/site/cargo/em.core/em.utils/BasicListManager/index.html index 8687bc6..0055ed7 100644 --- a/site/cargo/em.core/em.utils/BasicListManager/index.html +++ b/site/cargo/em.core/em.utils/BasicListManager/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/BoardController/index.html b/site/cargo/em.core/em.utils/BoardController/index.html index 62664ee..02c02de 100644 --- a/site/cargo/em.core/em.utils/BoardController/index.html +++ b/site/cargo/em.core/em.utils/BoardController/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/BoardDriverI/index.html b/site/cargo/em.core/em.utils/BoardDriverI/index.html index ef290f5..05fc006 100644 --- a/site/cargo/em.core/em.utils/BoardDriverI/index.html +++ b/site/cargo/em.core/em.utils/BoardDriverI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/BoardDriversGenT/index.html b/site/cargo/em.core/em.utils/BoardDriversGenT/index.html index 5ffaa2f..f53115d 100644 --- a/site/cargo/em.core/em.utils/BoardDriversGenT/index.html +++ b/site/cargo/em.core/em.utils/BoardDriversGenT/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/BoardInfo/index.html b/site/cargo/em.core/em.utils/BoardInfo/index.html index c619740..e91692d 100644 --- a/site/cargo/em.core/em.utils/BoardInfo/index.html +++ b/site/cargo/em.core/em.utils/BoardInfo/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/BoardMeta/index.html b/site/cargo/em.core/em.utils/BoardMeta/index.html index 37c73c8..f9017b2 100644 --- a/site/cargo/em.core/em.utils/BoardMeta/index.html +++ b/site/cargo/em.core/em.utils/BoardMeta/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/Bootup/index.html b/site/cargo/em.core/em.utils/Bootup/index.html index e0fef0d..24afcc3 100644 --- a/site/cargo/em.core/em.utils/Bootup/index.html +++ b/site/cargo/em.core/em.utils/Bootup/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/BufPrint/index.html b/site/cargo/em.core/em.utils/BufPrint/index.html index 498323d..0fc8a27 100644 --- a/site/cargo/em.core/em.utils/BufPrint/index.html +++ b/site/cargo/em.core/em.utils/BufPrint/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/ButtonT/index.html b/site/cargo/em.core/em.utils/ButtonT/index.html index 378ba25..29d9c43 100644 --- a/site/cargo/em.core/em.utils/ButtonT/index.html +++ b/site/cargo/em.core/em.utils/ButtonT/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/Checksum/index.html b/site/cargo/em.core/em.utils/Checksum/index.html index bee7bfe..d9ddc56 100644 --- a/site/cargo/em.core/em.utils/Checksum/index.html +++ b/site/cargo/em.core/em.utils/Checksum/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/ConsoleProtocol/index.html b/site/cargo/em.core/em.utils/ConsoleProtocol/index.html index b09eba7..278d407 100644 --- a/site/cargo/em.core/em.utils/ConsoleProtocol/index.html +++ b/site/cargo/em.core/em.utils/ConsoleProtocol/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/Copier/index.html b/site/cargo/em.core/em.utils/Copier/index.html index 26e6f83..29689a1 100644 --- a/site/cargo/em.core/em.utils/Copier/index.html +++ b/site/cargo/em.core/em.utils/Copier/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/Crc16/index.html b/site/cargo/em.core/em.utils/Crc16/index.html index f55914b..8dd5a0d 100644 --- a/site/cargo/em.core/em.utils/Crc16/index.html +++ b/site/cargo/em.core/em.utils/Crc16/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/DebugPinAux/index.html b/site/cargo/em.core/em.utils/DebugPinAux/index.html index a9c457e..0768a5e 100644 --- a/site/cargo/em.core/em.utils/DebugPinAux/index.html +++ b/site/cargo/em.core/em.utils/DebugPinAux/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/DebugPinT/index.html b/site/cargo/em.core/em.utils/DebugPinT/index.html index f6ef83d..90618de 100644 --- a/site/cargo/em.core/em.utils/DebugPinT/index.html +++ b/site/cargo/em.core/em.utils/DebugPinT/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/EpochTime/index.html b/site/cargo/em.core/em.utils/EpochTime/index.html index 1898c9e..750cf9e 100644 --- a/site/cargo/em.core/em.utils/EpochTime/index.html +++ b/site/cargo/em.core/em.utils/EpochTime/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/Error/index.html b/site/cargo/em.core/em.utils/Error/index.html index 4ac95cf..21da1d3 100644 --- a/site/cargo/em.core/em.utils/Error/index.html +++ b/site/cargo/em.core/em.utils/Error/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/FftC32/index.html b/site/cargo/em.core/em.utils/FftC32/index.html index a4efdfa..ccd23a5 100644 --- a/site/cargo/em.core/em.utils/FftC32/index.html +++ b/site/cargo/em.core/em.utils/FftC32/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/FftQ15/index.html b/site/cargo/em.core/em.utils/FftQ15/index.html index 30222cc..c343ff4 100644 --- a/site/cargo/em.core/em.utils/FftQ15/index.html +++ b/site/cargo/em.core/em.utils/FftQ15/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/FiberMgr/index.html b/site/cargo/em.core/em.utils/FiberMgr/index.html index dfccbb0..a328b88 100644 --- a/site/cargo/em.core/em.utils/FiberMgr/index.html +++ b/site/cargo/em.core/em.utils/FiberMgr/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/Formatter/index.html b/site/cargo/em.core/em.utils/Formatter/index.html index c29a4fe..09d9f34 100644 --- a/site/cargo/em.core/em.utils/Formatter/index.html +++ b/site/cargo/em.core/em.utils/Formatter/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/FormattingConsole/index.html b/site/cargo/em.core/em.utils/FormattingConsole/index.html index f36a051..b8cf927 100644 --- a/site/cargo/em.core/em.utils/FormattingConsole/index.html +++ b/site/cargo/em.core/em.utils/FormattingConsole/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/HeapMem/index.html b/site/cargo/em.core/em.utils/HeapMem/index.html index 4880e82..c56be3f 100644 --- a/site/cargo/em.core/em.utils/HeapMem/index.html +++ b/site/cargo/em.core/em.utils/HeapMem/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/HeapStatic/index.html b/site/cargo/em.core/em.utils/HeapStatic/index.html index fabe3e7..50f4cc7 100644 --- a/site/cargo/em.core/em.utils/HeapStatic/index.html +++ b/site/cargo/em.core/em.utils/HeapStatic/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/LedBlinkerI/index.html b/site/cargo/em.core/em.utils/LedBlinkerI/index.html index 1fc4465..a75411b 100644 --- a/site/cargo/em.core/em.utils/LedBlinkerI/index.html +++ b/site/cargo/em.core/em.utils/LedBlinkerI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/LedBlinkerT/index.html b/site/cargo/em.core/em.utils/LedBlinkerT/index.html index ed26069..04e8fe1 100644 --- a/site/cargo/em.core/em.utils/LedBlinkerT/index.html +++ b/site/cargo/em.core/em.utils/LedBlinkerT/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/LedT/index.html b/site/cargo/em.core/em.utils/LedT/index.html index a8ef1cb..b2ed377 100644 --- a/site/cargo/em.core/em.utils/LedT/index.html +++ b/site/cargo/em.core/em.utils/LedT/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/ListManagerI/index.html b/site/cargo/em.core/em.utils/ListManagerI/index.html index 1926f50..0dcc4be 100644 --- a/site/cargo/em.core/em.utils/ListManagerI/index.html +++ b/site/cargo/em.core/em.utils/ListManagerI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/ListMgr/index.html b/site/cargo/em.core/em.utils/ListMgr/index.html index ea1d867..52269f4 100644 --- a/site/cargo/em.core/em.utils/ListMgr/index.html +++ b/site/cargo/em.core/em.utils/ListMgr/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/LoaderAuxI/index.html b/site/cargo/em.core/em.utils/LoaderAuxI/index.html index 3a9b711..8faf635 100644 --- a/site/cargo/em.core/em.utils/LoaderAuxI/index.html +++ b/site/cargo/em.core/em.utils/LoaderAuxI/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/Logger/index.html b/site/cargo/em.core/em.utils/Logger/index.html index d50f1ea..787a311 100644 --- a/site/cargo/em.core/em.utils/Logger/index.html +++ b/site/cargo/em.core/em.utils/Logger/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/MemDump/index.html b/site/cargo/em.core/em.utils/MemDump/index.html index ec01160..fcc7858 100644 --- a/site/cargo/em.core/em.utils/MemDump/index.html +++ b/site/cargo/em.core/em.utils/MemDump/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/MinConsole/index.html b/site/cargo/em.core/em.utils/MinConsole/index.html index a3f85f3..f00046b 100644 --- a/site/cargo/em.core/em.utils/MinConsole/index.html +++ b/site/cargo/em.core/em.utils/MinConsole/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/MsCounterUptimer/index.html b/site/cargo/em.core/em.utils/MsCounterUptimer/index.html index b997a74..e397f97 100644 --- a/site/cargo/em.core/em.utils/MsCounterUptimer/index.html +++ b/site/cargo/em.core/em.utils/MsCounterUptimer/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/PollerAux/index.html b/site/cargo/em.core/em.utils/PollerAux/index.html index 2c17a69..0e8a593 100644 --- a/site/cargo/em.core/em.utils/PollerAux/index.html +++ b/site/cargo/em.core/em.utils/PollerAux/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/ProcMgr/index.html b/site/cargo/em.core/em.utils/ProcMgr/index.html index a7185e4..ad664e0 100644 --- a/site/cargo/em.core/em.utils/ProcMgr/index.html +++ b/site/cargo/em.core/em.utils/ProcMgr/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/SoftUart/index.html b/site/cargo/em.core/em.utils/SoftUart/index.html index 5343e78..c10dd8e 100644 --- a/site/cargo/em.core/em.utils/SoftUart/index.html +++ b/site/cargo/em.core/em.utils/SoftUart/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/TickerMgr/index.html b/site/cargo/em.core/em.utils/TickerMgr/index.html index 7ae750e..6d151ee 100644 --- a/site/cargo/em.core/em.utils/TickerMgr/index.html +++ b/site/cargo/em.core/em.utils/TickerMgr/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/TimeoutAux/index.html b/site/cargo/em.core/em.utils/TimeoutAux/index.html index 7464044..9874043 100644 --- a/site/cargo/em.core/em.utils/TimeoutAux/index.html +++ b/site/cargo/em.core/em.utils/TimeoutAux/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/em.utils/index.html b/site/cargo/em.core/em.utils/index.html index b450215..dcc7d07 100644 --- a/site/cargo/em.core/em.utils/index.html +++ b/site/cargo/em.core/em.utils/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.core/index.html b/site/cargo/em.core/index.html index 72ba9a9..5734628 100644 --- a/site/cargo/em.core/index.html +++ b/site/cargo/em.core/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/Alarm1P/index.html b/site/cargo/em.docs/em.examples.basic/Alarm1P/index.html index f593a12..fcbaf98 100644 --- a/site/cargo/em.docs/em.examples.basic/Alarm1P/index.html +++ b/site/cargo/em.docs/em.examples.basic/Alarm1P/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/Alarm2P/index.html b/site/cargo/em.docs/em.examples.basic/Alarm2P/index.html index 0d4f010..8d2e03a 100644 --- a/site/cargo/em.docs/em.examples.basic/Alarm2P/index.html +++ b/site/cargo/em.docs/em.examples.basic/Alarm2P/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/BlinkerDbgP/index.html b/site/cargo/em.docs/em.examples.basic/BlinkerDbgP/index.html index 43fc968..f7fe6cd 100644 --- a/site/cargo/em.docs/em.examples.basic/BlinkerDbgP/index.html +++ b/site/cargo/em.docs/em.examples.basic/BlinkerDbgP/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/BlinkerP/index.html b/site/cargo/em.docs/em.examples.basic/BlinkerP/index.html index 8a87ee9..1d24812 100644 --- a/site/cargo/em.docs/em.examples.basic/BlinkerP/index.html +++ b/site/cargo/em.docs/em.examples.basic/BlinkerP/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/Button1P/index.html b/site/cargo/em.docs/em.examples.basic/Button1P/index.html index 26945a3..d26afe5 100644 --- a/site/cargo/em.docs/em.examples.basic/Button1P/index.html +++ b/site/cargo/em.docs/em.examples.basic/Button1P/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/Button2P/index.html b/site/cargo/em.docs/em.examples.basic/Button2P/index.html index a8839d7..79eab13 100644 --- a/site/cargo/em.docs/em.examples.basic/Button2P/index.html +++ b/site/cargo/em.docs/em.examples.basic/Button2P/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/Button3P/index.html b/site/cargo/em.docs/em.examples.basic/Button3P/index.html index 3e8e3b2..b064657 100644 --- a/site/cargo/em.docs/em.examples.basic/Button3P/index.html +++ b/site/cargo/em.docs/em.examples.basic/Button3P/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/FiberP/index.html b/site/cargo/em.docs/em.examples.basic/FiberP/index.html index c7ac4dd..c9de245 100644 --- a/site/cargo/em.docs/em.examples.basic/FiberP/index.html +++ b/site/cargo/em.docs/em.examples.basic/FiberP/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/HelloP/index.html b/site/cargo/em.docs/em.examples.basic/HelloP/index.html index c9ab5d4..26305ac 100644 --- a/site/cargo/em.docs/em.examples.basic/HelloP/index.html +++ b/site/cargo/em.docs/em.examples.basic/HelloP/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/OneShot1P/index.html b/site/cargo/em.docs/em.examples.basic/OneShot1P/index.html index 47fa8c3..f50e741 100644 --- a/site/cargo/em.docs/em.examples.basic/OneShot1P/index.html +++ b/site/cargo/em.docs/em.examples.basic/OneShot1P/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/OneShot2P/index.html b/site/cargo/em.docs/em.examples.basic/OneShot2P/index.html index 2b3ed9f..6e93eb8 100644 --- a/site/cargo/em.docs/em.examples.basic/OneShot2P/index.html +++ b/site/cargo/em.docs/em.examples.basic/OneShot2P/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/PollerP/index.html b/site/cargo/em.docs/em.examples.basic/PollerP/index.html index 18d6c1e..2da5ff5 100644 --- a/site/cargo/em.docs/em.examples.basic/PollerP/index.html +++ b/site/cargo/em.docs/em.examples.basic/PollerP/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/TickerP/index.html b/site/cargo/em.docs/em.examples.basic/TickerP/index.html index 5df81c1..71e7054 100644 --- a/site/cargo/em.docs/em.examples.basic/TickerP/index.html +++ b/site/cargo/em.docs/em.examples.basic/TickerP/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/em.examples.basic/index.html b/site/cargo/em.docs/em.examples.basic/index.html index b5d58eb..a3d100a 100644 --- a/site/cargo/em.docs/em.examples.basic/index.html +++ b/site/cargo/em.docs/em.examples.basic/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/em.docs/index.html b/site/cargo/em.docs/index.html index 5fb8e1b..9a246b3 100644 --- a/site/cargo/em.docs/index.html +++ b/site/cargo/em.docs/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/index.html b/site/cargo/index.html index fe94d14..5eca9af 100644 --- a/site/cargo/index.html +++ b/site/cargo/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/index.html b/site/cargo/ti.cc23xx/index.html index c113e2e..fa8626f 100644 --- a/site/cargo/ti.cc23xx/index.html +++ b/site/cargo/ti.cc23xx/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.build.cc23xx/GccBuilder/index.html b/site/cargo/ti.cc23xx/ti.build.cc23xx/GccBuilder/index.html index e4357a0..cbbd40a 100644 --- a/site/cargo/ti.cc23xx/ti.build.cc23xx/GccBuilder/index.html +++ b/site/cargo/ti.cc23xx/ti.build.cc23xx/GccBuilder/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.build.cc23xx/SeggerBuilder/index.html b/site/cargo/ti.cc23xx/ti.build.cc23xx/SeggerBuilder/index.html index c921940..678458a 100644 --- a/site/cargo/ti.cc23xx/ti.build.cc23xx/SeggerBuilder/index.html +++ b/site/cargo/ti.cc23xx/ti.build.cc23xx/SeggerBuilder/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.build.cc23xx/index.html b/site/cargo/ti.cc23xx/ti.build.cc23xx/index.html index 9f80236..e528f26 100644 --- a/site/cargo/ti.cc23xx/ti.build.cc23xx/index.html +++ b/site/cargo/ti.cc23xx/ti.build.cc23xx/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.distro.cc23xx/BoardC/index.html b/site/cargo/ti.cc23xx/ti.distro.cc23xx/BoardC/index.html index 1c2edca..010e060 100644 --- a/site/cargo/ti.cc23xx/ti.distro.cc23xx/BoardC/index.html +++ b/site/cargo/ti.cc23xx/ti.distro.cc23xx/BoardC/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.distro.cc23xx/BoardMeta/index.html b/site/cargo/ti.cc23xx/ti.distro.cc23xx/BoardMeta/index.html index f17c586..7239817 100644 --- a/site/cargo/ti.cc23xx/ti.distro.cc23xx/BoardMeta/index.html +++ b/site/cargo/ti.cc23xx/ti.distro.cc23xx/BoardMeta/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.distro.cc23xx/McuC/index.html b/site/cargo/ti.cc23xx/ti.distro.cc23xx/McuC/index.html index d4c1f4b..5bb0282 100644 --- a/site/cargo/ti.cc23xx/ti.distro.cc23xx/McuC/index.html +++ b/site/cargo/ti.cc23xx/ti.distro.cc23xx/McuC/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.distro.cc23xx/index.html b/site/cargo/ti.cc23xx/ti.distro.cc23xx/index.html index 8e89092..e2a528b 100644 --- a/site/cargo/ti.cc23xx/ti.distro.cc23xx/index.html +++ b/site/cargo/ti.cc23xx/ti.distro.cc23xx/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWait/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWait/index.html index cc065e1..5b93131 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWait/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWait/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWaitSysTick/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWaitSysTick/index.html index 4215bf4..ab3bd74 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWaitSysTick/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWaitSysTick/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/ConsoleUart0/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/ConsoleUart0/index.html index 92e6b86..536c284 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/ConsoleUart0/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/ConsoleUart0/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioAux/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioAux/index.html index 85bbf20..adb4067 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioAux/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioAux/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioT/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioT/index.html index 73f138f..1202546 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioT/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioT/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/ExtFlashDisabler/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/ExtFlashDisabler/index.html index 580b121..7271547 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/ExtFlashDisabler/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/ExtFlashDisabler/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/GlobalInterrupts/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/GlobalInterrupts/index.html index 7c301c5..e047e15 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/GlobalInterrupts/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/GlobalInterrupts/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/GpioT/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/GpioT/index.html index bc1f689..dc39810 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/GpioT/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/GpioT/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Idle/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Idle/index.html index 550ed93..e1c7ed7 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Idle/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Idle/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/InterruptT/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/InterruptT/index.html index b3c028a..a94d024 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/InterruptT/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/InterruptT/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/IntrVec/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/IntrVec/index.html index b0fddcb..eee3864 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/IntrVec/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/IntrVec/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Mcu/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Mcu/index.html index eb3b3bc..c39b924 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Mcu/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Mcu/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/MsCounter/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/MsCounter/index.html index cd024db..029b72f 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/MsCounter/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/MsCounter/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotGpt3/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotGpt3/index.html index dbfee8a..c3b8475 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotGpt3/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotGpt3/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTick/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTick/index.html index 7aca597..cb668da 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTick/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTick/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTim0/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTim0/index.html index dedc663..f10d901 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTim0/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTim0/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Regs/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Regs/index.html index 840dbd3..276dc61 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Regs/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Regs/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Rtc/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Rtc/index.html index ab7c9b8..9c47c6e 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Rtc/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Rtc/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Uptimer/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Uptimer/index.html index 1fb89d6..9dd304b 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Uptimer/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/Uptimer/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/UsCounter/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/UsCounter/index.html index d11b2a5..482933f 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/UsCounter/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/UsCounter/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/WakeupTimer/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/WakeupTimer/index.html index a364fe4..44c74a4 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/WakeupTimer/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/WakeupTimer/index.html @@ -862,7 +862,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/index.html b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/index.html index 14dcc84..403ece9 100644 --- a/site/cargo/ti.cc23xx/ti.mcu.cc23xx/index.html +++ b/site/cargo/ti.cc23xx/ti.mcu.cc23xx/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/discuss/index.html b/site/discuss/index.html index 7fd9ea2..7f9a644 100644 --- a/site/discuss/index.html +++ b/site/discuss/index.html @@ -864,7 +864,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/edu/index.html b/site/edu/index.html index 726ecd3..86b7a1f 100644 --- a/site/edu/index.html +++ b/site/edu/index.html @@ -858,7 +858,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/extra.css b/site/extra.css index 68e2a7c..8a00942 100644 --- a/site/extra.css +++ b/site/extra.css @@ -4,7 +4,7 @@ :root { --em-vers: "24.0.10"; - --em-time: "202401270058"; + --em-time: "202401270133"; } [data-md-color-scheme="slate"] { diff --git a/site/index.html b/site/index.html index f6b869a..bc58945 100644 --- a/site/index.html +++ b/site/index.html @@ -872,7 +872,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/install/index.html b/site/install/index.html index b93d73e..51ad6cc 100644 --- a/site/install/index.html +++ b/site/install/index.html @@ -940,7 +940,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/intro/index.html b/site/intro/index.html index 2f57919..87e9acf 100644 --- a/site/intro/index.html +++ b/site/intro/index.html @@ -866,7 +866,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/intro/to-1/index.html b/site/intro/to-1/index.html index 41ce9cb..15e4729 100644 --- a/site/intro/to-1/index.html +++ b/site/intro/to-1/index.html @@ -933,7 +933,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/intro/to-2/index.html b/site/intro/to-2/index.html index 55d2141..749a455 100644 --- a/site/intro/to-2/index.html +++ b/site/intro/to-2/index.html @@ -942,7 +942,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/intro/to-3/index.html b/site/intro/to-3/index.html index 9fc8486..f1d255b 100644 --- a/site/intro/to-3/index.html +++ b/site/intro/to-3/index.html @@ -951,7 +951,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/intro/to-4/index.html b/site/intro/to-4/index.html index 71c3e54..1426346 100644 --- a/site/intro/to-4/index.html +++ b/site/intro/to-4/index.html @@ -942,7 +942,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/porting/index.html b/site/porting/index.html index 3780b65..1bfdb21 100644 --- a/site/porting/index.html +++ b/site/porting/index.html @@ -866,7 +866,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/search/search_index.json b/site/search/search_index.json index 37eb452..7fb455a 100644 --- a/site/search/search_index.json +++ b/site/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":""},{"location":"#the-em-programming-language","title":"The EM\u2122 Programming Language","text":"

Welcome to the world of EM \u2013 a novel programming language and runtime environment targeting resource-constrained embedded systems. To increase your understanding of the language and its runtime, this site documents all aspects of the EM software platform.

If you haven't already done so, we strongly suggest starting with Introducing EM which offers a 10,000' overview of the EM language and runtime \u2013 even if you just can't wait to install the EM software and start hacking some code\u2009!!!\u00a0\u00a0 Besides rationalizing the need for EM, this overview introduces concepts as well as defines terminology used throughout the site.

Building upon this introductory overview of EM, we've then organized the remaining documents found at this site as follows:

Installing EM software and hardware required to build and run EM programs Using EM language immersion through a graduated series of portable EM examples Porting EM steps required for (re-)targeting EM to a specific HW/SW environment Advancing EM deep-dives into specific facets of the EM platform Click here to see more (less) details

We'll often insert additional commentary on the material at hand in this collapsible format, providing deeper insights into some aspect of EM. While (hopefully) insightful, feel free to skip these comments at any time.

So follow me, and let the journey begin\u2009....

"},{"location":"discuss/","title":"General comments and specific issues","text":"

In my humble opinion\u2009...

Created for the benefit of the broader embedded software community, we value your general feedback \u2013 comments, questions, ideas \u2013 about The EM Programming Language as presented throughout these documents.

To add your thoughts about EM, use the discussion forum in our em-foundation/em-sdk GitHub repository.\u00a0 You can join here\u2009, if you don't already have a GitHub account.

Just keep in mind \u2013 nothing has been decided, and everything still matters.

If you've downloaded the EM SDK and have begun coding, you can report any specific issues with the software in the same em-foundation/em-sdk repository.

"},{"location":"edu/","title":"Academia \u2013 say \"hello world\" to EM","text":"

The EM software platform comprises a novel programming language and runtime which targets resource-constrained MCUs. Originally developed in 2010, EM has evolved over the past decade through a series of commercial deployments in low-power, low-cost wireless IoT applications. To encourage broader adoption of this technology, The EM Foundation (a non-profit formed in 2023) now makes the language and its runtime openly\u2009/\u2009freely available.

While EM leverages modern software constructs like interface inheritance and component composition, novel optimization techniques employed by the underlying language translator enable EM programs to invariably outperform their hand-crafted C counterparts in terms of time and (especially) space.

Often targeting MCUs with \u2264\u200932\u2009K of memory, real-world applications \u2013 including a BLE wireless stack \u2013 can comfortably fit within these constraints.\u00a0 A 5X\u2009-\u200910X size reduction in typical embedded applications can also drive comparable savings in energy consumption as well as overall system cost.

EM \u2013 a higher-level programming language AND a higher-level of program performance

"},{"location":"edu/#conceived-in-the-university","title":"Conceived in the university","text":"

Before addressing some opportunities for academic collaboration, you should make a quick pass through Introducing EM to understand a little more about the language and its run\u00adtime. The Tiny code \u2192 Tiny chips subsection already takes us to some fertile grounds for future investigation; EM's initial engagement with the RISC-V community should also spark interest within university environments.(1)

  1. This presentation from the RISC-V Europe Summit contains further details.

While you can certainly skip the technical overivew of the language and its runtime for now, we strongly encourage you to read The history of EM subsection \u2013 and do note the seminal role played by UC Santa Barbara in the birthing and early development of EM.\u2009 In retrospect, EM would not exist today without a nuturing university environment.

"},{"location":"edu/#managing-open-source-projects","title":"Managing open-source projects","text":"

With an abundance of open-source software ranging from host tooling to target drivers (plus open-source hardware ranging from Arduino boards to RISC-V MCUs), CS/CE university programs should (in our humble opinion) arm their students with knowledge of open-source best practices \u2013 enabling them to not only participate in established projects, but also to create their own open-source initiatives which they could lead and manage.

Given that the transition of the EM technology into the open-source domain has only just begun, \"ground-floor\" opportunities await enterprising CS/CE departments motivated to assume a leadership role in the process. Said another way, The EM Foundation seeks help from universities to support its mission \u2013 promoting, sustaining, and evolving the EM programming language and runtime for use by the broader embedded systems community.

"},{"location":"edu/#areas-for-technical-contribution","title":"Areas for technical contribution","text":"

From an academic perspective, the depth\u2009/\u2009duration of potential technical contributions to EM can range from (say) a single-semester undergraduate project to multi-year graduate-level research culminating in a thesis.\u2009 Some areas of mutual interest might include:

Overall management of EM repositories housed at GitHub \u2013 coordinate the transition of existing (private) sources to public repos; introduce processes defined by open-source maturity models.

Evolution of the (command-line) EM translator plus its companion VS Code extension \u2013 relatively stable, quite compact (~12\u2009K lines of TypeScript), but with many opportunities for adding new features.

Perpetual expansion of the EM language runtime \u2013 ports to different MCUs, device drivers for sensors\u2009/\u2009controllers, wired\u2009/\u2009wireless communication stacks, machine-learning algorithms, etc.

New MCU architectures tailored for EM \u2013 take on the Tiny code \u2192 Tiny chips challenge; leverage RISC-V IP targeting FPGAs for proof-of-concept; add application-specific CPU instructions, etc.

"},{"location":"edu/#call-to-action-contact-us","title":"Call to action \u2013 contact us","text":"

If EM appears to align with the interests of your department, don't hesitate to message The EM Foundation on Linkedin with any questions you may have.

In the interim, continue to explore the material at docs.openem.org as well as read our weekly posts at blog.openem.org.

And if you really feel motivated, consider visiting Installing EM and actually downloading the EM SDK \u2013 though perhaps you'll leave this task as an \"exercise for the student\"\u2009.

"},{"location":"install/","title":"Getting started with EM","text":"

Using the EM language and its runtime requires a cross-development environment, in which hosted tooling will build\u2009/\u2009load executable EM programs onto target hardware. For the host, you'll use a PC running Windows, Linux, or MacOS(1); for the target, you can choose any MCU board for which an em$distro package already exists.

  1. MacOS support coming in 1Q24

Before turning to the EM SDK (described next), you should first install\u2009/\u2009upgrade the following tooling environments on your host PC:

Node.js version 16.3.0 or later execute node --version to verify VS Code version 1.80.0 or later execute code --version to verify Windows

If you don't already have a recent version of the Git Bash shell, you should also install Git for Windows.\u00a0 To verify your setup, ensure that the node and code commands from the previous table operate correctly under Git Bash.

Do not proceed forward if these verification checks should fail\u2009!!!

"},{"location":"install/#software-development-kit","title":"Software development kit","text":"

The EM SDK comprises two distinct components:

\u2003a VS Code extension named EM Builder with which you'll interact directly; and

\u2003a special \u00abEM-SDK\u00bb folder automatically managed by , which you can largely ignore.

Under the \u00abEM-SDK\u00bb folder you'll find a sub-folder named tools, which will contain C/C++ compilers as well as emulation utilities \u2013 all used internally by EM to build\u2009/\u2009load executable target programs.\u00a0 Already found in a well-known place on your PC(1), EM requires no further action on your part to setup these tools.

  1. \u00abEM-SDK\u00bb\u00a0=\u2002~/em-sdk
Additional artifacts

Looking inside your \u00abEM-SDK\u00bb folder, you'll also find some package*.json files as well as a node_modules sub-folder \u2013 characteristic of an npm package.\u00a0 Unless instructed otherwise, please leave these (and any other\u2009!!\u2009) artifacts housed in \u00abEM-SDK\u00bb undisturbed.

Unless instructed otherwise, do NOT disturb the contents of your \u2009\u00abEM-SDK\u00bb\u2009 folder\u2009!!!

"},{"location":"install/#target-mcu-hardware","title":"Target MCU hardware","text":"

The EM SDK will contain all of the tools required to build\u2009/\u2009load EM programs targeting any of the following boards; you won't need to download any additional, vendor-specific software.\u00a0 While we encourage you to purchase one (or more) of these boards, you can still learn a great deal about EM without target hardware \u2013 by taking the **FAST-TRACK** option.

LP-EM-CC2340R5Board #2Board #3**\u2009FAST-TRACK\u2009**

The Texas Instruments CC2340R5 wireless MCU features an Arm Cortex-M0+ CPU together with a familiar suite of peripherals \u2013 including a generic 2.4\u2009GHz radio with BLE 5.x support. Texas Instruments also offers an inexpensive LP-EM-CC2340R5 evaluation board in their familiar LaunchPad format \u2013 available from TI as well as their distributors.

You should also purchase this emulator board from TI \u2013 unless you already own a \"classic\" TI LaunchPad with on-board XDS110 support. In that case, you can easily connect this legacy LP to your new LP-EM-CC2340R5 board using a cable supplied by TI. If you haven't used an XDS110 before, run the one_time_setup script found in \u00abEM-SDK\u00bb/tools/ti-uniflash.

The ti.cc23xx distro supports the following Setups for the EM-SDK tools:

ti.cc23xx/gcc GCC 10.3, optimized for space ti.cc23xx/gcc_sram GCC 10.3, optimized for space, code\u2009+\u2009consts in SRAM ti.cc23xx/segger CLANG\u2009/\u2009LLVM 14.0, optimized for space ti.cc23xx/segger_sram CLANG\u2009/\u2009LLVM 14.0, optimized for space, code\u2009+\u2009consts in SRAM ti.cc23xx/default == ti.cc23xx/segger

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

Nothing to buy, of course\u2009!!!\u00a0 You can still build executable programs using any em$distro package within the EM SDK; you just can't load these programs onto target hardware.

Familiarize yourself, however, with the Setups available for one (or more) of the other hardware tracks enumerated above.

As we pivot to installing EM Builder, we'll soon illustrate how to select one of the Setups associated with the distros supporting these hardware options.

Which MCU board(s) would you want to see EM support\u2009???

"},{"location":"install/#em-builder-extension","title":"EM Builder extension","text":"

At this stage, we can launch VS Code and install its EM Builder extension. To begin, first create an empty folder anywhere on your PC (outside of \u00abEM-SDK\u00bb); this folder will serve as your initial VS Code workspace.

Next, enter the command code workspace to launch VS Code (where workspace represents a path to the folder created above).\u00a0 Unless you've already installed EM Builder, you'll see something like the default Welcome layout shown within the following screen capture:

Importing EM Profile

Importing EM Profile

The installation process actually begins by importing a VS Code profile named EM, which will configure a variety of user-settings as well as download the latest (stable) version of the EM Builder extension and its dependencies. To illustrate the process, watch the Importing EM Profile animation above by clicking the button atop this screen capture.

As seen in the animation, you'll use a special URL generated by VS Code to fetch the EM profile from the cloud.\u00a0 When ready, copy this URL to your clipboard and follow the same steps [\u2009Profiles\u2009>\u2009Import Profiles...\u2009] within your own installation of VS Code \u2013 pasting this URL into the input box.

https://vscode.dev/profile/github/d42fc7e6ff05708f910babc909fce416\n

If necessary, you can rewind the animation by clicking the button whenever it appears atop the screen capture.\u00a0 Hint \u2013 once playing, you should click on the animation itself to enlarge the view.

With the EM profile in place, we'll now activate the EM Builder extension for the first time as illustrated in the following animation:

Activating EM Builder

Activating EM Builder

The [\u2009Command Palette\u2009>\u2009Reload Window\u2009] sequence effectively restarts VS Code which in turn will activate EM Builder.\u2009 Always checking the status of the \u00abEM-SDK\u00bb folder, the extension will prompt you to install the EM SDK components whenever absent or outdated.(1)

  1. Things will go faster the next time you'll launch VS Code.

The EM Builder extension also requires that you select one of the Setups supported by your target MCU hardware, as the following animation will illustrate:

Selecting EM Setups

Selecting EM Setups

You should select a \"default\" configuration when the EM Setup dropdown appears \u2013 even if you've chosen the **\u2009FAST-TRACK\u2009** option for your target MCU hardware. Note that this process implicitly binds a default target board associated with your selection.

If you do plan to connect a target board, you'll also need to assign an appropriate value to the ConsolePort parameter found in the workspace local.properties file as follows:

Setting ConsolePort

Finding the actual value for the ConsolePort parameter depends, of course, on utilities specific to your PC's operating system as well as some help from your board's documentation.

In summary:

\u2003enter code workspace from the shell to launch VS Code \u2003execute the \u2009Profiles\u2009>\u2009Import Profiles...\u2009 command sequence \u2003paste the special URL given above into the input box \u2003select Create Profile and then Create when prompted \u2003execute the Developer: Reload Window command \u2003select Install... if prompted to install EM SDK components \u2003select Select... if prompted to bind EM Setups \u2003choose a \"default\" configuration from the EM Setup dropdown \u2003update the ConsolePort parameter in local.properties as appropriate"},{"location":"install/#ready-set-go","title":"Ready, Set, Go\u00a0!!!","text":"

With everything in place, the time has come to start Using EM\u2009.Happy coding\u2009!!! \u2002

"},{"location":"advancing/","title":"Deep-dive into different facets of EM","text":"

This document comprises a collection of independent articles focusing on different facets of the EM language and runtime. So pick a topic of interest and then dive right in\u2009!!!

Command-line interface Managing EM from within the shell CoreMark\u00ae Reimagined Transforming legacy C code into EM EM\u2022Mark Results Standard benchmarks for EM Energy Consumption Optimizing power over time Language Syntax Navigating EM syntax diagrams

What other aspects of EM should we tackle next\u2009???

"},{"location":"advancing/cli/","title":"Managing EM from within the shell","text":"

Under Construction \u2014 estimated completion in 1Q24 \u2009

"},{"location":"advancing/coremark/","title":"Transforming legacy C code into EM","text":"

CoreMark\u00ae has emerged as the premier industry benchmark for measuring CPU performance within embedded systems. Managed through EEMBC\u2009, virtually every MCU vendor has certified and published CoreMark scores for a broad portfolio of their processors. Running the benchmark code also serves as a \"typical workload\" used when characterizing active power consumption [\u2009\u03bcW\u2009/\u2009Mhz\u2009] of a particular MCU.

The workload introduced by CoreMark encompasses four algorithms reflecting the variety of software functions often implemented within embedded application programs:

list processing find and remove elements, generalized sorting matrix manipulation add and multiply by a scalar, vector, or matrix state machine scan a string for a variety of numeric formats cyclic redundancy check checksum over a sequence of 16\u2009/\u200932-bit values

Besides adding to the workload, CoreMark uses algorithm to validate the final results of running the benchmark program \u2013 comparing a checksum over the list elements used in algorithm against an expected value. CoreMark also checksums the matrix data produced by algorithm as well as the state machine transitions encountered by algorithm .

You'll find the CoreMark sources on GitHub, together with instructions for building\u2009/\u2009running the benchmark program. To ensure the integrity of the benchmark, you cannot modify any of its (portable) C source files \u2013 with the exception of core_portme.[ch], used to adapt CoreMark to a particular hardware platform.

Needless to say, your choice of C compiler along with specific options for controlling program optimization remain on the table. While primarily intended for comparing different MCUs, CoreMark also provides a known codebase useful for \"apples-to-apples\" comparisons between different compilers [GCC, IAR, Keil, LLVM] targeting the same MCU.

CoreMark \u2013 a \"typical\" C program in more ways than one

We sense that very few software practitioners have actually studied the CoreMark source files themselves. As long as \"someone else\" can actually port\u2009/\u2009build\u2009/\u2009run the benchmark on the MCU of interest, good enough\u2009!!

In our humble opinion, the CoreMark sources would not serve as the best textbook example of well-crafted C code:\u00a0 insufficent separation of concerns, excessive coupling among compilation units, plus other deficiencies.

Said another way, CoreMark typifies the design\u2009/\u2009implementation of much of the legacy embedded C code we've encountered for decades within industry and academia alike.\u00a0 But therein lies an opportunity to showcase EM.

"},{"location":"advancing/coremark/#coremark-emmark","title":"CoreMark \u21d2 EM\u2022Mark","text":"

In reality, none of the official CoreMark sources (written in C) will survive their transformation into EM\u2022Mark \u2013 a new codebase (re-)written entirely in EM.\u2009 At the same time, applying the same CoreMark algorithms to the same input data must yield the same results in EM.

The input data used by EM\u2022Mark (like CoreMark) ultimately derives from a handful of seed\u2009 variables, statically-initialized with prescribed values.\u2009 Declared volatile in EM as well as C, the integrity of the benchmark requires that the underlying compiler cannot know the initial values of these seed variables and potentially perform overly-aggressive code optimizations.

At the same time, the CoreMark sources do make use of C preprocessor #define directives to efficiently propogate constants and small (inline) functions during compilation.\u2009 EM\u2022Mark not only achieves the same effect automatically via whole-program optimization, but also leverages the full power of EM meta-programming to initialize internal data structures at build-time \u2013 resulting in a far-more compact program image at run-time.

If necessary, review the material on program configuration and compilation to fully appreciate the opportunities that EM affords for build-time optimization.

"},{"location":"advancing/coremark/#high-level-design","title":"High-level design","text":"

The EM\u2022Mark sources (found in the em.coremark package within the em.bench bundle) consist of ten EM modules and two EM interfaces, organized as follows:

EM\u2022Mark Design Hierarchy

The ActiveRunnerP and SleepyRunnerP programs on top of this hierarchy both execute the same core benchmark algorithms, albeit in two very different contexts:

ActiveRunnerP performs multiple\u2009 benchmark iterations, much like the legacy CoreMark program

SleepyRunnerP performs a single\u2009 benchmark iteration, awakening every second from deep-sleep

The CoreBench module (imported by both of these programs) coordinates both configuration as well as execution of the list processing, matrix manipulation, and state machine algorithms; we'll have more to say about its implementation in a little while.

To capture behavioral commonality between CoreBench and the algorithm modules it uses internally [\u2009ListBench, MatrixBench, StateBench\u2009], our EM\u2022Mark design introduces the abstract em.coremark/BenchAlgI interface:

em.coremark/BenchAlgI.em
package em.coremark\n\nimport Utils\n\ninterface BenchAlgI\n\n    config memSize: uint16\n\n    function dump()\n    function kind(): Utils.Kind\n    function print()\n    function run(arg: uarg_t = 0): Utils.sum_t\n    function setup()\n\nend\n

Of the handful of functions specified by this interface, two of these play a central role in the implementation of each benchmark algorithm:

BenchAlgI.setup, which initializes the algorithm's input data using volatile seed variables

BenchAlgI.run, which executes one pass of the benchmark algorithm and returns a CRC value

Taking a quick peek inside CoreBench, you'll notice how this module's implementation of the BenchI interface simply delegates to the other algorithm modules \u2013 which in turn implement the same interface:

em.coremark/CoreBench.em [exc]
def em$construct()\n    Utils.bindSeedH(1, 0x0)\n    Utils.bindSeedH(2, 0x0)\n    Utils.bindSeedH(3, 0x66)\nend\n\ndef dump()\n    ListBench.dump()\n    MatrixBench.dump()\n    StateBench.dump()\nend\n\ndef kind()\n    return Utils.Kind.FINAL\nend\n\ndef print()\n    ListBench.print()\n    MatrixBench.print()\n    StateBench.print()\nend\n\ndef run(arg)\n    auto crc = ListBench.run(1)\n    Utils.setCrc(Utils.Kind.FINAL, Crc.add16(<int16>crc, Utils.getCrc(Utils.Kind.FINAL)))\n    crc = ListBench.run(-1)\n    Utils.setCrc(Utils.Kind.FINAL, Crc.add16(<int16>crc, Utils.getCrc(Utils.Kind.FINAL)))\n    Utils.bindCrc(Utils.Kind.LIST, Utils.getCrc(Utils.Kind.FINAL))\n    return Utils.getCrc(Utils.Kind.FINAL)\nend\n\ndef setup()\n    ListBench.setup()\n    MatrixBench.setup()\n    StateBench.setup()\nend\n

CoreBench also uses public get\u2009/\u2009set functions provided by the Utils module to fetch\u2009/\u2009store designated CRC and seed values.

more code ahead \u2013 free free to scroll down to the Summary

Each of the benchmark algorithms will call the Crc.add16 or Crc.addU32 functions to fold a new data value into a particular checksum. Looking at the implementation of the Crc module, both of these function definitions ultimately call Crc.update \u2013 a private function that effectively mimics the crcu8 routine found in the legacy CoreMark source code:

core_util.c
ee_u16\ncrcu8(ee_u8 data, ee_u16 crc)\n{\n    ee_u8 i = 0, x16 = 0, carry = 0;\n\n    for (i = 0; i < 8; i++)\n    {\n        x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1));\n        data >>= 1;\n\n        if (x16 == 1)\n        {\n            crc ^= 0x4002;\n            carry = 1;\n        }\n        else\n            carry = 0;\n        crc >>= 1;\n        if (carry)\n            crc |= 0x8000;\n        else\n            crc &= 0x7fff;\n    }\n    return crc;\n}\n

Finally, CoreBench defines a pair of config params [\u2009TOTAL_DATA_SIZE, NUM_ALGS\u2009] used to bind the BenchAlgI.memSize parameter associated with the other algorithms; refer to CoreBench.em$configure defined here for further details.\u2009 Initialized to values tracking the legacy CoreMark code, CoreBench assigns \u230a2000/3\u230b\u2009\u2261\u2009666 bytes per algorithm.(1)

  1. We'll have more to say about CoreBench.em$configure after we explore the three benchmark algorithms in more detail.
"},{"location":"advancing/coremark/#matrix-manipulation","title":"Matrix manipulation","text":"

Pivoting to the simplest of the three benchmark algorithms administered by CoreBench, the MatrixBench module implements each (public) function specified by the BenchAlgI interface; and most of the MatrixBench private functions defined inside the module [\u2009addVal, mulVec, clip, etc\u2009] correspond to legacy C functions\u2009/\u2009macros found in core_matrix.c\u2009.

Internally, MatrixBench operates upon three matrices [\u2009matA, matB, matC\u2009] dimensioned at build-time by the module's em$construct function \u2013 which uses the BenchI.memSize parameter (bound previously in CoreBench.em$configure) when calculating a value for dimN:

em.coremark/MatrixBench.em [exc]
module MatrixBench: BenchAlgI\n\nprivate:\n\n    type matdat_t: int16\n    type matres_t: int32\n\n    config dimN: uint8\n\n    var matA: matdat_t[]\n    var matB: matdat_t[]\n    var matC: matres_t[]\n
em.coremark/MatrixBench.em [exc]
def em$construct()\n    auto i = 0\n    auto j = 0\n    while j < memSize\n        i += 1\n        j = i * i * 2 * 4\n    end\n    dimN = i - 1\n    matA.length = matB.length = matC.length = dimN * dimN\nend\n

The MatrixBench.setup function initializes \"input\" matrices [\u2009matA, matB\u2009] at run-time, using values derived from two of the volatile seed variables prescribed by legacy CoreMark:

em.coremark/MatrixBench.em [exc]
def setup()\n    auto s32 = <uint32>Utils.getSeed(1) | (<uint32>Utils.getSeed(2) << 16)\n    auto sd = <matdat_t>s32\n    sd = 1 if sd == 0\n    auto order = <matdat_t>1\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            sd = <int16>((order * sd) % 65536)\n            auto val = <matdat_t>(sd + order)\n            val = clip(val, false)\n            matB[i * dimN + j] = val\n            val += order\n            val = clip(val, true)\n            matA[i * dimN + j] = val\n            order += 1\n        end\n    end\nend\n

MatrixBench.run finally executes the benchmark algorithm itself \u2013 calling a sequence of private matrix manipulation functions and then returning a checksum that captures intermediate results of these operations:

em.coremark/MatrixBench.em [exc]
def run(arg)\n    auto crc = <Crc.sum_t>0\n    auto val = <matdat_t>arg\n    auto clipval = enlarge(val)\n    #\n    addVal(val)\n    mulVal(val)\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    mulVec()\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    mulMat()\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    mulMatBix()\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    addVal(-val)\n    return Crc.add16(<int16>crc, Utils.getCrc(Utils.Kind.FINAL))\nend\n

Once again, the [EM] implementations of private functions like addVal and mulMat track their [C] counterparts found in the CoreMark core_matrix.c source file.

"},{"location":"advancing/coremark/#state-machine","title":"State machine","text":"

The StateBench module \u2013 which also conforms to the BenchAlgI interface \u2013 scans an internal array [\u2009memBuf\u2009] for text matching a variety of numeric formats.\u2009 Similar to what we've seen in MatrixBench, the build-time em$construct function sizes memBuf as well as initializes some private config parameters used as run-time constants:

em.coremark/StateBench.em [exc]
    config intPat: string[4] = [\n        \"5012\", \"1234\", \"-874\", \"+122\"\n    ]\n    config fltPat: string[4] = [\n        \"35.54400\", \".1234500\", \"-110.700\", \"+0.64400\"\n    ]\n    config sciPat: string[4] = [\n        \"5.500e+3\", \"-.123e-2\", \"-87e+832\", \"+0.6e-12\"\n    ]\n    config errPat: string[4] = [\n        \"T0.3e-1F\", \"-T.T++Tq\", \"1T3.4e4z\", \"34.0e-T^\"\n    ]\n\n    config intPatLen: uint16\n    config fltPatLen: uint16\n    config sciPatLen: uint16\n    config errPatLen: uint16\n\n    var memBuf: char[]\n
em.coremark/StateBench.em [exc]
def em$construct()\n    memBuf.length = memSize\n    intPatLen = intPat[0].length\n    fltPatLen = fltPat[0].length\n    sciPatLen = sciPat[0].length\n    errPatLen = errPat[0].length\nend\n

The StateBench.setup function uses the xxxPat and xxxPatLen config parameters in combination with a local seed variable to initializing the memBuf characters at run-time:

em.coremark/StateBench.em [exc]
def setup()\n    auto seed = Utils.getSeed(1)\n    auto p = &memBuf[0]\n    auto total = 0\n    auto pat = \"\"\n    auto plen = 0\n    while (total + plen + 1) < (memSize - 1)\n        if plen\n            for auto i = 0; i < plen; i++\n                *p++ = pat[i]\n            end\n            *p++ = ','\n            total += plen + 1\n        end\n        switch ++seed & 0x7\n        case 0\n        case 1\n        case 2\n            pat  = intPat[(seed >> 3) & 0x3]\n            plen = intPatLen\n            break\n        case 3\n        case 4\n            pat  = fltPat[(seed >> 3) & 0x3]\n            plen = fltPatLen\n            break\n        case 5\n        case 6\n            pat  = sciPat[(seed >> 3) & 0x3]\n            plen = sciPatLen\n            break\n        case 7\n            pat  = errPat[(seed >> 3) & 0x3]\n            plen = errPatLen\n            break\n        end\n    end\nend\n

Details aside, StateBench.run calls a private scan function which in turn drives the algorithm's state machine; run also calls a private scramble function to \"corrupt\" memBuf contents ahead of the next scanning cycle:

em.coremark/StateBench.em [exc]
def run(arg)\n    arg = 0x22 if arg < 0x22\n    var finalCnt: uint32[NUM_STATES]\n    var transCnt: uint32[NUM_STATES]\n    for auto i = 0; i < NUM_STATES; i++\n        finalCnt[i] = transCnt[i] = 0\n    end\n    scan(finalCnt, transCnt)\n    scramble(Utils.getSeed(1), arg)\n    scan(finalCnt, transCnt)\n    scramble(Utils.getSeed(2), arg)\n    auto crc = Utils.getCrc(Utils.Kind.FINAL)\n    for auto i = 0; i < NUM_STATES; i++\n        crc = Crc.addU32(finalCnt[i], crc)\n        crc = Crc.addU32(transCnt[i], crc)\n    end\n    return crc\nend\n\ndef scan(finalCnt, transCnt)\n    for auto str = &memBuf[0]; *str;\n        auto state = nextState(&str, transCnt)\n        finalCnt[ord(state)] += 1\n    end\nend\n\ndef scramble(seed, step)\n    for auto str = &memBuf[0]; str < &memBuf[memSize]; str += <uint16>step\n        *str ^= <uint8>seed if *str != ','\n    end\nend\n

The crc returned by StateBench.run effectively summarizes the number of transitory and finals states encountered when scanning.

even more\u2009 code ahead \u2013 free free to scroll down to the Summary

"},{"location":"advancing/coremark/#list-processing","title":"List processing","text":"

Unlike its peer benchmark algorithms, the ListBench module introduces some new design elements into the EM\u2022Mark hierarchy depicted earlier:

the ComparatorI abstraction, used by ListBench to generalize its internal implementation of list sorting through a function-valued parameter that compares element values

the ValComparator module, an implementation of ComparatorI which invokes the other\u2009 benchmark algorithms (through a proxy) in a data-dependent fashion

The ComparatorI interface names just a single function [\u2009compare\u2009]\u2009; the ListBench module in turn specifies the signature of this function through a public type [\u2009Comparator\u2009]\u2009:\u2009(1)

  1. a design-pattern similar to a Java @FunctionalInterface annotation or a C# delegate object
em.coremark/ComparatorI.em
package em.coremark\n\nimport ListBench\n\ninterface ComparatorI\n\n    function compare: ListBench.Comparator\n\nend\n
em.coremark/ListBench.em [exc]
module ListBench: BenchAlgI\n\n    type Data: struct\n        val: int16\n        idx: int16\n    end\n\n    type Comparator: function(a: Data&, b: Data&): int32\n\n    config idxCompare: Comparator\n    config valCompare: Comparator\n

CoreBench.em$configure (which we'll examine shortly) performs build-time binding of conformant Comparator functions to the pair of ListBench config parameters declared above. But first, let's look at some private declarations within the ListBench module:

em.coremark/ListBench.em [exc]
private:\n\n    type Elem: struct\n        next: Elem&\n        data: Data&\n    end\n\n    function find(list: Elem&, data: Data&): Elem&\n    function pr(list: Elem&, name: string)\n    function remove(item: Elem&): Elem&\n    function reverse(list: Elem&): Elem&\n    function sort(list: Elem&, cmp: Comparator): Elem&\n    function unremove(removed: Elem&, modified: Elem&)\n\n    config maxElems: uint16\n\n    var curHead: Elem&\n\nend\n

The Elem struct supports the conventional representation of a singly-linked list, with the ListBench private functions manipulating references to objects of this type. The maxElems parameter effectively sizes the pool of Elem objects, while the curHead variable references a particular Elem object that presently anchors the list.

Similar to the other BenchAlgI modules we've seen, ListBench cannot fully initialize its internal data structures until setup fetches a volatile seed at run-time. Nevertheless, we still can perform a sizeable amount of build-time initialization within em$construct:

em.coremark/ListBench.em [exc]
def em$construct()\n    auto itemSize = 16 + sizeof<Data>\n    maxElems = Math.round(memSize / itemSize) - 3\n    curHead = new<Elem>\n    curHead.data = new<Data>\n    auto p = curHead\n    for auto i = 0; i < maxElems - 1; i++\n        auto q = p.next = new<Elem>\n        q.data = new<Data>\n        p = q\n    end\n    p.data = new<Data>\n    p.next = null\nend\n

Like all EM config params, maxElems behaves like a var at build-time but like a const at run-time; and the value assigned by em$construct will itself depend on other build-time parameters and variables [\u2009itemSize, memSize\u2009].\u2009 In theory, initialization of maxElem could have occurred at run-time \u2013 and with EM code that looks virtually identical to what we see here.

But by executing this EM code at build-time\u2009, we'll enjoy higher-levels of performance at run-time\u2009.

Taking this facet of EM one step further,(1)em$construct \"wires up\" a singly-linked chain of newly allocated\u2009/\u2009initialized Elem objects anchored by the curHead variable \u2013 a programming idiom you've learned in Data Structures 101\u2009.\u2009 Notice how each Elem.data field similarly references a newly-allocated (but uninitialized\u2009) Data object.

  1. that the EM language serves as its own meta-language

Turning now to ListBench.setup, the pseudo-random values assigned to each element's e.data.val and e.data.idx fields originate with one of the volatile seed variables prescribed by CoreMark.\u2009 Before returning, the private sort function (which we'll visit shortly) re-orders the list elements by comparing their e.data.idx fields:

em.coremark/ListBench.em [exc]
def setup()\n    auto seed = Utils.getSeed(1)\n    auto ki = 1\n    auto kd = maxElems - 3\n    auto e = curHead\n    e.data.idx = 0\n    e.data.val = 0x8080\n    for e = e.next; e.next; e = e.next\n        auto pat = <uint16>(seed ^ kd) & 0xf\n        auto dat = (pat << 3) | (kd & 0x7)\n        e.data.val = <int16>((dat << 8) | dat)\n        kd -= 1\n        if ki < (maxElems / 5)\n            e.data.idx = ki++\n        else\n            pat = <uint16>(seed ^ ki++)\n            e.data.idx = <int16>(0x3fff & (((ki & 0x7) << 8) | pat))\n        end\n    end\n    e.data.idx = 0x7fff\n    e.data.val = 0xffff\n    curHead = sort(curHead, idxCompare)\nend\n

Finally, the following implementation of ListBench.run calls many private functions [\u2009find, remove, reverse, \u2026\u2009] to continually rearrange the list elements; ListBench.run also uses another volatile seed as well as calls sort with two different Comparator functions:

em.coremark/ListBench.em [exc]
 def run(arg)\n    auto list = curHead\n    auto finderIdx = <int16>arg\n    auto findCnt = Utils.getSeed(3)\n    auto found = <uint16>0\n    auto missed = <uint16>0\n    auto retval = <Crc.sum_t>0\n    var data: Data\n    data.idx = finderIdx\n    for auto i = 0; i < findCnt; i++\n        data.val = <int16>(i & 0xff)\n        auto elem = find(list, data)\n        list = reverse(list)\n        if elem == null\n            missed += 1\n            retval += <uint16>(list.next.data.val >> 8) & 0x1\n        else\n            found += 1\n            if <uint16>elem.data.val & 0x1\n                retval += (<uint16>(elem.data.val >> 9)) & 0x1\n            end\n            if elem.next != null\n                auto tmp = elem.next\n                elem.next = tmp.next\n                tmp.next = list.next\n                list.next = tmp\n            end\n        end\n        data.idx += 1 if data.idx >= 0\n    end\n    retval += found * 4 - missed\n    list = sort(list, valCompare) if finderIdx > 0\n    auto remover = remove(list.next)\n    auto finder = find(list, &data)\n    finder = list.next if !finder\n    while finder\n        retval = Crc.add16(list.data.val, retval)\n        finder = finder.next\n    end\n    unremove(remover, list.next)\n    list = sort(list, idxCompare)\n    for auto e = list.next; e; e = e.next\n        retval = Crc.add16(list.data.val, retval)\n    end\n    return retval\nend\n

Refer to ListBench for the definitions of the internal functions called by ListBench.run\u2009.

"},{"location":"advancing/coremark/#generalized-sorting","title":"Generalized sorting","text":"

As already illustrated, the ListBench.sort accepts a cmp argument of type Comparator \u2013 invoked when merging Data objects from a pair of sorted sub-lists: (1)

  1. The implementation seen here (including the inline comments) mimics the core_list_mergesort function found in the legacy core_list_join.c source file.
em.coremark/ListBench.em [exc]
def sort(list, cmp)\n    auto insize = <int32>1\n    var q: Elem&\n    var e: Elem&\n    for ;;\n        auto p = list\n        auto tail = list = null\n        auto nmerges = <int32>0  # count number of merges we do in this pass\n        while p\n            nmerges++  # there exists a merge to be done\n            # step `insize' places along from p\n            q = p\n            auto psize = 0\n            for auto i = 0; i < insize; i++\n                psize++\n                q = q.next\n                break if !q\n            end\n            # if q hasn't fallen off end, we have two lists to merge\n            auto qsize = insize\n            # now we have two lists; merge them\n            while psize > 0 || (qsize > 0 && q)\n                # decide whether next element of merge comes from p or q\n                if psize == 0\n                    # p is empty; e must come from q\n                    e = q\n                    q = q.next\n                    qsize--\n                elif qsize == 0 || !q\n                    # q is empty; e must come from p.\n                    e = p\n                    p = p.next\n                    psize--\n                elif cmp(p.data, q.data) <= 0\n                    # First element of p is lower (or same); e must come from p.\n                    e = p\n                    p = p.next\n                    psize--\n                else\n                    # First element of q is lower; e must come from q.\n                    e = q\n                    q = q.next\n                    qsize--\n                end\n                # add the next element to the merged list\n                if tail\n                    tail.next = e\n                else\n                    list = e\n                end\n                tail = e\n            end\n            # now p has stepped `insize' places along, and q has too\n            p = q\n        end\n        tail.next = null\n        # If we have done only one merge, we're finished\n        break if nmerges <= 1  # allow for nmerges==0, the empty list case\n        # Otherwise repeat, merging lists twice the size\n        insize *= 2\n    end\n    return list\nend\n

Looking first at the IdxComparator module, you couldn't imagine a simpler implementation of its ComparatorI.compare function \u2013 which returns the signed difference of the idx fields after scrambling the val fields:

em.coremark/IdxComparator.em [exc]
module IdxComparator: ComparatorI\n\nend\n\ndef compare(a, b)\n    a.val = <int16>((<uint16>a.val & 0xff00) | (0x00ff & <uint16>(a.val >> 8)))\n    b.val = <int16>((<uint16>b.val & 0xff00) | (0x00ff & <uint16>(b.val >> 8)))\n    return a.idx - b.idx\nend\n

Turning now to the ValComparator module, you couldn't imagine a more convoluted\u2009 implementation of ComparatorI.compare \u2013 which returns the signed difference of values computed by the private calc function:\u2009(1)

  1. the twin of calc_func found in the legacy core_list_join.c source file
em.coremark/ValComparator.em [exc]
module ValComparator: ComparatorI\n\n    proxy Bench0: BenchAlgI\n    proxy Bench1: BenchAlgI\n\nprivate:\n\n    function calc(pval: int16*): int16\n\nend\n\ndef calc(pval)\n    auto val = <uint16>*pval\n    auto optype = <uint8>(val >> 7) & 1\n    return <int16>(val & 0x007f) if optype\n    auto flag = val & 0x7\n    auto vtype = (val >> 3) & 0xf\n    vtype |= vtype << 4\n    var ret: uint16\n    switch flag\n    case 0\n        ret = Bench0.run(<uarg_t>vtype)\n        Utils.bindCrc(Bench0.kind(), ret)\n        break\n    case 1\n        ret = Bench1.run(<uarg_t>vtype)\n        Utils.bindCrc(Bench1.kind(), ret)\n        break\n    default\n        ret = val\n        break\n    end\n    auto newcrc = Crc.add16(<int16>ret, Utils.getCrc(Utils.Kind.FINAL))\n    Utils.setCrc(Utils.Kind.FINAL, Crc.add16(<int16>ret, Utils.getCrc(Utils.Kind.FINAL)))\n    ret &= 0x007f\n    *pval = <int16>((val & 0xff00) | 0x0080 | ret)   ## cache the result\n    return <int16>ret\nend\n\ndef compare(a, b)\n    auto val1 = calc(&a.val)\n    auto val2 = calc(&b.val)\n    return val1 - val2\nend\n

Besides scrambling the contents of a val field reference passed as its argument, calc actually runs other benchmark algorithms via a pair of BenchAlgI proxies [\u2009Bench0, Bench1\u2009]\u2009.

"},{"location":"advancing/coremark/#benchmark-configuration","title":"Benchmark configuration","text":"

Having visited most of the individual modules found in the EM\u2022Mark design hierarchy, let's return to CoreBench and review its build-time configuration functions:

em.coremark/CoreBench.em [exc]
module CoreBench: BenchAlgI\n\n    config TOTAL_DATA_SIZE: uint16 = 2000\n    config NUM_ALGS: uint8 = 3\n\nend\n\ndef em$configure()\n    memSize = Math.floor(TOTAL_DATA_SIZE / NUM_ALGS)\n    ListBench.idxCompare ?= IdxComparator.compare\n    ListBench.valCompare ?= ValComparator.compare\n    ListBench.memSize ?= memSize\n    MatrixBench.memSize ?= memSize\n    StateBench.memSize ?= memSize\n    ValComparator.Bench0 ?= StateBench\n    ValComparator.Bench1 ?= MatrixBench\nend\n\ndef em$construct()\n    Utils.bindSeedH(1, 0x0)\n    Utils.bindSeedH(2, 0x0)\n    Utils.bindSeedH(3, 0x66)\nend\n

In addition to calculating and assigning the memSize config parameter for each of the benchmarks, CoreBench.em$configure binds a pair of Comparator functions to ListBench as well as binds the StateBench and MatrixBench modules to the ValComparator proxies.

CoreBench.em$construct completes build-time configuration by binding a prescribed set of values to the volatile seed variables accessed at run-time by the individual benchmarks.

"},{"location":"advancing/coremark/#summary-and-next-steps","title":"Summary and next steps","text":"

Whether you've arrived here by studying (or skipping\u2009!!) all of that EM code, let's summarize some key takeaways from the exercise of transforming CoreMark into EM\u2022Mark\u2009:

The CoreMark source code \u2013 written in C with \"plenty of room for improvement\" \u2013 typifies much of the legacy software targeting resource-constrained MCUs.

The high-level design of EM\u2022Mark (depicted here) showcases many aspects of the EM langage \u2013 separation of concerns, client-supplier decoupling, build-time configuration, etc.

The ActiveRunnerP and SleepyRunnerP programs can run on any\u2009 MCU for which an em$distro package exists \u2013 making EM\u2022Mark ideal for benchmarking MCU performance.

Besides embodying a higher-level of programming, EM\u2022Mark also outperforms\u2009 legacy CoreMark.

To prove our claim about programming in EM, let's move on to the EM\u2022Mark results and allow the numbers to speak for themselves.

"},{"location":"advancing/emmark/","title":"Standard benchmarks for EM","text":"

Armed with an understanding of the CoreMark \u21d2 EM\u2022Mark transformation, you'll further appreciate the significance of the EM benchmarks presented below. While CoreMark focuses heavily on measuring CPU performance, EM\u2022Mark takes a more balanced approach that also considers program image size, active power consumption, and overall energy efficiency.

With an emphasis on maximizing execution time, CoreMark programs overwhelmingly employ the most aggressive \"optimize-for-speed\" options when compiling the benchmark sources for a particular MCU \u2013 resulting in excessively large program images.

By way of contrast, EM\u2022Mark starts from the premise that minimizing program size when targeting resource-constrained MCUs trumps other performance factors.\u00a0 Said another way, most embedded firmware developers in practice will usually choose the most aggressive \"optimize-for-size\" option when compiling their code.

LP-EM-CC2340R5Board #2Board #3

Texas Instruments reports a score of 2.1 CoreMarks\u2009/\u2009MHz for their CC2340R5 wireless MCU, which features a 48\u2009MHz Cortex-M0+ CPU.\u00a0 TI used the IAR C/C++ compiler [\u2009v9.32.2\u2009] to generate an ~18\u2009K program image, optimized for high-speed with no size constraints.

The legacy CoreMark results we'll report below used TI's LLVM-based Arm compiler [\u2009v2.1.3\u2009] with its \"optimize-for-size\" [\u2009-Oz\u2009] option. To satisfy our curiousity, building the same Core\u00adMark program using the compiler's \"optimize-for-speed\" [\u2009-Os\u2009] option yielded comparable results to those reported with IAR.\u2009(1)

  1. We'll leave adding GCC into the mix as an exercise for the reader; suffice it to say the GCC does not\u2009 win the race\u2009!!

All of the EM\u2022Mark results reported below use the ti.cc23xx distro bundle delivered with the EM-SDK plus the following pair of Setups when building program images:\u2009(1)

  1. Here, too, we'll leave experimentation with GCC-based Setups available for this target hardware as an extra-credit project.
ti.cc23xx/segger CLANG\u2009/\u2009LLVM 14.0, optimized for space, code\u2009+\u2009consts in Flash ti.cc23xx/segger_sram CLANG\u2009/\u2009LLVM 14.0, optimized for space, code\u2009+\u2009consts in SRAM

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

"},{"location":"advancing/emmark/#program-size","title":"Program size","text":"

Much like the legacy CoreMark C code, the ActiveRunnerP EM program performs multiple iterations of the benchmark algorithms and displays results when finished:

em.coremark/ActiveRunnerP.em
package em.coremark\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.mcu import Common\n\nimport CoreBench\nimport Utils\n\nmodule ActiveRunnerP\n\n    config ITERATIONS: uint16 = 10\n\nend\n\ndef em$startup()\n    CoreBench.setup()\nend\n\ndef em$run()\n    AppLed.on()\n    Common.BusyWait.wait(250000)\n    AppLed.off()\n    Common.UsCounter.start()\n    %%[d+]\n    for auto i = 0; i < ITERATIONS; i++\n        CoreBench.run()\n    end\n    %%[d-]\n    auto usecs = Common.UsCounter.stop()\n    AppLed.on()\n    Common.BusyWait.wait(250000)\n    AppLed.off()\n    printf \"usecs = %d\\n\", usecs\n    printf \"list crc = %04x\\n\", Utils.getCrc(Utils.Kind.LIST)\n    printf \"matrix crc = %04x\\n\", Utils.getCrc(Utils.Kind.MATRIX)\n    printf \"state crc = %04x\\n\", Utils.getCrc(Utils.Kind.STATE)\n    printf \"final crc = %04x\\n\", Utils.getCrc(Utils.Kind.FINAL)\nend\n

Recalling the central role played by the CoreBench module in the EM\u2022Mark high-level design, the implementation of its setup and run functions dominate the code\u2009/\u2009data sizes of the ActiveRunnerP program image:

LP-EM-CC2340R5Board #2Board #3

EM\u2022Mark Image Size

By way of comparison, the legacy CoreMark program built with TI's compiler weighs in with the following image size:

text (8798) const (3777) data (286) bss (2372)

CoreMark Image Size

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

"},{"location":"advancing/emmark/#execution-time","title":"Execution time","text":"

We've used a Saleae Logic Analyzer to capture logic traces of the legacy CoreMark and ActiveRunnerP programs executing ten iterations of the benchmark. To help measure execution time, both programs blink appLed for 250\u2009ms before\u2009/\u2009after the main benchmark loop:

LP-EM-CC2340R5Board #2Board #3

Legacy Logic Capture \u2013 Flash

ActiveRunnerP Logic Capture \u2013 Flash

ActiveRunnerP Logic Capture \u2013 SRAM

CoreMark text\u2009+\u2009const [\u2009Flash\u2009] 176\u2009ms EM\u2022Mark text\u2009+\u2009const [\u2009Flash\u2009] 151\u2009ms EM\u2022Mark text\u2009+\u2009const [\u2009SRAM\u2009] 124\u2009ms

Execution Times \u2013 Summary

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

"},{"location":"advancing/emmark/#active-power","title":"Active power","text":"

We've used a Joulescope JS220 to capture power profiles of legacy CoreMark and ActiveRunnerP executing ten iterations of the benchmark. To help measure power consumption, both programs blink appLed for 250\u2009ms before\u2009/\u2009after the main benchmark loop:

LP-EM-CC2340R5Board #2Board #3

Legacy Power Capture \u2013 Flash

ActiveRunnerP Power Capture \u2013 Flash

ActiveRunnerP Power Capture \u2013 SRAM

CoreMark text\u2009+\u2009const [\u2009Flash\u2009] 1.368\u2009mJ EM\u2022Mark text\u2009+\u2009const [\u2009Flash\u2009] 1.034\u2009mJ EM\u2022Mark text\u2009+\u2009const [\u2009SRAM\u2009] 0.634\u2009mJ

Execution Times \u2013 Summary

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

"},{"location":"advancing/emmark/#energy-efficiency","title":"Energy efficiency","text":"

Applications targeting resource-constrained (ultra-low-power) MCUs often spend most of their time in deep-sleep \u2013 awakening at rates from once-per-second down to once-per-day, and actively executing for time windows measured in just milliseconds.

The CPU-centric nature of legacy CoreMark (and hence ActiveRunnerP) doesn't necessarily reflect \"real-world\" duty-cycled applications targeting ULP MCUs, where maximizing energy efficiency becomes paramount.

ULPMark\u00ae benchmark suite

In addition to legacy CoreMark, the EEMBC organization offers ULPMark \u2013 a benchmark suite that quantifies many aspects of ultra-low-power MCUs. One of the profiles in the suite in fact measures active power consumption, using CoreMark as the workload; other profiles quantify the true energy cost of deep-sleep.

Unlike CoreMark, however, ULPMark requires a paid license to access its source code \u2014 an obstacle for purely inquisitive engineers working with ULP MCUs.\u2009 EM\u2022Mark attempts to fill this niche with a complementary pair of portable programs for benchmarking code size and execution time, as well as power consumption.

To that end, EM\u2022Mark also incorporates the SleepyRunnerP program \u2013 which executes the same underlying benchmark algorithms as ActiveRunnerP, but in a very different setting:

em.coremark/SleepyRunnerP.em
package em.coremark\n\nfrom em$distro import BoardC\n\nfrom em.utils import FiberMgr\nfrom em.utils import TickerMgr\n\nimport CoreBench\n\nmodule SleepyRunnerP\n\nprivate:\n\n    var ticker: TickerMgr.Ticker&\n\n    var count: uint8 = 10\n\n    function tickCb: TickerMgr.TickCallback\n\nend\n\ndef em$construct()\n    ticker = TickerMgr.createH()\nend\n\ndef em$startup()\n    CoreBench.setup()\nend\n\ndef em$run()\n    ticker.start(256, tickCb)\n    FiberMgr.run()\nend\n\ndef tickCb()\n    %%[d+]\n    auto crc = CoreBench.run()\n    %%[d-]\n    printf \"crc = %04x\\n\", crc\n    return if --count\n    ticker.stop()\n    halt\nend\n

Here too, SleepyRunnerP calls CoreBench.setup at startup; but instead of the \"main loop\" seen earlier in ActiveRunnerP, we now make a single\u2009 call to CoreBench.run just once-per-second. Relying only on modules found in the em.core bundle [\u2009FiberMgr, TickerMgr\u2009], SleepyRunnerP can execute on any target MCU for which an em$distro package exists.\u2009(1)

  1. Review the material in Tour 12 \u2013 cyclic tickers if necessary

The following sets of Saleae logic-captures first show SleepyRunner awakening once-per-second, and then zoom-in to view the execution time of a single active cycle:

LP-EM-CC2340R5Board #2Board #3

SleepRunnerP Logic Capture \u2013 SRAM

SleepRunnerP Logic Capture \u2013 SRAM\u2002[\u2009zoom\u2009]

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

Note that measurement M0 reflects the total active time as framed by dbgB (managed automatically by EM), whereas measurement M1 reflects the actual benchmark interval between the dbgD toggles seen earlier in SleepyRunnerP.\u2009 Also note that the latter measurement does not\u2009 include the time to format\u2009/\u2009output the \"crc = 72be\\n\" character string.

The following sets of Joulescope power-captures report the total amount of energy consumed over a one-second interval, as well as the amount of energy consumed when the SleepyRunnerP program awakens and executes a single iteration of the benchmark:

LP-EM-CC2340R5Board #2Board #3

SleepRunnerP Power Capture \u2013 SRAM

SleepRunnerP Power Capture \u2013 SRAM\u2002[\u2009zoom\u2009]

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

As expected, a single call to the CoreBench.run function takes only milliseconds to execute and yet consumes most of the energy over the one-second cycle.

"},{"location":"advancing/emmark/#general-observations","title":"General observations","text":"

Improvements in EM\u2022Mark program size and execution time compared with legacy CoreMark hopefully supports EM's claim of higher-level programming and higher-levels of performance\u2009.

Building EM\u2022Mark with the most aggressive \"optimize-for-size\" options passed to the underlying C/C++ compiler reflects the reality of targeting resource-constrained MCUs.

Placing runtime code and constants into SRAM (versus Flash) not only improves execution time but also reduces active power consumption \u2014 a corrolary of optimizing for program size.

While ActiveRunnerP maintains the same focus as legacy CoreMark (inviting side-by-side comparison), the SleepyRunnerP benchmark more accurately quantifies the energy efficiency of ULP MCUs.

"},{"location":"advancing/energy/","title":"Optimizing power over time","text":"

We put forth a rather bold proposition in Using EM:\u2003 If you can't see the problem, you can't fix it\u2009!!!\u00a0 As we toured the EM runtime, logic captures for each example program gave you an important perspective \u2013 that of program state over the course of time. Informally termed \"real-time debug\", this kind of logic trace proves invaluable to both quantify program execution time at sub-\u03bcs resolution, as well as to verify proper sequencing of program execution.

This article expands this proposition into the domain of energy consumption \u2013 by now tracing MCU power over the course of time. With many resource-constrained MCUs targeting always-on applications that run using batteries and\u2009/\u2009or harvested energy, power profiles captured by a precision energy analyzer nicely complement the \"real-time debug\" traces captured by a logic-state analyzer.

Until recently, the cost of a high-quality energy analyzer would often exceed $10,000 \u2013 far beyond most of our budgets. The recent arrival of the Joulescope JS220 precision analyzer does, however, afford order-of-magnitude relief on pricing. And the STM32 Power Shield offers an even more affordable option at <\u2009$100.

Help wanted \u2013 someone familiar with the STM32 Power Shield

For now, though, we'll stick with the Joulescope JS220 as our energy analyzer. And even if you don't own a JS220, we recommend downloading the (free) Joulescope UI software as well as the original power capture files presented throughout this article.

"},{"location":"advancing/energy/#mcu-power-modes","title":"Mcu power modes","text":"

The Tour 10 \u2013 Logic Capture seen here in Using EM introduced the terms \"lite-sleep\" and \"deep-sleep\" corresponding to distinct marks on dbgB. Recalling the Alarm1P example, this program enters the MCU's deep-sleep mode %%[b:2] after calling alarm.wakeup. But after calling AppLed.wink \u2013 which internally pauses execution for a much shorter period of time \u2013 the program instead enters the MCU's lite-sleep mode %%[b:1].

While each vendor often has their own jargon for these power modes (IDLE, PAUSE, SLEEP, STOP, SUSPEND, \u2026\u2009), we'll uniformally use the following terminology when measuring power across different MCUs supported by EM:

ACTIVE CPU core running \u2013 MCU peripherals powered on when needed by CPU PAUSE CPU core idling \u2013 MCU peripherals powered on when needed for CPU wakeup SLEEP CPU + most peripherals powered off \u2013 wakeup via special \"always-on\" peripherals HIBERNATE entire MCU powered off \u2013 CPU \"reset\" interrupt triggered by external HW devices only

As application software transitions amongst these modes, the power required to operate the MCU can range from milliwatts [ACTIVE] to microwatts [SLEEP] \u2013 and even down to nanowatts [HIBERNATE] if the application wishes to suspend execution indefintely.

To quantify these MCU power modes on your target board, we'll use the Button3P program highlighted in Tour\u200906 to obtain these readings. The Button3P Power Capture image below marks four distinct points during program execution, where we'll use the JS220 to measure the amperage instanteneously drawn by the MCU.

\u00a0 We've pressed appBut for almost 4\u2009s, with the program testing appBut every 100\u2009ms. [PAUSE]

\u00a0 Crossing the 4\u2009s threshold, the program now blinks sysLed for 40\u2009ms using a busy-wait loop. [ACTIVE]

\u00a0 The program sleeps until the next button event, even though appBut itself remains pressed. [SLEEP]

\u00a0 With the button now released, the program remains asleep while drawing even less current. [SLEEP]

LP-EM-CC2340R5Board #2Board #3

Button3P Power Capture

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

Because the JS200 samples at a relatively slow 1\u2009MHz rate (compared with the CPU clock), the capture around marker shows a series of ripples spaced 100\u2009ms apart which in fact correspond to very brief CPU wakeups from PAUSE to sample appBut; a similar train of blips occurs around markers and , which here represent an internal duty-cycled recharge of the MCU's DC/DC converter or LDO regulator.

By in large, these current measurements align with specifications found in the MCU vendor's datasheet. Do note, however, that the ACTIVE reading recorded at marker includes current drawn by the board's LED as well as the CPU itself.

"},{"location":"advancing/energy/#measuring-energy","title":"Measuring energy","text":"

While important, MCU power specifications such as [SLEEP = 1.5 \u03bcA] or even more generalized forms such as [ACTIVE = 53 \u03bcA / MHz] say absolutely nothing about the overall energy efficiency of an ultra-low-power embedded system built around this particular MCU. To gain this perspective, we must simultaneously consider the software running on the MCU and answer critical questions such as:

Once awakened, how quickly can our application software go back to sleep\u2009?!?!

By knowing the amount of time a program spends in the various MCU power modes, we can begin to quantify the overall energy efficiency of an embedded system. To illustrate the methodology we'll apply to measure energy consumption, consider the following JS220 capture of the Alarm1P example, which complements the logic capture found here:

LP-EM-CC2340R5Board #2Board #3

Alarm1P Power Capture \u2013 Flash

EM Setup:\u00a0ti.cc23xx/segger_default

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

Alarm1P spends the majority of its time in SLEEP, typical of many embedded applications.

\u00a0 Once ACTIVE, the program calls AppLed.wink and then enters PAUSE mode for 100\u2009ms;

\u00a0 awoken from PAUSE, the program calls alarm.wakeup and moves from ACTIVE to SLEEP mode.

\u00a0 The energy (in millijoules) consumed during this 100+\u2009ms SLEEP\u2009-\u2009ACTIVE\u2009-\u2009PAUSE\u2009-\u2009ACTIVE\u2009-\u2009SLEEP interval.

\u00a0 The energy (in millijoules) consumed over an arbitrary 10\u2009s interval encompassing six wakeups from SLEEP.

While time intervals and differ by a factor of 100, the total energy [\u2009mJ\u2009] consumed over these intervals differ by only a factor of \u2248\u20096. Needless to say, decreasing the number of wakeups over a given timeframe will always improve overall energy efficiency. Often, though, application requirements will dictate the frequency of these wakeup intervals \u2013 as high as once per second in many embedded systems.

"},{"location":"advancing/energy/#less-code-less-energy","title":"Less code, less energy","text":"

Introducing EM hypothesized that reducing code size could have a potentially dramatic impact on the size, power, and cost of future MCU silicon. Focusing on the dimension of power for now \u2013 and targeting legacy MCUs \u2013 we can already quantify the relationship between \"less code\" and \"less energy\".

Needless to say, minimizing the number of CPU instructions executed while ACTIVE will only reduce overall energy consumption \u2013 assuming our software still meets a given set of application requirements. With its uncanny ability to reduce code size, the EM language and runtime should benchmark quite favorably against more conventional C/C++ RTOS platforms such as Zephyr.

Help wanted \u2013 embedded programmer familiar with Zephyr

Setting aside the larger \"EM vs C/C++\" discussion for now, we'll focus instead on a very effective technique for reducing energy consumption using the same Alarm1P program executing on the same target MCU board.\u00a0 Quite simply, the EM runtime will automatically copy the\u2009.text and\u2009.const program sections into fast, on-chip SRAM at startup \u2013 rather than leaving this readonly code\u2009+\u2009data in Flash memory, where they conventionally reside.

To quantify the impact of this change, compare the following Alarm1P Power Capture with our earlier baseline \u2013 paying close attention to the total energy [\u2009mJ\u2009] consumed at intervals and in each capture.

LP-EM-CC2340R5Board #2Board #3

Alarm1P Power Capture \u2013 SRAM

EM Setup:\u00a0ti.cc23xx/segger_sram

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

While we do see a modest 10% gain in energy efficiency here, don't forget that the Alarm1P program actually fetches very few instructions \u2013 with the MCU remaining in a (lower-power) PAUSE mode for most of interval .\u00a0 Imagine, though, a duty-cycled \"sleepy\" application that executes a non-trivial mix of math functions and control code when ACTIVE:\u00a0 significant improvements during interval would also lower overall energy consumption reported at .

With modern MCUs clocked at \u2248\u200950\u2009-\u2009150\u2009MHz\u2009, these architectures invariably employ a HW cache to mitigate wait-states which would otherwise stall the CPU when fetching instructions or constants directly from slower flash memory. But SRAM has no such limitations, as this class of memory can easily sustain read rates in excess of 500\u2009MHz\u2009. The CPU hence runs at maximum efficiency, allowing the application to re-enter SLEEP that much sooner.

Assuming the program image can actually fit within SRAM \u2013 a far more scarce resource than flash \u2013 the EM distro for your target MCU board can actually disable the flash memory and its HW cache during em$startup to further reduce ambient power. Paradoxically, running the CPU at its highest possible clock rate will often decrease overall energy consumption when executing \u2013 again, by minimizing the amount of time spent in the ACTIVE mode.

In the future, we'll have additional articles under Advancing EM that benchmark more sophisticated EM applications that nevertheless can execute entirely from on-chip SRAM.\u00a0 In the meanwhile, ponder the following question:

Knowing EM applications need only a small SRAM to run, how might we architect future MCUs\u2009???

"},{"location":"advancing/syntax/","title":"Navigating EM syntax diagrams","text":"

The following \"railroad track\" diagram captures the complete syntax of EM. Automatically generated from the actual grammar used by the language translator, you can click on any of the blue rectangles (such as Unit or Decl) and navigate to the definition of these non-terminal elements; the cyan ovals represent terminal tokens scanned by an underlying lexer.

Hint

To quickly jump to the major sections of the grammar, click through the blue non-terminals within the special definitions at the top of the diagram [\u2009$start, Decl_$, Expr_$, Stmt_$, Type_$\u2009]\u2009.

Your browser will not maintain history as you navigate through this diagram. To save time scrolling back to the top of diagram, simply click on the Language Syntax link to reload the entire window.

"},{"location":"cargo/","title":"Index","text":""},{"location":"cargo/#em-bundles","title":"EM bundles","text":""},{"location":"cargo/em.bench/","title":"Index","text":""},{"location":"cargo/em.bench/#bundle-embench","title":"bundle em.bench","text":""},{"location":"cargo/em.bench/em.coremark/","title":"Index","text":""},{"location":"cargo/em.bench/em.coremark/#package-emcoremark","title":"package em.coremark","text":""},{"location":"cargo/em.bench/em.coremark/ActiveRunnerP/","title":"ActiveRunnerP","text":""},{"location":"cargo/em.bench/em.coremark/ActiveRunnerP/#unit-activerunnerp","title":"unit ActiveRunnerP","text":"em.coremark/ActiveRunnerP.em
package em.coremark\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.mcu import Common\n\nimport CoreBench\nimport Utils\n\nmodule ActiveRunnerP\n\n    config ITERATIONS: uint16 = 10\n\nend\n\ndef em$startup()\n    CoreBench.setup()\nend\n\ndef em$run()\n    AppLed.on()\n    Common.BusyWait.wait(250000)\n    AppLed.off()\n    Common.UsCounter.start()\n    %%[d+]\n    for auto i = 0; i < ITERATIONS; i++\n        CoreBench.run()\n    end\n    %%[d-]\n    auto usecs = Common.UsCounter.stop()\n    AppLed.on()\n    Common.BusyWait.wait(250000)\n    AppLed.off()\n    printf \"usecs = %d\\n\", usecs\n    printf \"list crc = %04x\\n\", Utils.getCrc(Utils.Kind.LIST)\n    printf \"matrix crc = %04x\\n\", Utils.getCrc(Utils.Kind.MATRIX)\n    printf \"state crc = %04x\\n\", Utils.getCrc(Utils.Kind.STATE)\n    printf \"final crc = %04x\\n\", Utils.getCrc(Utils.Kind.FINAL)\nend\n
"},{"location":"cargo/em.bench/em.coremark/BenchAlgI/","title":"BenchAlgI","text":""},{"location":"cargo/em.bench/em.coremark/BenchAlgI/#unit-benchalgi","title":"unit BenchAlgI","text":"em.coremark/BenchAlgI.em
package em.coremark\n\nimport Utils\n\ninterface BenchAlgI\n\n    config memSize: uint16\n\n    function dump()\n    function kind(): Utils.Kind\n    function print()\n    function run(arg: uarg_t = 0): Utils.sum_t\n    function setup()\n\nend\n
"},{"location":"cargo/em.bench/em.coremark/ComparatorI/","title":"ComparatorI","text":""},{"location":"cargo/em.bench/em.coremark/ComparatorI/#unit-comparatori","title":"unit ComparatorI","text":"em.coremark/ComparatorI.em
package em.coremark\n\nimport ListBench\n\ninterface ComparatorI\n\n    function compare: ListBench.Comparator\n\nend\n
"},{"location":"cargo/em.bench/em.coremark/CoreBench/","title":"CoreBench","text":""},{"location":"cargo/em.bench/em.coremark/CoreBench/#unit-corebench","title":"unit CoreBench","text":"em.coremark/CoreBench.em
package em.coremark\n\nfrom em.lang import Math\n\nimport BenchAlgI\nimport Crc\nimport ListBench\nimport IdxComparator\nimport MatrixBench\nimport StateBench\nimport Utils\nimport ValComparator\n\nmodule CoreBench: BenchAlgI\n\n    config TOTAL_DATA_SIZE: uint16 = 2000\n    config NUM_ALGS: uint8 = 3\n\nend\n\ndef em$configure()\n    memSize = Math.floor(TOTAL_DATA_SIZE / NUM_ALGS)\n    ListBench.idxCompare ?= IdxComparator.compare\n    ListBench.valCompare ?= ValComparator.compare\n    ListBench.memSize ?= memSize\n    MatrixBench.memSize ?= memSize\n    StateBench.memSize ?= memSize\n    ValComparator.Bench0 ?= StateBench\n    ValComparator.Bench1 ?= MatrixBench\nend\n\ndef em$construct()\n    Utils.bindSeedH(1, 0x0)\n    Utils.bindSeedH(2, 0x0)\n    Utils.bindSeedH(3, 0x66)\nend\n\ndef dump()\n    ListBench.dump()\n    MatrixBench.dump()\n    StateBench.dump()\nend\n\ndef kind()\n    return Utils.Kind.FINAL\nend\n\ndef print()\n    ListBench.print()\n    MatrixBench.print()\n    StateBench.print()\nend\n\ndef run(arg)\n    auto crc = ListBench.run(1)\n    Utils.setCrc(Utils.Kind.FINAL, Crc.add16(<int16>crc, Utils.getCrc(Utils.Kind.FINAL)))\n    crc = ListBench.run(-1)\n    Utils.setCrc(Utils.Kind.FINAL, Crc.add16(<int16>crc, Utils.getCrc(Utils.Kind.FINAL)))\n    Utils.bindCrc(Utils.Kind.LIST, Utils.getCrc(Utils.Kind.FINAL))\n    return Utils.getCrc(Utils.Kind.FINAL)\nend\n\ndef setup()\n    ListBench.setup()\n    MatrixBench.setup()\n    StateBench.setup()\nend\n
"},{"location":"cargo/em.bench/em.coremark/Crc/","title":"Crc","text":""},{"location":"cargo/em.bench/em.coremark/Crc/#unit-crc","title":"unit Crc","text":"em.coremark/Crc.em
package em.coremark\n\nimport Utils\n\nmodule Crc\n\n    type sum_t: Utils.sum_t\n\n    function add16(val: int16, crc: sum_t): sum_t\n    function addU32(val: uint32, crc: sum_t): sum_t\n\nprivate:\n\n    function update(data: uint8, crc: sum_t): sum_t\n\nend\n\ndef add16(val, crc)\n    auto v = <uint16>val\n    crc = update(<uint8>v, crc)\n    crc = update(<uint8>(v >> 8), crc)\n    return crc\nend\n\ndef addU32(val, crc)\n    crc = add16(<int16>val, crc)\n    crc = add16(<int16>(val >> 16), crc)\n    return crc\nend\n\ndef update(data, crc)\n    auto i = <uint8>0\n    auto x16 = <uint8>0\n    auto carry = <uint8>0\n    for auto i = 0; i < 8; i++\n        x16 = <uint8>((data & 1) ^ (<uint8>crc & 1))\n        data >>= 1\n        if x16 == 1\n            crc ^= 0x4002\n            carry = 1\n        else\n            carry = 0\n        end\n        crc >>= 1\n        if carry\n            crc |= 0x8000\n        else\n            crc &= 0x7fff\n        end\n    end\n    return crc\nend\n
"},{"location":"cargo/em.bench/em.coremark/IdxComparator/","title":"IdxComparator","text":""},{"location":"cargo/em.bench/em.coremark/IdxComparator/#unit-idxcomparator","title":"unit IdxComparator","text":"em.coremark/IdxComparator.em
package em.coremark\n\nimport ComparatorI\n\nmodule IdxComparator: ComparatorI\n\nend\n\ndef compare(a, b)\n    a.val = <int16>((<uint16>a.val & 0xff00) | (0x00ff & <uint16>(a.val >> 8)))\n    b.val = <int16>((<uint16>b.val & 0xff00) | (0x00ff & <uint16>(b.val >> 8)))\n    return a.idx - b.idx\nend\n
"},{"location":"cargo/em.bench/em.coremark/ListBench/","title":"ListBench","text":""},{"location":"cargo/em.bench/em.coremark/ListBench/#unit-listbench","title":"unit ListBench","text":"em.coremark/ListBench.em
package em.coremark\n\nfrom em.lang import Math\n\nimport BenchAlgI\nimport Crc\nimport Utils\n\n# patterned after core_list_join.c\n\nmodule ListBench: BenchAlgI\n\n    type Data: struct\n        val: int16\n        idx: int16\n    end\n\n    type Comparator: function(a: Data&, b: Data&): int32\n\n    config idxCompare: Comparator\n    config valCompare: Comparator\n\nprivate:\n\n    type Elem: struct\n        next: Elem&\n        data: Data&\n    end\n\n    function find(list: Elem&, data: Data&): Elem&\n    function pr(list: Elem&, name: string)\n    function remove(item: Elem&): Elem&\n    function reverse(list: Elem&): Elem&\n    function sort(list: Elem&, cmp: Comparator): Elem&\n    function unremove(removed: Elem&, modified: Elem&)\n\n    config maxElems: uint16\n\n    var curHead: Elem&\n\nend\n\ndef em$construct()\n    auto itemSize = 16 + sizeof<Data>\n    maxElems = Math.round(memSize / itemSize) - 3\n    curHead = new<Elem>\n    curHead.data = new<Data>\n    auto p = curHead\n    for auto i = 0; i < maxElems - 1; i++\n        auto q = p.next = new<Elem>\n        q.data = new<Data>\n        p = q\n    end\n    p.data = new<Data>\n    p.next = null\nend\n\ndef dump()\n    for auto e = curHead; e; e = e.next\n        %%[a+]\n        %%[>e.data.idx]\n        %%[>e.data.val]\n        %%[a-]\n    end\nend\n\ndef find(list, data)\n    auto elem = list\n    if data.idx >= 0\n        while elem && elem.data.idx != data.idx\n            elem = elem.next\n        end\n    else\n        while elem && <int16>(<uint16>elem.data.val & 0xff) != data.val\n            elem = elem.next\n        end\n    end\n    return elem\nend\n\ndef kind()\n    return Utils.Kind.LIST\nend\n\ndef pr(list, name)\n    auto sz = 0\n    printf \"%s\\n[\", name\n    for auto e = list; e; e = e.next\n        auto pre = (sz++ % 8) == 0 ? \"\\n    \" : \"\"\n        printf \"%s(%04x,%04x)\", <iarg_t>pre, e.data.idx, e.data.val\n    end\n    printf \"\\n], size = %d\\n\", sz\nend\n\ndef print()\n    pr(curHead, \"current\")\nend\n\ndef remove(item)\n    auto ret = item.next\n    auto tmp = item.data\n    item.data = ret.data\n    ret.data = tmp\n    item.next = item.next.next\n    ret.next = null\n    return ret\nend\n\ndef reverse(list)\n    auto next = <Elem&>null\n    while list\n        auto tmp = list.next\n        list.next = next\n        next = list\n        list = tmp\n    end\n    return next\nend\n\n def run(arg)\n    auto list = curHead\n    auto finderIdx = <int16>arg\n    auto findCnt = Utils.getSeed(3)\n    auto found = <uint16>0\n    auto missed = <uint16>0\n    auto retval = <Crc.sum_t>0\n    var data: Data\n    data.idx = finderIdx\n    for auto i = 0; i < findCnt; i++\n        data.val = <int16>(i & 0xff)\n        auto elem = find(list, data)\n        list = reverse(list)\n        if elem == null\n            missed += 1\n            retval += <uint16>(list.next.data.val >> 8) & 0x1\n        else\n            found += 1\n            if <uint16>elem.data.val & 0x1\n                retval += (<uint16>(elem.data.val >> 9)) & 0x1\n            end\n            if elem.next != null\n                auto tmp = elem.next\n                elem.next = tmp.next\n                tmp.next = list.next\n                list.next = tmp\n            end\n        end\n        data.idx += 1 if data.idx >= 0\n    end\n    retval += found * 4 - missed\n    list = sort(list, valCompare) if finderIdx > 0\n    auto remover = remove(list.next)\n    auto finder = find(list, &data)\n    finder = list.next if !finder\n    while finder\n        retval = Crc.add16(list.data.val, retval)\n        finder = finder.next\n    end\n    unremove(remover, list.next)\n    list = sort(list, idxCompare)\n    for auto e = list.next; e; e = e.next\n        retval = Crc.add16(list.data.val, retval)\n    end\n    return retval\nend\n\ndef setup()\n    auto seed = Utils.getSeed(1)\n    auto ki = 1\n    auto kd = maxElems - 3\n    auto e = curHead\n    e.data.idx = 0\n    e.data.val = 0x8080\n    for e = e.next; e.next; e = e.next\n        auto pat = <uint16>(seed ^ kd) & 0xf\n        auto dat = (pat << 3) | (kd & 0x7)\n        e.data.val = <int16>((dat << 8) | dat)\n        kd -= 1\n        if ki < (maxElems / 5)\n            e.data.idx = ki++\n        else\n            pat = <uint16>(seed ^ ki++)\n            e.data.idx = <int16>(0x3fff & (((ki & 0x7) << 8) | pat))\n        end\n    end\n    e.data.idx = 0x7fff\n    e.data.val = 0xffff\n    curHead = sort(curHead, idxCompare)\nend\n\ndef sort(list, cmp)\n    auto insize = <int32>1\n    var q: Elem&\n    var e: Elem&\n    for ;;\n        auto p = list\n        auto tail = list = null\n        auto nmerges = <int32>0  # count number of merges we do in this pass\n        while p\n            nmerges++  # there exists a merge to be done\n            # step `insize' places along from p\n            q = p\n            auto psize = 0\n            for auto i = 0; i < insize; i++\n                psize++\n                q = q.next\n                break if !q\n            end\n            # if q hasn't fallen off end, we have two lists to merge\n            auto qsize = insize\n            # now we have two lists; merge them\n            while psize > 0 || (qsize > 0 && q)\n                # decide whether next element of merge comes from p or q\n                if psize == 0\n                    # p is empty; e must come from q\n                    e = q\n                    q = q.next\n                    qsize--\n                elif qsize == 0 || !q\n                    # q is empty; e must come from p.\n                    e = p\n                    p = p.next\n                    psize--\n                elif cmp(p.data, q.data) <= 0\n                    # First element of p is lower (or same); e must come from p.\n                    e = p\n                    p = p.next\n                    psize--\n                else\n                    # First element of q is lower; e must come from q.\n                    e = q\n                    q = q.next\n                    qsize--\n                end\n                # add the next element to the merged list\n                if tail\n                    tail.next = e\n                else\n                    list = e\n                end\n                tail = e\n            end\n            # now p has stepped `insize' places along, and q has too\n            p = q\n        end\n        tail.next = null\n        # If we have done only one merge, we're finished\n        break if nmerges <= 1  # allow for nmerges==0, the empty list case\n        # Otherwise repeat, merging lists twice the size\n        insize *= 2\n    end\n    return list\nend\n\ndef unremove(removed, modified)\n    auto tmp = removed.data\n    removed.data = modified.data\n    modified.data = tmp\n    removed.next = modified.next\n    modified.next = removed\nend\n
"},{"location":"cargo/em.bench/em.coremark/MatrixBench/","title":"MatrixBench","text":""},{"location":"cargo/em.bench/em.coremark/MatrixBench/#unit-matrixbench","title":"unit MatrixBench","text":"em.coremark/MatrixBench.em
package em.coremark\n\nimport BenchAlgI\nimport Crc\nimport Utils\n\n# patterned after core_matrix.c\n\nmodule MatrixBench: BenchAlgI\n\nprivate:\n\n    type matdat_t: int16\n    type matres_t: int32\n\n    config dimN: uint8\n\n    var matA: matdat_t[]\n    var matB: matdat_t[]\n    var matC: matres_t[]\n\n    function addVal(val: matdat_t)\n    function mulVal(val: matdat_t)\n    function mulMat()\n    function mulMatBix()\n    function mulVec()\n    function sumDat(clipval: matdat_t): matdat_t\n\n    function bix(res: matres_t, lower: uint8, upper: uint8): matres_t\n    function clip(d: matdat_t, b: bool): matdat_t\n    function enlarge(val: matdat_t): matdat_t\n\n    function prDat(lab: string, mat: matdat_t[])\n    function prRes(lab: string)\n\nend\n\ndef em$construct()\n    auto i = 0\n    auto j = 0\n    while j < memSize\n        i += 1\n        j = i * i * 2 * 4\n    end\n    dimN = i - 1\n    matA.length = matB.length = matC.length = dimN * dimN\nend\n\ndef addVal(val)\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            matA[i * dimN + j] += val\n        end\n    end\nend\n\ndef bix(res, lower, upper)\n    auto r = <uint32>res\n    auto l = <uint32>lower\n    auto u = <uint32>upper\n    return <matres_t>((r >> l) & (~(0xffffffff << u)))\nend\n\ndef clip(d, b)\n    auto x = <uint16>d\n    return <matdat_t>(x & (b ? 0x0ff : 0x0ffff))\nend\n\ndef dump()\n    ## TODO -- implement\nend\n\ndef enlarge(val)\n    auto v = <uint16>val\n    return <matdat_t>(0xf000 | v)\nend\n\ndef kind()\n    return Utils.Kind.MATRIX\nend\n\ndef mulVal(val)\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            matC[i * dimN + j] = <matres_t>matA[i * dimN + j] * <matres_t>val\n        end\n    end\nend\n\ndef mulMat()\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            matC[i * dimN + j] = 0\n            for auto k = 0; k < dimN; k++\n                matC[i * dimN + j] += <matres_t>matA[i * dimN + k] * <matres_t>matB[k * dimN + j]\n            end\n        end\n    end\nend\n\ndef mulMatBix()\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            matC[i * dimN + j] = 0\n            for auto k = 0; k < dimN; k++\n                auto tmp = <matres_t>matA[i * dimN + k] * <matres_t>matB[k * dimN + j]\n                matC[i * dimN + j] += bix(tmp, 2, 4) * bix(tmp, 5, 7)\n            end\n        end\n    end\nend\n\ndef mulVec()\n    for auto i = 0; i < dimN; i++\n        matC[i] = 0\n        for auto j = 0; j < dimN; j++\n            matC[i] += <matres_t>matA[i * dimN + j] * <matres_t>matB[j]\n        end\n    end\nend\n\ndef print()\n    prDat(\"A\", matA)\n    prDat(\"B\", matB)\nend\n\ndef prDat(lab, mat)\n    printf \"\\n%s:\\n    \", lab\n    for auto i = 0; i < dimN; i++\n        auto sep = \"\"\n        for auto j = 0; j < dimN; j++\n            printf \"%s%d\", sep, mat[i * dimN + j]\n            sep = \",\"\n        end\n        printf \"\\n    \"\n    end\nend\n\ndef prRes(lab)\n    printf \"\\n%s:\\n    \", lab\n    for auto i = 0; i < dimN; i++\n        auto sep = \"\"\n        for auto j = 0; j < dimN; j++\n            printf \"%s%d\", sep, matC[i * dimN + j]\n            sep = \",\"\n        end\n        printf \"\\n    \"\n    end\nend\n\ndef run(arg)\n    auto crc = <Crc.sum_t>0\n    auto val = <matdat_t>arg\n    auto clipval = enlarge(val)\n    #\n    addVal(val)\n    mulVal(val)\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    mulVec()\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    mulMat()\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    mulMatBix()\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    addVal(-val)\n    return Crc.add16(<int16>crc, Utils.getCrc(Utils.Kind.FINAL))\nend\n\ndef setup()\n    auto s32 = <uint32>Utils.getSeed(1) | (<uint32>Utils.getSeed(2) << 16)\n    auto sd = <matdat_t>s32\n    sd = 1 if sd == 0\n    auto order = <matdat_t>1\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            sd = <int16>((order * sd) % 65536)\n            auto val = <matdat_t>(sd + order)\n            val = clip(val, false)\n            matB[i * dimN + j] = val\n            val += order\n            val = clip(val, true)\n            matA[i * dimN + j] = val\n            order += 1\n        end\n    end\nend\n\ndef sumDat(clipval)\n    auto cur = <matres_t>0\n    auto prev = <matres_t>0\n    auto tmp = <matres_t>0\n    auto ret = <matdat_t>0\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            cur = matC[i * dimN + j]\n            tmp += cur\n            if tmp > clipval\n                ret += 10\n                tmp = 0\n            else\n                ret += (cur > prev) ? 1 : 0\n            end\n            prev = cur\n        end\n    end\n    return ret\nend\n
"},{"location":"cargo/em.bench/em.coremark/SleepyRunnerP/","title":"SleepyRunnerP","text":""},{"location":"cargo/em.bench/em.coremark/SleepyRunnerP/#unit-sleepyrunnerp","title":"unit SleepyRunnerP","text":"em.coremark/SleepyRunnerP.em
package em.coremark\n\nfrom em$distro import BoardC\n\nfrom em.utils import FiberMgr\nfrom em.utils import TickerMgr\n\nimport CoreBench\n\nmodule SleepyRunnerP\n\nprivate:\n\n    var ticker: TickerMgr.Ticker&\n\n    var count: uint8 = 10\n\n    function tickCb: TickerMgr.TickCallback\n\nend\n\ndef em$construct()\n    ticker = TickerMgr.createH()\nend\n\ndef em$startup()\n    CoreBench.setup()\nend\n\ndef em$run()\n    ticker.start(256, tickCb)\n    FiberMgr.run()\nend\n\ndef tickCb()\n    %%[d+]\n    auto crc = CoreBench.run()\n    %%[d-]\n    printf \"crc = %04x\\n\", crc\n    return if --count\n    ticker.stop()\n    halt\nend\n
"},{"location":"cargo/em.bench/em.coremark/StateBench/","title":"StateBench","text":""},{"location":"cargo/em.bench/em.coremark/StateBench/#unit-statebench","title":"unit StateBench","text":"em.coremark/StateBench.em
package em.coremark\n\nimport BenchAlgI\nimport Crc\nimport Utils\n\n# patterned after core_state.c\n\nmodule StateBench: BenchAlgI\n\nprivate:\n\n    const NUM_STATES: uint8 = 8\n\n    type StringBuf: char*\n\n    type State: enum\n        START,\n        INVALID,\n        S1,\n        S2,\n        INT,\n        FLOAT,\n        EXPONENT,\n        SCIENTIFIC,\n    end\n\n    config intPat: string[4] = [\n        \"5012\", \"1234\", \"-874\", \"+122\"\n    ]\n    config fltPat: string[4] = [\n        \"35.54400\", \".1234500\", \"-110.700\", \"+0.64400\"\n    ]\n    config sciPat: string[4] = [\n        \"5.500e+3\", \"-.123e-2\", \"-87e+832\", \"+0.6e-12\"\n    ]\n    config errPat: string[4] = [\n        \"T0.3e-1F\", \"-T.T++Tq\", \"1T3.4e4z\", \"34.0e-T^\"\n    ]\n\n    config intPatLen: uint16\n    config fltPatLen: uint16\n    config sciPatLen: uint16\n    config errPatLen: uint16\n\n    var memBuf: char[]\n\n    function isDigit(ch: char): bool\n    function nextState(pStr: StringBuf*, transCnt: uint32[]): State\n    function ord(state: State): uint8\n    function scan(finalCnt: uint32[], transCnt: uint32[])\n    function scramble(seed: Utils.seed_t, step: uarg_t)\n\nend\n\ndef em$construct()\n    memBuf.length = memSize\n    intPatLen = intPat[0].length\n    fltPatLen = fltPat[0].length\n    sciPatLen = sciPat[0].length\n    errPatLen = errPat[0].length\nend\n\ndef dump()\n    ## TODO -- implement\nend\n\ndef isDigit(ch)\n    return ch >= '0' && ch <= '9'\nend\n\ndef kind()\n    return Utils.Kind.STATE\nend\n\ndef nextState(pStr, transCnt)\n    auto str = *pStr\n    auto state = State.START\n    for ; *str && state != State.INVALID; str++\n        auto ch = *str\n        if ch == ','\n            str++\n            break\n        end\n        switch state\n        case State.START\n            if isDigit(ch)\n                state = State.INT\n            elif ch == '+' || ch == '-'\n                state = State.S1\n            elif ch == '.'\n                state = State.FLOAT\n            else\n                state = State.INVALID\n                transCnt[ord(State.INVALID)] += 1\n            end\n            transCnt[ord(State.START)] += 1\n            break\n        case State.S1\n            if isDigit(ch)\n                state = State.INT\n                transCnt[ord(State.S1)] += 1\n            elif ch == '.'\n                state = State.FLOAT\n                transCnt[ord(State.S1)] += 1\n            else\n                state = State.INVALID\n                transCnt[ord(State.S1)] += 1\n            end\n            break\n        case State.INT\n            if ch == '.'\n                state = State.FLOAT\n                transCnt[ord(State.INT)] += 1\n            elif !isDigit(ch)\n                state = State.INVALID\n                transCnt[ord(State.INT)] += 1\n            end\n            break\n        case State.FLOAT\n            if ch == 'E' || ch == 'e'\n                state = State.S2\n                transCnt[ord(State.FLOAT)] += 1\n            elif !isDigit(ch)\n                state = State.INVALID\n                transCnt[ord(State.FLOAT)] += 1\n            end\n            break\n        case State.S2\n            if ch == '+' || ch == '-'\n                state = State.EXPONENT\n                transCnt[ord(State.S2)] += 1\n            else\n                state = State.INVALID\n                transCnt[ord(State.S2)] += 1\n            end\n            break\n        case State.EXPONENT\n            if isDigit(ch)\n                state = State.SCIENTIFIC\n                transCnt[ord(State.EXPONENT)] += 1\n            else\n                state = State.INVALID\n                transCnt[ord(State.EXPONENT)] += 1\n            end\n            break\n        case State.SCIENTIFIC\n            if !isDigit(ch)\n                state = State.INVALID\n                transCnt[ord(State.INVALID)] += 1\n            end\n            break\n        end\n    end\n    *pStr = str\n    return state\nend\n\ndef ord(state)\n    return <uint8>state\nend\n\ndef print()\n    auto p = &memBuf[0]\n    auto cnt = 0\n    printf \"\\n%c\", '\"'\n    while *p\n        if (cnt++ % 8) == 0\n            printf \"\\n    \"\n        end\n        var c: char\n        while (c = *p++) != ','\n            printf \"%c\", c\n        end\n        printf \", \"\n    end\n    printf \"\\n%c, count = %d\\n\", '\"', cnt\nend\n\ndef run(arg)\n    arg = 0x22 if arg < 0x22\n    var finalCnt: uint32[NUM_STATES]\n    var transCnt: uint32[NUM_STATES]\n    for auto i = 0; i < NUM_STATES; i++\n        finalCnt[i] = transCnt[i] = 0\n    end\n    scan(finalCnt, transCnt)\n    scramble(Utils.getSeed(1), arg)\n    scan(finalCnt, transCnt)\n    scramble(Utils.getSeed(2), arg)\n    auto crc = Utils.getCrc(Utils.Kind.FINAL)\n    for auto i = 0; i < NUM_STATES; i++\n        crc = Crc.addU32(finalCnt[i], crc)\n        crc = Crc.addU32(transCnt[i], crc)\n    end\n    return crc\nend\n\ndef scan(finalCnt, transCnt)\n    for auto str = &memBuf[0]; *str;\n        auto state = nextState(&str, transCnt)\n        finalCnt[ord(state)] += 1\n    end\nend\n\ndef scramble(seed, step)\n    for auto str = &memBuf[0]; str < &memBuf[memSize]; str += <uint16>step\n        *str ^= <uint8>seed if *str != ','\n    end\nend\n\ndef setup()\n    auto seed = Utils.getSeed(1)\n    auto p = &memBuf[0]\n    auto total = 0\n    auto pat = \"\"\n    auto plen = 0\n    while (total + plen + 1) < (memSize - 1)\n        if plen\n            for auto i = 0; i < plen; i++\n                *p++ = pat[i]\n            end\n            *p++ = ','\n            total += plen + 1\n        end\n        switch ++seed & 0x7\n        case 0\n        case 1\n        case 2\n            pat  = intPat[(seed >> 3) & 0x3]\n            plen = intPatLen\n            break\n        case 3\n        case 4\n            pat  = fltPat[(seed >> 3) & 0x3]\n            plen = fltPatLen\n            break\n        case 5\n        case 6\n            pat  = sciPat[(seed >> 3) & 0x3]\n            plen = sciPatLen\n            break\n        case 7\n            pat  = errPat[(seed >> 3) & 0x3]\n            plen = errPatLen\n            break\n        end\n    end\nend\n
"},{"location":"cargo/em.bench/em.coremark/Utils/","title":"Utils","text":""},{"location":"cargo/em.bench/em.coremark/Utils/#unit-utils","title":"unit Utils","text":"em.coremark/Utils.em
package em.coremark\n\nmodule Utils\n\n    const NUM_SEEDS: uint8 = 5\n\n    type Kind: enum\n        FINAL, LIST, MATRIX, STATE, ZZZ_\n    end\n\n    type seed_t: uint16 volatile\n    type sum_t: uint16\n\n    function bindCrc(kind: Kind, crc: sum_t)\n    function getCrc(kind: Kind): sum_t\n    function setCrc(kind: Kind, crc: sum_t)\n\n    host function bindSeedH(idx: uint8, val: seed_t)\n    function getSeed(idx: uint8): seed_t\n\nprivate:\n\n    var crcTab: sum_t[]\n    var seedTab: seed_t[NUM_SEEDS]\n\nend\n\ndef em$construct()\n    crcTab.length = <uint16>Kind.ZZZ_\nend\n\ndef bindCrc(kind, crc)\n    auto p = &crcTab[<uint16>kind]\n    *p = crc if *p == 0\nend\n\ndef bindSeedH(idx, val)\n    seedTab[idx - 1] = val\nend\n\ndef getCrc(kind)\n    return crcTab[<uint16>kind]\nend\n\ndef getSeed(idx)\n    return seedTab[idx - 1]\nend\n\ndef setCrc(kind, crc)\n    crcTab[<uint16>kind] = crc\nend\n
"},{"location":"cargo/em.bench/em.coremark/ValComparator/","title":"ValComparator","text":""},{"location":"cargo/em.bench/em.coremark/ValComparator/#unit-valcomparator","title":"unit ValComparator","text":"em.coremark/ValComparator.em
package em.coremark\n\nimport BenchAlgI\nimport ComparatorI\nimport Crc\nimport Utils\n\nmodule ValComparator: ComparatorI\n\n    proxy Bench0: BenchAlgI\n    proxy Bench1: BenchAlgI\n\nprivate:\n\n    function calc(pval: int16*): int16\n\nend\n\ndef calc(pval)\n    auto val = <uint16>*pval\n    auto optype = <uint8>(val >> 7) & 1\n    return <int16>(val & 0x007f) if optype\n    auto flag = val & 0x7\n    auto vtype = (val >> 3) & 0xf\n    vtype |= vtype << 4\n    var ret: uint16\n    switch flag\n    case 0\n        ret = Bench0.run(<uarg_t>vtype)\n        Utils.bindCrc(Bench0.kind(), ret)\n        break\n    case 1\n        ret = Bench1.run(<uarg_t>vtype)\n        Utils.bindCrc(Bench1.kind(), ret)\n        break\n    default\n        ret = val\n        break\n    end\n    auto newcrc = Crc.add16(<int16>ret, Utils.getCrc(Utils.Kind.FINAL))\n    Utils.setCrc(Utils.Kind.FINAL, Crc.add16(<int16>ret, Utils.getCrc(Utils.Kind.FINAL)))\n    ret &= 0x007f\n    *pval = <int16>((val & 0xff00) | 0x0080 | ret)   ## cache the result\n    return <int16>ret\nend\n\ndef compare(a, b)\n    auto val1 = calc(&a.val)\n    auto val2 = calc(&b.val)\n    return val1 - val2\nend\n
"},{"location":"cargo/em.core/","title":"Index","text":""},{"location":"cargo/em.core/#bundle-emcore","title":"bundle em.core","text":""},{"location":"cargo/em.core/em.hal/","title":"Index","text":""},{"location":"cargo/em.core/em.hal/#package-emhal","title":"package em.hal","text":""},{"location":"cargo/em.core/em.hal/BusyWaitI/","title":"BusyWaitI","text":""},{"location":"cargo/em.core/em.hal/BusyWaitI/#unit-busywaiti","title":"unit BusyWaitI","text":"em.hal/BusyWaitI.em
package em.hal\n\ninterface BusyWaitI\n        #   ^| abstraction of a spin-loop\n    function wait(usecs: uint32)\n        #   ^| enter a spin-loop\n        #   ^| @usecs - duration in microseconds\nend\n
"},{"location":"cargo/em.core/em.hal/BusyWaitN/","title":"BusyWaitN","text":""},{"location":"cargo/em.core/em.hal/BusyWaitN/#unit-busywaitn","title":"unit BusyWaitN","text":"em.hal/BusyWaitN.em
package em.hal\n\nimport BusyWaitI\n\nmodule BusyWaitN: BusyWaitI\n    #   ^| Nil implementation of the BusyWaitI interface\nend\n\ndef wait(usecs)\nend\n
"},{"location":"cargo/em.core/em.hal/ButtonI/","title":"ButtonI","text":""},{"location":"cargo/em.core/em.hal/ButtonI/#unit-buttoni","title":"unit ButtonI","text":"em.hal/ButtonI.em
package em.hal\n\ninterface ButtonI\n        #   ^| abstraction of a pressable button\n    type OnPressedCB: function()\n        #   ^| signature of a button's callback function\n    function isPressed(): bool\n        #   ^| test whether this button is currently pressed\n    function onPressed(cb: OnPressedCB, minDurationMs: uint16 = 100, maxDurationMs: uint16 = 4000)\n        #   ^| bind a callback to this button\n        #   ^| @cb - callback function, executed when this button is pressed\n        #   ^| @minDurationMs - minimum time in millisecs before executing this button's callback\n        #   ^| @maxDurationMs - maximum time in millisecs, after which this button's callback is executed\n\nend\n
"},{"location":"cargo/em.core/em.hal/ButtonN/","title":"ButtonN","text":""},{"location":"cargo/em.core/em.hal/ButtonN/#unit-buttonn","title":"unit ButtonN","text":"em.hal/ButtonN.em
package em.hal\n\nimport ButtonI\n\nmodule ButtonN: ButtonI\n    #   ^| Nil implementation of the ButtonI interface\nend\n\ndef isPressed()\n    return false\nend\n\ndef onPressed(cb, minDurationMs, maxDurationMs)\nend\n
"},{"location":"cargo/em.core/em.hal/ConsoleUartI/","title":"ConsoleUartI","text":""},{"location":"cargo/em.core/em.hal/ConsoleUartI/#unit-consoleuarti","title":"unit ConsoleUartI","text":"em.hal/ConsoleUartI.em
package em.hal\n\ninterface ConsoleUartI \n\n    host function setBaudH(rate: uint32)\n\n    function flush()\n    function put(data: uint8)\n\nend\n
"},{"location":"cargo/em.core/em.hal/ConsoleUartN/","title":"ConsoleUartN","text":""},{"location":"cargo/em.core/em.hal/ConsoleUartN/#unit-consoleuartn","title":"unit ConsoleUartN","text":"em.hal/ConsoleUartN.em
package em.hal\n\nimport ConsoleUartI\n\nmodule ConsoleUartN: ConsoleUartI\n    #   ^| Nil implementation of the ConsoleUartI interface\nend\n\ndef setBaudH(rate)\nend\n\ndef flush()\nend\n\ndef put(data)\nend\n
"},{"location":"cargo/em.core/em.hal/CopierI/","title":"CopierI","text":""},{"location":"cargo/em.core/em.hal/CopierI/#unit-copieri","title":"unit CopierI","text":"em.hal/CopierI.em
package em.hal\n\ninterface CopierI\n\n    function exec(dst: ptr_t, src: ptr_t, cnt: uint16)\n\nend\n
"},{"location":"cargo/em.core/em.hal/FlashI/","title":"FlashI","text":""},{"location":"cargo/em.core/em.hal/FlashI/#unit-flashi","title":"unit FlashI","text":"em.hal/FlashI.em
package em.hal\n\ninterface FlashI\n\n    host function getSectorSizeH(): uint32\n    host function getWriteChunkH(): uint32\n\n    function erase(addr: addr_t, upto: addr_t = 0)\n    function write(addr: addr_t, data: ptr_t, len: uint32): addr_t\n\nend\n
"},{"location":"cargo/em.core/em.hal/FlashN/","title":"FlashN","text":""},{"location":"cargo/em.core/em.hal/FlashN/#unit-flashn","title":"unit FlashN","text":"em.hal/FlashN.em
package em.hal\n\nimport FlashI\n\nmodule FlashN: FlashI\n    #   ^| Nil implementation of the FlashI interface\nend\n\ndef getSectorSizeH()\n    return 0\nend\n\ndef getWriteChunkH()\n    return 0\nend\n\ndef erase(addr, upto)\nend\n\ndef write(addr, data, len)\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/GlobalInterruptsI/","title":"GlobalInterruptsI","text":""},{"location":"cargo/em.core/em.hal/GlobalInterruptsI/#unit-globalinterruptsi","title":"unit GlobalInterruptsI","text":"em.hal/GlobalInterruptsI.em
package em.hal\n\n#! Interface implemented by a GlobalInterrupts module for a device.\n\ninterface GlobalInterruptsI \n\n    type Key: uarg_t\n\n    #! Disables interrupts and saves state\n    function disable(): Key\n\n    #! Enables interrupts\n    function enable()\n\n    #! Restores interrupts to previous state\n    function restore(key: Key)\nend\n
"},{"location":"cargo/em.core/em.hal/GlobalInterruptsN/","title":"GlobalInterruptsN","text":""},{"location":"cargo/em.core/em.hal/GlobalInterruptsN/#unit-globalinterruptsn","title":"unit GlobalInterruptsN","text":"em.hal/GlobalInterruptsN.em
package em.hal\n\nimport GlobalInterruptsI\n\nmodule GlobalInterruptsN: GlobalInterruptsI\n    #   ^| Nil implementation of the GlobalInterruptsI interface\nend\n\ndef disable()\n    return 0\nend\n\ndef enable()\nend\n\ndef restore(key)\nend\n
"},{"location":"cargo/em.core/em.hal/GpioEdgeDetectMinI/","title":"GpioEdgeDetectMinI","text":""},{"location":"cargo/em.core/em.hal/GpioEdgeDetectMinI/#unit-gpioedgedetectmini","title":"unit GpioEdgeDetectMinI","text":"em.hal/GpioEdgeDetectMinI.em
package em.hal\n\nimport GpioI\n\ninterface GpioEdgeDetectMinI: GpioI \n        #   ^| extends the GpioI abstraction with edge-detection features\n    type Handler: function ()\n        #   ^| signature of an edge-detection function\n    host function setDetectHandlerH(h: Handler)\n        #   ^| bind a handler to this GPIO at build-time\n    function clearDetect()\n        #   ^| clear (acknowledge) any edge-detection by this GPIO\n    function disableDetect()   \n        #   ^| disable edge-detection by this GPIO\n    function enableDetect()\n        #   ^| enable edge-detection by this GPIO\n    function setDetectFallingEdge()\n        #   ^| detect high-to-low transitions by this GPIO\n    function setDetectRisingEdge()\n        #   ^| detect low-to-high transitions by this GPIO\nend\n
"},{"location":"cargo/em.core/em.hal/GpioEdgeDetectMinN/","title":"GpioEdgeDetectMinN","text":""},{"location":"cargo/em.core/em.hal/GpioEdgeDetectMinN/#unit-gpioedgedetectminn","title":"unit GpioEdgeDetectMinN","text":"em.hal/GpioEdgeDetectMinN.em
package em.hal\n\nimport GpioEdgeDetectMinI\n\nmodule GpioEdgeDetectMinN: GpioEdgeDetectMinI\n    #   ^| Nil implementation of the GpioEdgeDetectMinI interface\nend\n\ndef set()\nend\n\ndef clear()\nend\n\ndef toggle()\nend\n\ndef get()\n    return false\nend\n\ndef makeInput()\nend\n\ndef isInput()\n    return false\nend\n\ndef makeOutput()\nend\n\ndef isOutput()\n    return false\nend\n\ndef functionSelect(select)\nend\n\ndef setInternalPullup(state)\nend\n\ndef pinId()\n    return 0\nend\n\ndef reset()\nend\n\ndef enableDetect()\nend\n\ndef disableDetect()\nend\n\ndef clearDetect()\nend\n\ndef setDetectRisingEdge()\nend\n\ndef setDetectFallingEdge()\nend\n\ndef setDetectHandlerH(h)\nend\n
"},{"location":"cargo/em.core/em.hal/GpioI/","title":"GpioI","text":""},{"location":"cargo/em.core/em.hal/GpioI/#unit-gpioi","title":"unit GpioI","text":"em.hal/GpioI.em
package em.hal\n\ninterface GpioI\n        #   ^| abstraction of a GPIO pin\n    function clear()\n        #   ^| clear the value of this GPIO (low)\n    function functionSelect (select: uint8)\n        #   ^| select an alternative function of this GPIO\n    function get(): bool\n        #   ^| get the value of this GPIO\n    function isInput(): bool\n        #   ^| test if this GPIO is an input pin\n    function isOutput(): bool\n        #   ^| test if this GPIO is an output pin\n    function makeInput()\n        #   ^| make this GPIO an input pin\n    function makeOutput()\n        #   ^| make this GPIO an output pin\n    function pinId(): int16\n        #   ^| Return the pin ID of this GPIO\n    function reset()\n        #   ^| Reset this GPIO\n    function set()\n        #   ^| set the value of this GPIO (high)\n    function setInternalPullup (state: bool)\n        #   ^| enable/disable the internalpullup for this GPIO\n    function toggle()\n        #   ^| toggle the value of this GPIO\n\nend\n
"},{"location":"cargo/em.core/em.hal/GpioN/","title":"GpioN","text":""},{"location":"cargo/em.core/em.hal/GpioN/#unit-gpion","title":"unit GpioN","text":"em.hal/GpioN.em
package em.hal\n\nimport GpioI\n\nmodule GpioN: GpioI\n    #   ^| Nil implementation of the GpioI interface\nend\n\ndef set()\nend\n\ndef clear()\nend\n\ndef toggle()\nend\n\ndef get()\n    return false\nend\n\ndef makeInput()\nend\n\ndef isInput()\n    return false\nend\n\ndef makeOutput()\nend\n\ndef isOutput()\n    return false\nend\n\ndef functionSelect(select)\nend\n\ndef setInternalPullup(state)\nend\n\ndef pinId()\n    return 0\nend\n\ndef reset()\nend\n
"},{"location":"cargo/em.core/em.hal/HostUartI/","title":"HostUartI","text":""},{"location":"cargo/em.core/em.hal/HostUartI/#unit-hostuarti","title":"unit HostUartI","text":"em.hal/HostUartI.em
package em.hal\n\nimport ConsoleUartI\n\ninterface HostUartI: ConsoleUartI\n\n    type RxHandler: function(b: uint8)\n\n    function disable()\n    function enable()\n    function get(): uint8\n\n    host function setRxHandlerH(handler: RxHandler)\n\nend\n
"},{"location":"cargo/em.core/em.hal/HostUartN/","title":"HostUartN","text":""},{"location":"cargo/em.core/em.hal/HostUartN/#unit-hostuartn","title":"unit HostUartN","text":"em.hal/HostUartN.em
package em.hal\n\nimport HostUartI\n\nmodule HostUartN: HostUartI\n    #   ^| Nil implementation of the HostUartI interface\nend\n\ndef setBaudH(rate)\n    ## TODO -- implement\nend\n\ndef flush()\n    ## TODO -- implement\nend\n\ndef put(data)\n    ## TODO -- implement\nend\n\ndef disable()\n    ## TODO -- implement\nend\n\ndef enable()\n    ## TODO -- implement\nend\n\ndef get()\n    ## TODO -- implement\n    return 0\nend\n\ndef setRxHandlerH(handler)\n    ## TODO -- implement\nend\n
"},{"location":"cargo/em.core/em.hal/IdleI/","title":"IdleI","text":""},{"location":"cargo/em.core/em.hal/IdleI/#unit-idlei","title":"unit IdleI","text":"em.hal/IdleI.em
package em.hal\n\n#! Should be implemented by an Idle module\n\ninterface IdleI  \n\n    #! This function defines how the system idles\n    function exec()\n\n    #! This function is called during \"warm\" wakeups\n    function wakeup()\nend\n
"},{"location":"cargo/em.core/em.hal/IdleN/","title":"IdleN","text":""},{"location":"cargo/em.core/em.hal/IdleN/#unit-idlen","title":"unit IdleN","text":"em.hal/IdleN.em
package em.hal\n\nimport IdleI\n\nmodule IdleN: IdleI\n    #   ^| Nil implementation of the IdleI interface\nend\n\ndef exec()\nend\n\ndef wakeup()\nend\n
"},{"location":"cargo/em.core/em.hal/InterruptSourceI/","title":"InterruptSourceI","text":""},{"location":"cargo/em.core/em.hal/InterruptSourceI/#unit-interruptsourcei","title":"unit InterruptSourceI","text":"em.hal/InterruptSourceI.em
package em.hal\n\n#! Generally implemented by an Interrupt Template used to \"create\" interrupts\n\ninterface InterruptSourceI \n\n    type Handler: function()\n\n    #! Sets the handler function for a particular interrupt\n    host function setHandlerH(h: Handler)\n\n    #! Enables a particular interrupt\n    function enable()\n\n    #! Disables a particular interrupt\n    function disable()\n\n    #! Clears the interrupt flag   \n    function clear()\n\n    #! True if the interrupt is enabled\n    function isEnabled(): bool\nend\n
"},{"location":"cargo/em.core/em.hal/IntrVecI/","title":"IntrVecI","text":""},{"location":"cargo/em.core/em.hal/IntrVecI/#unit-intrveci","title":"unit IntrVecI","text":"em.hal/IntrVecI.em
package em.hal\n\ninterface IntrVecI\n\n    type ExceptionHandler: function(vecNum: uint32, retAddr: addr_t)\n\n    host function bindExceptionHandlerH(handler: ExceptionHandler)\n\nend\n
"},{"location":"cargo/em.core/em.hal/LedI/","title":"LedI","text":""},{"location":"cargo/em.core/em.hal/LedI/#unit-ledi","title":"unit LedI","text":"em.hal/LedI.em
package em.hal\n\ninterface LedI\n        #   ^| abstraction of an LED\n    function isOn(): bool\n        #   ^| test if the LED is on\n    function off()\n        #   ^| turn the LED off\n    function on()\n        #   ^| turn the LED on\n    function toggle()\n        #   ^| toggle the LED\n    function wink(msecs: uint16)\n        #   ^| turn the LED on/off\n        #   ^| @msecs duration in milliseconds\n    end\n
"},{"location":"cargo/em.core/em.hal/LedN/","title":"LedN","text":""},{"location":"cargo/em.core/em.hal/LedN/#unit-ledn","title":"unit LedN","text":"em.hal/LedN.em
package em.hal\n\nimport LedI\n\nmodule LedN: LedI\n    #   ^| Nil implementation of the LedI interface\nend\n\ndef isOn()\n    return false\nend\n\ndef on()\nend\n\ndef off()\nend\n\ndef toggle()\nend\n\ndef wink(usecs)\nend\n
"},{"location":"cargo/em.core/em.hal/McuI/","title":"McuI","text":""},{"location":"cargo/em.core/em.hal/McuI/#unit-mcui","title":"unit McuI","text":"em.hal/McuI.em
package em.hal\n\n#! Implemented by an Mcu module\n\ninterface McuI \n\n    const ADMIN_RESET: int8 = -1\n    const HOST_RESET:  int8 = -2\n    const COLD_RESET:  int8 = -3\n    const FIRST_RESET: int8 = -4\n\n    config mclkFrequency: uint32\n\n    function getResetCode(): int8\n    function getStashAddr(): ptr_t\n    function isWarm(): bool\n    function readEui48(dst: uint8*)\n\n    #! Perform startup and shutdown operations specific for a particular Mcu\n    function reset(code: int8 = 0)\n    function startup()\n    function shutdown()\nend\n
"},{"location":"cargo/em.core/em.hal/McuInfoI/","title":"McuInfoI","text":""},{"location":"cargo/em.core/em.hal/McuInfoI/#unit-mcuinfoi","title":"unit McuInfoI","text":"em.hal/McuInfoI.em
package em.hal\n\ninterface McuInfoI\n\n    function readBatMv(): uint16\n    function readTempC(): int8\n\nend\n
"},{"location":"cargo/em.core/em.hal/McuInfoN/","title":"McuInfoN","text":""},{"location":"cargo/em.core/em.hal/McuInfoN/#unit-mcuinfon","title":"unit McuInfoN","text":"em.hal/McuInfoN.em
package em.hal\n\nimport McuInfoI\n\nmodule McuInfoN: McuInfoI\n    #   ^| Nil implementation of the McuInfoI interface\nend\n\ndef readBatMv()\n    return 0\nend\n\ndef readTempC()\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/McuN/","title":"McuN","text":""},{"location":"cargo/em.core/em.hal/McuN/#unit-mcun","title":"unit McuN","text":"em.hal/McuN.em
package em.hal\n\nimport McuI\n\nmodule McuN: McuI\n\nend\n\ndef getResetCode()\n    return 0\nend\n\ndef getStashAddr()\n    return null\nend\n\ndef isWarm()\n    return false\nend\n\ndef readEui48(dst)\nend\n\ndef reset(code)\nend\n\ndef startup()\nend\n\ndef shutdown()\nend\n
"},{"location":"cargo/em.core/em.hal/MsCounterI/","title":"MsCounterI","text":""},{"location":"cargo/em.core/em.hal/MsCounterI/#unit-mscounteri","title":"unit MsCounterI","text":"em.hal/MsCounterI.em
package em.hal\n\ninterface MsCounterI\n\n    function start()\n    function stop(): uint32\n\nend\n
"},{"location":"cargo/em.core/em.hal/MsCounterN/","title":"MsCounterN","text":""},{"location":"cargo/em.core/em.hal/MsCounterN/#unit-mscountern","title":"unit MsCounterN","text":"em.hal/MsCounterN.em
package em.hal\n\nimport MsCounterI\n\nmodule MsCounterN: MsCounterI\n    #   ^| Nil implementation of the MsCounterI interface\nend\n\ndef start()\nend\n\ndef stop()\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/OneShotMilliI/","title":"OneShotMilliI","text":""},{"location":"cargo/em.core/em.hal/OneShotMilliI/#unit-oneshotmillii","title":"unit OneShotMilliI","text":"em.hal/OneShotMilliI.em
 package em.hal\n\ninterface OneShotMilliI\n        #   ^| abstraction of a one-shot timer with millisecond resolution\n    type Handler: function(arg: ptr_t)\n        #   ^| handler function signature\n    function disable()\n        #   ^| disables the timer\n    function enable(msecs: uint32, handler: Handler, arg: ptr_t = null) \n        #   ^| enables the timer to expire in msecs milliseconds\n        #   ^| @msecs - duration in millisecs before expiration\n        #   ^| @handler - handler function called upon expiration \n        #   ^| @arg - optional value passed to the handler\nend\n
"},{"location":"cargo/em.core/em.hal/OneShotMilliN/","title":"OneShotMilliN","text":""},{"location":"cargo/em.core/em.hal/OneShotMilliN/#unit-oneshotmillin","title":"unit OneShotMilliN","text":"em.hal/OneShotMilliN.em
package em.hal\n\nimport OneShotMilliI\n\nmodule OneShotMilliN: OneShotMilliI\n    #   ^| Nil implementation of the OneShotMilliI interface\nend\n\ndef disable()\nend\n\ndef enable(msecs, handler, arg)\nend\n
"},{"location":"cargo/em.core/em.hal/PollerI/","title":"PollerI","text":""},{"location":"cargo/em.core/em.hal/PollerI/#unit-polleri","title":"unit PollerI","text":"em.hal/PollerI.em
package em.hal\n\ninterface PollerI\n        #       ^| abstration of periodic polling\n    type PollFxn: function(): bool\n        #       ^| signature of a boolean-valued polling function\n    function poll(rateMs: uint16, count: uint16, fxn: PollFxn): uint16 \n        #       ^| initiates a polling sequence\n        #       ^| @rateMs - idle time in milliseconds between pollings\n        #       ^| @count - maximum number of polling attempts\n        #       ^| @fxn - the polling function itself\n        #       ^| @return - the number of polling attempts remaining (success if >0)\nend\n
"},{"location":"cargo/em.core/em.hal/PollerN/","title":"PollerN","text":""},{"location":"cargo/em.core/em.hal/PollerN/#unit-pollern","title":"unit PollerN","text":"em.hal/PollerN.em
package em.hal\n\nimport PollerI\n\nmodule PollerN: PollerI\n    #   ^| Nil implementation of the PollerI interface\nend\n\ndef poll(rateMs, count, fxn)\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/RandI/","title":"RandI","text":""},{"location":"cargo/em.core/em.hal/RandI/#unit-randi","title":"unit RandI","text":"em.hal/RandI.em
package em.hal\n\ninterface RandI\n\n    function gen(): uint32\n\nend\n
"},{"location":"cargo/em.core/em.hal/RandN/","title":"RandN","text":""},{"location":"cargo/em.core/em.hal/RandN/#unit-randn","title":"unit RandN","text":"em.hal/RandN.em
package em.hal\n\nimport RandI\n\nmodule RandN: RandI\n    #   ^| Nil implementation of the RandI interface\nend\n\ndef gen()\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/SpiMasterI/","title":"SpiMasterI","text":""},{"location":"cargo/em.core/em.hal/SpiMasterI/#unit-spimasteri","title":"unit SpiMasterI","text":"em.hal/SpiMasterI.em
package em.hal\n\ninterface SpiMasterI\n\n    function activate()\n    function deactivate()\n    function flush()\n    function get(): uint8\n    function put(data: uint8)\n\nend\n
"},{"location":"cargo/em.core/em.hal/TimeoutI/","title":"TimeoutI","text":""},{"location":"cargo/em.core/em.hal/TimeoutI/#unit-timeouti","title":"unit TimeoutI","text":"em.hal/TimeoutI.em
package em.hal\n\ninterface TimeoutI\n\n    function active(): bool\n    function cancel()\n    function set(msecs: uint32)\n\nend\n
"},{"location":"cargo/em.core/em.hal/TimeoutN/","title":"TimeoutN","text":""},{"location":"cargo/em.core/em.hal/TimeoutN/#unit-timeoutn","title":"unit TimeoutN","text":"em.hal/TimeoutN.em
package em.hal\n\nimport TimeoutI\n\nmodule TimeoutN: TimeoutI\n    #   ^| Nil implementation of the TimeoutI interface\nend\n\ndef active()\n    return false\nend\n\ndef cancel()\nend\n\ndef set(msecs)\nend\n
"},{"location":"cargo/em.core/em.hal/UptimerI/","title":"UptimerI","text":""},{"location":"cargo/em.core/em.hal/UptimerI/#unit-uptimeri","title":"unit UptimerI","text":"em.hal/UptimerI.em
package em.hal\n\ninterface UptimerI\n\n    type Time: struct\n        secs: uint32\n        subs: uint32\n        ticks: uint32\n    end\n\n    function calibrate(secs256: uint32, ticks: uint32): uint16\n    function read(): Time&\n    function resetSync()\n    function trim(): uint16\n\nend\n
"},{"location":"cargo/em.core/em.hal/UptimerN/","title":"UptimerN","text":""},{"location":"cargo/em.core/em.hal/UptimerN/#unit-uptimern","title":"unit UptimerN","text":"em.hal/UptimerN.em
package em.hal\n\nimport UptimerI\n\nmodule UptimerN: UptimerI\n    #   ^| Nil implementation of the UptimerI interface\nend\n\ndef calibrate(secs256, ticks)\n    return 0\nend\n\ndef read()\n    return null\nend\n\ndef resetSync()\nend\n\ndef trim()\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/UsCounterI/","title":"UsCounterI","text":""},{"location":"cargo/em.core/em.hal/UsCounterI/#unit-uscounteri","title":"unit UsCounterI","text":"em.hal/UsCounterI.em
package em.hal\n\ninterface UsCounterI\n\n    function start()\n    function stop(): uint32\n\nend\n
"},{"location":"cargo/em.core/em.hal/UsCounterN/","title":"UsCounterN","text":""},{"location":"cargo/em.core/em.hal/UsCounterN/#unit-uscountern","title":"unit UsCounterN","text":"em.hal/UsCounterN.em
package em.hal\n\nimport UsCounterI\n\nmodule UsCounterN: UsCounterI\n\nend\n\ndef start()\nend\n\ndef stop()\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/UsThreshI/","title":"UsThreshI","text":""},{"location":"cargo/em.core/em.hal/UsThreshI/#unit-usthreshi","title":"unit UsThreshI","text":"em.hal/UsThreshI.em
package em.hal\n\ninterface UsThreshI\n\n    function pause()\n    function set(usecs: uint16)\n\nend\n
"},{"location":"cargo/em.core/em.hal/WakeupTimerI/","title":"WakeupTimerI","text":""},{"location":"cargo/em.core/em.hal/WakeupTimerI/#unit-wakeuptimeri","title":"unit WakeupTimerI","text":"em.hal/WakeupTimerI.em
package em.hal\n\ninterface WakeupTimerI\n        #   ^| abstraction of a free-running wakeup-timer (RTC)\n    type Handler: function()\n        #   ^| handler function signature\n    function disable()\n        #   ^| disables any pending wakeup from the timer\n    function enable(thresh: uint32, handler: Handler)\n        #   ^| enables a future wakeup from the timer\n        #   ^| @thresh - an internal timer threshold value\n        #   ^| @handler - the function called when reaching the threshold\n    function secs256ToTicks(secs256: uint32): uint32\n        #   ^| converts secs256 to logical timer ticks\n    function ticksToThresh(ticks: uint32): uint32\n        #   ^| converts timer ticks to an internal timer threshold value\n    function timeToTicks(secs: uint32, subs: uint32): uint32\n        #   ^| converts secs+subs time value to logical timer ticks\n        #   ^| @secs - the seconds component of the time value\n        #   ^| @subs - the sub-seconds component of the time value\n        #   ^| @return - time value represented as logic timer ticks\nend\n
"},{"location":"cargo/em.core/em.hal/WakeupTimerN/","title":"WakeupTimerN","text":""},{"location":"cargo/em.core/em.hal/WakeupTimerN/#unit-wakeuptimern","title":"unit WakeupTimerN","text":"em.hal/WakeupTimerN.em
package em.hal\n\nimport WakeupTimerI\n\nmodule WakeupTimerN: WakeupTimerI\n    #   ^| Nil implementation of the WakeupTimerI interface\nend\n\ndef disable()\nend\n\ndef enable(thresh, handler)\nend\n\ndef secs256ToTicks(secs256)\n    return 0\nend\n\ndef ticksToThresh(ticks)\n    return 0\nend\n\ndef timeToTicks(secs, subs)\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/WatchdogI/","title":"WatchdogI","text":""},{"location":"cargo/em.core/em.hal/WatchdogI/#unit-watchdogi","title":"unit WatchdogI","text":"em.hal/WatchdogI.em
package em.hal\n\ninterface WatchdogI\n\n    type Handler: function()\n\n    function didBite(): bool\n    function disable()\n    function enable(secs: uint16, handler: Handler)\n    function pet()\n\nend\n
"},{"location":"cargo/em.core/em.hal/WatchdogN/","title":"WatchdogN","text":""},{"location":"cargo/em.core/em.hal/WatchdogN/#unit-watchdogn","title":"unit WatchdogN","text":"em.hal/WatchdogN.em
package em.hal\n\nimport WatchdogI\n\nmodule WatchdogN: WatchdogI\n    #   ^| Nil implementation of the WatchdogI interface\nend\n\ndef didBite()\n    return false\nend\n\ndef disable()\nend\n\ndef enable(secs, handler)\nend\n\ndef pet()\nend\n
"},{"location":"cargo/em.core/em.lang/","title":"Index","text":""},{"location":"cargo/em.core/em.lang/#package-emlang","title":"package em.lang","text":""},{"location":"cargo/em.core/em.lang/Assert/","title":"Assert","text":""},{"location":"cargo/em.core/em.lang/Assert/#unit-assert","title":"unit Assert","text":"em.lang/Assert.em
package em.lang\n\nimport AssertProviderI\nimport AssertProviderN\n\nmodule Assert\n\n    proxy Provider: AssertProviderI\n\n    function enabled(): bool\n    function trigger(upath: atom_t, line: uint16, msg: atom_t = 0, arg1: iarg_t = 0, arg2: iarg_t = 0)\n\nend\n\ndef em$configure()\n    Provider ?= AssertProviderN\nend\n\ndef enabled()\n    return Provider.enabled()\nend\n\ndef trigger(upath, line, msg, arg1, arg2)\n    Provider.trigger(upath, line, msg, arg1, arg2) if enabled()\nend\n
"},{"location":"cargo/em.core/em.lang/AssertProviderI/","title":"AssertProviderI","text":""},{"location":"cargo/em.core/em.lang/AssertProviderI/#unit-assertprovideri","title":"unit AssertProviderI","text":"em.lang/AssertProviderI.em
package em.lang\n\ninterface AssertProviderI\n\n    function enabled(): bool\n    function trigger(upath: atom_t, line: uint16, msg: atom_t, arg1: iarg_t, arg2: iarg_t)\n\nend\n
"},{"location":"cargo/em.core/em.lang/AssertProviderN/","title":"AssertProviderN","text":""},{"location":"cargo/em.core/em.lang/AssertProviderN/#unit-assertprovidern","title":"unit AssertProviderN","text":"em.lang/AssertProviderN.em
package em.lang\n\nimport AssertProviderI\n\nmodule AssertProviderN: AssertProviderI\n\nend\n\ndef enabled()\n    return false\nend\n\ndef trigger(upath, line, msg, arg1, arg2)\nend\n
"},{"location":"cargo/em.core/em.lang/Atom/","title":"Atom","text":""},{"location":"cargo/em.core/em.lang/Atom/#unit-atom","title":"unit Atom","text":"em.lang/Atom.em
package em.lang\n\nmodule Atom\n\n    config NULL_A: atom_t = @\"<<null>>\"\n    config UNDEFINED_A: atom_t = @\"<<undefined>>\"\n\n    function fromString(str: string, oatom: atom_t*): bool\n    function hasTable(): bool\n    function toString(atom: atom_t): string\n\nprivate:\n\n    const MASK: addr_t = 0x80000000\n\n    config tableFlag: bool\n\nend\n\ndef em$construct()\n    tableFlag = ^^!!em$props.get(em$session.PROP_ATOM_TABLE)^^\nend\n\ndef fromString(str, oatom)\n    auto saddr = <addr_t>str\n    return false if tableFlag || (saddr & MASK) == 0\n    *oatom = <atom_t>saddr\n    return true\nend\n\ndef hasTable()\n    return tableFlag\nend\n\ndef toString(atom)\n    return tableFlag ? ^^em$atoms[atom]^^ : <string>((<addr_t>atom) | MASK)\nend\n
"},{"location":"cargo/em.core/em.lang/BuildC/","title":"BuildC","text":""},{"location":"cargo/em.core/em.lang/BuildC/#unit-buildc","title":"unit BuildC","text":"em.lang/BuildC.em
package em.lang\n\ncomposite BuildC\n\n    config arch: string\n    config bootFlash: bool\n    config bootLoader: bool\n    config compiler: string\n    config cpu: string\n    config jlinkDev: string\n    config mcu: string\n    config optimize: string\n\nprivate:\n\n    var curPval: string\n\n    function getProp(pname: string): string\n\nend\n\ndef em$preconfigure()\n    arch ?= curPval if getProp(\"em.build.Arch\")\n    bootFlash ?= true if getProp(\"em.build.BootFlash\")\n    bootLoader ?= true if getProp(\"em.lang.BootLoader\")\n    compiler ?= curPval if getProp(\"em.build.Compiler\")\n    cpu ?= curPval if getProp(\"em.build.Cpu\")\n    jlinkDev ?= curPval if getProp(\"em.build.JlinkDev\")\n    mcu ?= curPval if getProp(\"em.build.Mcu\")\n    optimize ?= curPval if getProp(\"em.build.Optimize\")\nend\n\ndef getProp(pname)\n    return curPval = ^^em$props.get^^(pname, null)\nend\n
"},{"location":"cargo/em.core/em.lang/BuilderI/","title":"BuilderI","text":""},{"location":"cargo/em.core/em.lang/BuilderI/#unit-builderi","title":"unit BuilderI","text":"em.lang/BuilderI.em
package em.lang\n\nhost interface BuilderI\n\n    type CompileInfo: struct\n        errMsgs: string[]\n        imageSizes: string\n        procStat: int8\n    end\n\n    type TypeInfoDesc: uint8[2]\n\n    type TypeInfo: struct\n        ARG:    TypeInfoDesc\n        CHAR:   TypeInfoDesc\n        INT:    TypeInfoDesc\n        INT8:   TypeInfoDesc\n        INT16:  TypeInfoDesc\n        INT32:  TypeInfoDesc\n        LONG:   TypeInfoDesc\n        PTR:    TypeInfoDesc\n        SHORT:  TypeInfoDesc\n        SIZE:   TypeInfoDesc\n    end\n\n    function compile(buildDir: string): CompileInfo&\n    function getTypeInfo(): TypeInfo&\n    function populate(buildDir: string, sysFlag: bool)\n\nend\n
"},{"location":"cargo/em.core/em.lang/CompositeI/","title":"CompositeI","text":""},{"location":"cargo/em.core/em.lang/CompositeI/#unit-compositei","title":"unit CompositeI","text":"em.lang/CompositeI.em
package em.lang\n\ninterface CompositeI\n\n    host function em$configure()\n    host function em$preconfigure()\n\nend\n
"},{"location":"cargo/em.core/em.lang/Console/","title":"Console","text":""},{"location":"cargo/em.core/em.lang/Console/#unit-console","title":"unit Console","text":"em.lang/Console.em
package em.lang\n\nimport ConsoleProviderI\n\nmodule Console\n\n    proxy Provider: ConsoleProviderI\n\n    config noPrint: bool\n\n    function print(fmt: string, a1: iarg_t = 0, a2: iarg_t = 0, a3: iarg_t = 0, a4: iarg_t = 0, a5: iarg_t = 0, a6: iarg_t = 0)\n\n    function wrC(data: char)\n    function wrN(data: num_t)\n    function wrP(data: ptr_t)\n\n    function wrT(data: string)\n\n    function wrIA(data: iarg_t)\n    function wrUA(data: uarg_t)\n\n    function wrI8(data: int8)\n    function wrI16(data: int16)\n    function wrI32(data: int32)\n\n    function wrU8(data: uint8)\n    function wrU16(data: uint16)\n    function wrU32(data: uint32)\n\nend\n\ndef em$generateCode(prefix)\n    |-> #define em$print em_lang_Console::print\nend\n\ndef print(fmt, a1, a2, a3, a4, a5, a6)\n    if !noPrint\n        Provider.print(fmt, a1, a2, a3, a4, a5, a6)\n    end\nend\n\ndef wrC(data)\n    Provider.put(data)\nend\n\ndef wrN(data)\n    Provider.put(0x8F)\n    auto ba = <uint8[]>(&data)\n    for auto i = 0; i < sizeof<num_t>; i++\n        Provider.put(ba[i])\n    end\n    Provider.flush()\nend\n\ndef wrP(data)\n    wrU32(<uint32>data)\nend\n\ndef wrT(data)\n    Provider.put(0x80)\n    auto cp = <char*>data\n    for ;;\n        auto ch = *cp++\n        wrC(ch)\n        return if ch == 0      \n    end\nend\n\ndef wrIA(data)\n    wrU16(<uint16>data)\nend\n\ndef wrUA(data)\n    wrU16(<uint16>data)\nend\n\ndef wrI8(data)\n    wrU8(<uint8>data)\nend\n\ndef wrI16(data)\n    wrU16(<uint16>data)\nend\n\ndef wrI32(data)\n    wrU32(<uint32>data)\nend\n\ndef wrU8(data)\n    Provider.put(0x81)\n    Provider.put(data)\n    Provider.flush()\nend\n\ndef wrU16(data)\n    Provider.put(0x82)\n    auto b = <uint8> ((data >> 8) & 0xFF)\n    Provider.put(b)\n    b = <uint8> ((data >> 0) & 0xFF)\n    Provider.put(b)\n    Provider.flush()\nend\n\ndef wrU32(data)\n    Provider.put(0x84)\n    auto b = <uint8> ((data >> 24) & 0xFF)\n    Provider.put(b)\n    b = <uint8> ((data >> 16) & 0xFF)\n    Provider.put(b)\n    b = <uint8> ((data >> 8) & 0xFF)\n    Provider.put(b)\n    b = <uint8> ((data >> 0) & 0xFF)\n    Provider.put(b)\n    Provider.flush()\nend\n
"},{"location":"cargo/em.core/em.lang/ConsoleProviderI/","title":"ConsoleProviderI","text":""},{"location":"cargo/em.core/em.lang/ConsoleProviderI/#unit-consoleprovideri","title":"unit ConsoleProviderI","text":"em.lang/ConsoleProviderI.em
package em.lang\n\ninterface ConsoleProviderI\n\n    function flush()\n    function print(fmt: string, a1: iarg_t = 0, a2: iarg_t = 0, a3: iarg_t = 0, a4: iarg_t = 0, a5: iarg_t = 0, a6: iarg_t = 0)\n    function put(data: uint8)\n\nend\n
"},{"location":"cargo/em.core/em.lang/ConsoleProviderN/","title":"ConsoleProviderN","text":""},{"location":"cargo/em.core/em.lang/ConsoleProviderN/#unit-consoleprovidern","title":"unit ConsoleProviderN","text":"em.lang/ConsoleProviderN.em
package em.lang\n\nimport ConsoleProviderI\n\nmodule ConsoleProviderN: ConsoleProviderI\n\nend\n\ndef flush()\nend\n\ndef print(fmt, a1, a2, a3, a4, a5, a6)\nend\n\ndef put(data)\nend\n
"},{"location":"cargo/em.core/em.lang/Debug/","title":"Debug","text":""},{"location":"cargo/em.core/em.lang/Debug/#unit-debug","title":"unit Debug","text":"em.lang/Debug.em
package em.lang\n\nimport DebugPinI\n\nmodule Debug\n\n    proxy Pin_a: DebugPinI\n    proxy Pin_b: DebugPinI\n    proxy Pin_c: DebugPinI\n    proxy Pin_d: DebugPinI\n\n    function getNumPins(): uint8\n    function sleepEnter()\n    function sleepLeave()\n    function startup()\n\nprivate:\n\nend\n\ndef em$configure()\n    em$used ?= true\nend\n\ndef getNumPins()\n    return 4\nend\n\ndef sleepEnter()\n    Pin_a.reset()\n    Pin_b.reset()\n    Pin_c.reset()\n    Pin_d.reset()\nend\n\ndef sleepLeave()\n    startup()\nend\n\ndef startup()\n    Pin_a.startup()\n    Pin_b.startup()\n    Pin_c.startup()\n    Pin_d.startup()\nend\n
"},{"location":"cargo/em.core/em.lang/DebugPinI/","title":"DebugPinI","text":""},{"location":"cargo/em.core/em.lang/DebugPinI/#unit-debugpini","title":"unit DebugPinI","text":"em.lang/DebugPinI.em
package em.lang\n\ninterface DebugPinI\n\n    function clear()\n    function get(): bool\n    function set()\n    function toggle()\n    function pulse()\n    function mark(k: uint8 = 0)\n    function reset()\n    function startup()\n\nend\n
"},{"location":"cargo/em.core/em.lang/DebugPinN/","title":"DebugPinN","text":""},{"location":"cargo/em.core/em.lang/DebugPinN/#unit-debugpinn","title":"unit DebugPinN","text":"em.lang/DebugPinN.em
package em.lang\n\nimport DebugPinI\n\nmodule DebugPinN: DebugPinI\n\nend\n\ndef clear()\nend\n\ndef get()\n    return false\nend\n\ndef set()\nend\n\ndef toggle()\nend\n\ndef pulse()\nend\n\ndef mark(k)\nend\n\ndef reset()\nend\n\ndef startup()\nend\n
"},{"location":"cargo/em.core/em.lang/Math/","title":"Math","text":""},{"location":"cargo/em.core/em.lang/Math/#unit-math","title":"unit Math","text":"em.lang/Math.em
package em.lang\n\n#! This module is only available for use on the host.\n#! It contains some standard math functions.\n\nhost module Math\n\n    config PI: num_t\n\n    #! Returns the absolute value of x\n    function abs(x: num_t): num_t\n\n    #! Returns the smallest integer greater than or equal to x\n    function ceil(x: num_t): num_t\n\n    #! Returns the cos of x\n    function cos(x: num_t): num_t\n\n    #! Returns the largest integer less than or equal to x\n    function floor(x: num_t): num_t\n\n    #! Returns the logarithm (base 10) of x\n    function log2(x: num_t): num_t\n\n    #! Returns the logarithm (base 10) of x\n    function log10(x: num_t): num_t\n\n    #! Returns the value of x to the y power\n    function pow(x: num_t, y: num_t): num_t\n\n    #! Returns the rounded value of x\n    function round(x: num_t): num_t\n\n    #! Returns the sin of x\n    function sin(x: num_t): num_t\n\nend\n\ndef em$configure()\n    PI ?= ^^global.Math.PI^^\nend\n\ndef abs(x)\n    return ^^global.Math.abs(x)^^\nend\n\n# If x = 19.1 this function will return 20\ndef ceil(x)\n    return ^^global.Math.ceil(x)^^\nend\n\ndef cos(x)\n    return ^^global.Math.cos(x)^^\nend\n\n# If x = 19.6 this function will return 19\ndef floor(x)\n    return ^^global.Math.floor(x)^^\nend\n\ndef log2(x)\n    return ^^global.Math.log2(x)^^\nend\n\ndef log10(x)\n    return ^^global.Math.LOG10E * global.Math.log(x)^^\nend\n\ndef pow(x, y)\n    return ^^global.Math.pow(x, y)^^\nend\n\ndef round(x)\n    return ^^global.Math.round(x)^^\nend\n\ndef sin(x)\n    return ^^global.Math.sin(x)^^\nend\n
"},{"location":"cargo/em.core/em.lang/ModuleI/","title":"ModuleI","text":""},{"location":"cargo/em.core/em.lang/ModuleI/#unit-modulei","title":"unit ModuleI","text":"em.lang/ModuleI.em
package em.lang\n\ninterface ModuleI\n\n    type io32_t: uint32 volatile*\n\n    host config em$exclude: bool\n    host config em$export: bool\n    host config em$traceGrp: string\n    host config em$used: bool\n\n    config em$tracePri: uint8\n\n    host function em$configure()\n    host function em$construct()\n    template em$generateCode(prefix: string)\n\n    function em$fail()\n    function em$halt()\n    function em$reset()\n    function em$run()\n    function em$shutdown()\n    function em$startup()\n    function em$startupDone()\n\n    host function em$uses__()\n\nend\n
"},{"location":"cargo/em.core/em.lang/RunC/","title":"RunC","text":""},{"location":"cargo/em.core/em.lang/RunC/#unit-runc","title":"unit RunC","text":"em.lang/RunC.em
package em.lang\n\nimport Console\nimport ConsoleProviderN\n\nimport Debug\nimport DebugPinN\n\ncomposite RunC\n\nend\n\ndef em$configure()\n    Console.em$used ?= true\n    Console.Provider ?= ConsoleProviderN\n    Debug.em$used ?= true\n    Debug.Pin_a ?= DebugPinN\n    Debug.Pin_b ?= DebugPinN\n    Debug.Pin_c ?= DebugPinN\n    Debug.Pin_d ?= DebugPinN\nend\n
"},{"location":"cargo/em.core/em.lang/TemplateI/","title":"TemplateI","text":""},{"location":"cargo/em.core/em.lang/TemplateI/#unit-templatei","title":"unit TemplateI","text":"em.lang/TemplateI.em
package em.lang\n\nhost interface TemplateI \n\n    function em$cacheDirty(ctimeMs: num_t): bool\n    template em$generateUnit(pkgName: string, unitName: string)\n\nend\n
"},{"location":"cargo/em.core/em.mcu/","title":"Index","text":""},{"location":"cargo/em.core/em.mcu/#package-emmcu","title":"package em.mcu","text":""},{"location":"cargo/em.core/em.mcu/Common/","title":"Common","text":""},{"location":"cargo/em.core/em.mcu/Common/#unit-common","title":"unit Common","text":"em.mcu/Common.em
package em.mcu\n\nfrom em.hal import BusyWaitI\nfrom em.hal import GlobalInterruptsI\nfrom em.hal import IdleI\nfrom em.hal import McuI\nfrom em.hal import MsCounterI\nfrom em.hal import RandI\nfrom em.hal import UsCounterI\nfrom em.hal import WatchdogI\n\nmodule Common\n        #   ^| collection of proxies implementing MCU abstractions\n    proxy BusyWait: BusyWaitI\n    proxy GlobalInterrupts: GlobalInterruptsI\n    proxy Idle: IdleI \n    proxy Mcu: McuI    \n    proxy MsCounter: MsCounterI    \n    proxy Rand: RandI\n    proxy UsCounter: UsCounterI    \n    proxy Watchdog: WatchdogI\n\nend\n
"},{"location":"cargo/em.core/em.mcu/CommonC/","title":"CommonC","text":""},{"location":"cargo/em.core/em.mcu/CommonC/#unit-commonc","title":"unit CommonC","text":"em.mcu/CommonC.em
package em.mcu\n\nfrom em.hal import BusyWaitN\nfrom em.hal import GlobalInterruptsN\nfrom em.hal import IdleN\nfrom em.hal import McuN\nfrom em.hal import MsCounterN\nfrom em.hal import RandN\nfrom em.hal import UsCounterN\nfrom em.hal import WatchdogN\n\nfrom em.mcu import Common\n\ncomposite CommonC\n\nend\n\ndef em$configure()\n    Common.BusyWait ?= BusyWaitN\n    Common.GlobalInterrupts ?= GlobalInterruptsN\n    Common.Idle ?= IdleN\n    Common.Mcu ?= McuN\n    Common.MsCounter ?= MsCounterN\n    Common.Rand ?= RandN\n    Common.UsCounter ?= UsCounterN\n    Common.Watchdog ?= WatchdogN\nend\n
"},{"location":"cargo/em.core/em.mcu/ConsoleUart/","title":"ConsoleUart","text":""},{"location":"cargo/em.core/em.mcu/ConsoleUart/#unit-consoleuart","title":"unit ConsoleUart","text":"em.mcu/ConsoleUart.em
package em.mcu\n\nfrom em.hal import ConsoleUartI\nfrom em.hal import ConsoleUartN\n\nmodule ConsoleUart: ConsoleUartI\n\n    proxy Impl: ConsoleUartI\n\nend\n\ndef em$configure()\n    Impl ?= ConsoleUartN\nend\n\ndef setBaudH(rate)\n    Impl.setBaudH(rate)\nend\n\ndef flush()\n    Impl.flush()\nend\n\ndef put(data)\n    Impl.put(data)\nend\n
"},{"location":"cargo/em.core/em.mcu/Copier/","title":"Copier","text":""},{"location":"cargo/em.core/em.mcu/Copier/#unit-copier","title":"unit Copier","text":"em.mcu/Copier.em
package em.mcu\n\nfrom em.hal import CopierI\n\nmodule Copier: CopierI\n\n    proxy Impl: CopierI\n\nend\n\ndef exec(dst, src, cnt)\n    Impl.exec(dst, src, cnt)\nend\n
"},{"location":"cargo/em.core/em.mcu/Info/","title":"Info","text":""},{"location":"cargo/em.core/em.mcu/Info/#unit-info","title":"unit Info","text":"em.mcu/Info.em
package em.mcu\n\nfrom em.hal import McuInfoI\n\nmodule Info: McuInfoI\n\n    proxy Impl: McuInfoI\n\nend\n\ndef readBatMv()\n    return Impl.readBatMv()\nend\n\ndef readTempC()\n    return Impl.readTempC()\nend\n
"},{"location":"cargo/em.core/em.mcu/Poller/","title":"Poller","text":""},{"location":"cargo/em.core/em.mcu/Poller/#unit-poller","title":"unit Poller","text":"em.mcu/Poller.em
package em.mcu\n\nfrom em.hal import PollerN\n\nfrom em.hal import PollerI\n\nmodule Poller: PollerI\n\n    proxy Impl: PollerI\n\n    function pause(timeMs: uint16)\n\nend\n\ndef em$configure()\n    Impl ?= PollerN\nend\n\ndef pause(timeMs)\n    Impl.poll(timeMs, 1, null)\nend\n\ndef poll(rateMs, count, fxn)\n    return Impl.poll(rateMs, count, fxn)\nend\n
"},{"location":"cargo/em.core/em.mcu/Timeout/","title":"Timeout","text":""},{"location":"cargo/em.core/em.mcu/Timeout/#unit-timeout","title":"unit Timeout","text":"em.mcu/Timeout.em
package em.mcu\n\nfrom em.hal import TimeoutI\n\nmodule Timeout: TimeoutI\n\n    proxy Impl: TimeoutI\n\nend\n\ndef active()\n    return Impl.active()\nend\n\ndef cancel()\n    Impl.cancel()\nend\n\ndef set(msecs)\n    Impl.set(msecs)\nend\n
"},{"location":"cargo/em.core/em.utils/","title":"Index","text":""},{"location":"cargo/em.core/em.utils/#package-emutils","title":"package em.utils","text":""},{"location":"cargo/em.core/em.utils/AlarmMgr/","title":"AlarmMgr","text":""},{"location":"cargo/em.core/em.utils/AlarmMgr/#unit-alarmmgr","title":"unit AlarmMgr","text":"em.utils/AlarmMgr.em
package em.utils\n\nfrom em.hal import WakeupTimerI\n\nimport EpochTime\nimport FiberMgr\n\nmodule AlarmMgr\n            #   ^|\n    proxy WakeupTimer: WakeupTimerI\n            #   ^|\n    type Alarm: opaque\n            #   ^|        \n        host function initH(fiber: FiberMgr.Fiber&)\n            #   ^|        \n        function active(): bool\n            #   ^|        \n        function cancel()\n            #   ^|        \n        function wakeup(secs256: uint32)\n            #   ^|        \n        function wakeupAt(secs256: uint32)\n            #   ^|        \n    end\n\n    host function createH(fiber: FiberMgr.Fiber&): Alarm&\n            #   ^|\nprivate:\n\n    def opaque Alarm\n        fiber: FiberMgr.Fiber&\n        thresh: uint32\n        ticks: uint32\n        function setup(ticks: uint32)\n    end\n\n    function update(deltaTicks: uint32)\n    function wakeupHandler: WakeupTimer.Handler\n\n    var alarmTab: Alarm[..]\n    var curAlarm: Alarm&\n\nend\n\ndef createH(fiber)\n    var alarm: Alarm& = alarmTab[alarmTab.length++]\n    alarm.initH(fiber)\n    return alarm\nend\n\ndef update(deltaTicks)\n    WakeupTimer.disable()\n    auto nxtAlarm = <Alarm&>null\n    var maxTicks: uint32 = ~0       # largest uint32\n    for a in alarmTab\n        continue if a.ticks == 0    # inactive alarm\n        a.ticks -= deltaTicks\n        if a.ticks == 0             # expired alarm\n            a.fiber.post()\n        elif a.ticks < maxTicks\n            nxtAlarm = a\n            maxTicks = a.ticks         \n        end\n    end\n    return if nxtAlarm == null      # no active alarms\n    curAlarm = nxtAlarm\n    WakeupTimer.enable(curAlarm.thresh, wakeupHandler)\nend\n\ndef wakeupHandler()\n    update(curAlarm.ticks)\nend\n\ndef Alarm.initH(fiber)\n    this.fiber = fiber\n    this.ticks = 0\nend\n\ndef Alarm.active()\n    return this.ticks != 0\nend\n\ndef Alarm.cancel()\n    this.ticks = 0\n    update(0)\nend\n\ndef Alarm.setup(ticks)\n    this.thresh = WakeupTimer.ticksToThresh(ticks)\n    this.ticks = ticks\n    update(0)\nend\n\ndef Alarm.wakeup(secs256)\n    auto ticks = WakeupTimer.secs256ToTicks(secs256)\n    this.setup(ticks)\nend\n\ndef Alarm.wakeupAt(secs256)\n    var etSubs: uint32\n    auto etSecs = EpochTime.getCurrent(&etSubs)\n    auto etTicks = WakeupTimer.timeToTicks(etSecs, etSubs)\n    auto ticks = WakeupTimer.secs256ToTicks(secs256)\n    this.setup(ticks - (etTicks % ticks))\nend\n
"},{"location":"cargo/em.core/em.utils/AppControl/","title":"AppControl","text":""},{"location":"cargo/em.core/em.utils/AppControl/#unit-appcontrol","title":"unit AppControl","text":"em.utils/AppControl.em
package em.utils\n\nfrom em.mcu import Common\n\nimport BoardController\nimport EpochTime\n\nmodule AppControl\n\n    function restart(status: int8)\n\nprivate:\n\n    type Stash: struct\n        secs: uint32\n        subs: uint32\n    end\n\n    function getStash(): Stash&\n    function doReset(code: int8)\n\nend\n\ndef em$startup()\n    return if Common.Mcu.isWarm() || Common.Mcu.getResetCode() < 0\n    auto stash = getStash()\n    EpochTime.setCurrent(stash.secs, stash.subs, false)\nend\n\ndef em$fail()\n    BoardController.em$fail()\nend\n\ndef em$halt()\n    BoardController.em$halt()\nend\n\ndef doReset(code)\n    auto stash = getStash()\n    stash.secs = EpochTime.getCurrent(&stash.subs)\n    Common.Mcu.reset(code) \nend\n\ndef getStash()\n    return Common.Mcu.getStashAddr()\nend\n\ndef restart(status)\n    doReset(status)\nend\n
"},{"location":"cargo/em.core/em.utils/AssertProvider/","title":"AssertProvider","text":""},{"location":"cargo/em.core/em.utils/AssertProvider/#unit-assertprovider","title":"unit AssertProvider","text":"em.utils/AssertProvider.em
package em.utils\n\nfrom em.lang import AssertProviderI\n\nimport Error\nimport Logger\n\nmodule AssertProvider: AssertProviderI\n\nprivate:\n\n    config assertMsgE: Logger.EventKind&\n    config assertSiteE: Logger.EventKind&\n\nend\n\ndef em$construct()\n    assertMsgE = Logger.declareEventH(\"ASSERT: $F\", \"*--*\")\n    assertSiteE = Logger.declareEventH(\"ASSERT: $a, line %d\", \"*--*\")\nend\n\ndef enabled()\n    return Logger.POLICY != Logger.Policy.NIL\nend\n\ndef trigger(upath, line, msg, arg1, arg2)\n    assertSiteE.log(<addr_t>upath, line)\n    assertMsgE.log(<addr_t>msg, <addr_t>arg1, <addr_t>arg2) if msg\n    Error.raise(Error.Kind.ASSERTION, 0, 0)\nend\n
"},{"location":"cargo/em.core/em.utils/BasicListManager/","title":"BasicListManager","text":""},{"location":"cargo/em.core/em.utils/BasicListManager/#unit-basiclistmanager","title":"unit BasicListManager","text":"em.utils/BasicListManager.em
package em.utils\n\nimport ListManagerI\n\n#! This module implements ListManagerI.\n#! It contains all the functions necessary to maintain a list of objects.\n\nmodule BasicListManager: ListManagerI\n\nprivate:\n\n    # Representation of Element\n    def opaque Element \n        next: Element& volatile\n    end\n\n    # Representation of List\n    def opaque List \n        first: Element& volatile\n        last: Element& volatile\n    end\nend\n\n# Initially an Element is not a member of a List\ndef Element.init() \n    this.next = null\nend\n\n# Initially an Element is not a member of a List\ndef Element.initH() \n    this.next = null\nend\n\ndef Element.isActive() \n    return <uarg_t> this.next\nend\n\n# Creates a head and tail pointer\ndef List.init() \n    this.first = this.last = <Element&> &this.first\nend\n\n# Creates a head and tail pointer\ndef List.initH() \n    this.first = this.last = <Element&> &this.first;\nend\n\n# The very first Element is pointed to by this.first and this.last.\n# Subsequent Elements are added to the end of the list by setting the\n# next pointer of the current last Element to the added Element then moving\n# the last pointer.    \ndef List.add(elem)\n    this.last.next = elem\n    this.last = elem\n    elem.next = <Element&> this\nend\n\n# Elements are removed from the front of the list by\n# setting a pointer equal to the this.first pointer,\n# then moving the this.first pointer to the next Element.\n# If the pointer then points to the List then that was the last\n# Element and reinitialize the list for adding Elements.\n# Otherwise just remove the Element.    \ndef List.get() \n    auto elem = this.first\n    this.last = <Element&>this if (this.first = elem.next) == <Element&>this\n    elem.next = null\n    return elem\nend\n\ndef List.getAt(index)\n    auto elem = this.first\n    auto i = 0\n    if this.hasElements()\n        for ;;\n            break if i++ == index                \n            elem = elem.next                \n            break if elem == <Element&> this\n        end\n        elem = null if elem == <Element&> this\n    else \n        elem = null\n    end\n    return elem\nend\n\n# This function returns the Element after the given Element\n# in the List, but does not remove it from the List.\ndef List.getNext(elem) \n    return elem == this.last ? null : elem.next\nend\n\ndef List.hasElements() \n    return (<uarg_t> this.first) ^ <uarg_t> this\nend\n\n# This function prints the index and address of each Element in the List\ndef List.print() \n    auto elem = this.first\n    auto i = 0\n    if this.hasElements()\n        for ;;\n            printf \"elem%d %p\\n\", i++, elem\n            elem = elem.next\n            break if elem == <Element&> this\n        end\n    else \n        printf \"list empty\\n\"\n    end\n    printf \"\\n\" \nend\n\n# Performs a linear search through the list to find the Element\n# then removes it, updating the appropriate pointers.\ndef List.remove(elem)\n    auto e = this.first\n    if this.hasElements()\n        if elem == this.first\n            this.first = this.first.next\n        else \n            for ;; \n                if e.next == elem\n                    e.next = elem.next                    \n                    break    \n                end \n                break if e == <Element&> this\n            end\n        end\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/BoardController/","title":"BoardController","text":""},{"location":"cargo/em.core/em.utils/BoardController/#unit-boardcontroller","title":"unit BoardController","text":"em.utils/BoardController.em
package em.utils\n\nfrom em.hal import ConsoleUartI\nfrom em.hal import LedI\n\nfrom em.mcu import Common\nfrom em.mcu import ConsoleUart\n\nimport ConsoleProtocol\n\nmodule BoardController\n\n    proxy Led: LedI\n    proxy Uart: ConsoleUartI\n\n    config blinkRate: uint32 = 50000\n\nprivate:    \n\n    function blink(times: uint8, usecs: uint32)\n\nend\n\ndef em$configure()\n    Uart ?= ConsoleUart\nend\n\ndef em$reset()\n    Common.Mcu.startup() \nend\n\ndef em$startupDone()\n    return if Common.Mcu.isWarm()\n    Led.off()\n    blink(2, blinkRate)\n    Uart.flush()\n    Uart.put(0)\n    Uart.put(0)\n    for auto i = 0; i < ConsoleProtocol.SOT_COUNT; i++\n        Uart.put(ConsoleProtocol.SOT_BYTE)\n    end\n    Uart.flush()\nend\n\ndef em$halt()\n    Uart.put(ConsoleProtocol.EOT_BYTE)\n    Common.GlobalInterrupts.disable()\n    Led.on()\n    Common.Mcu.shutdown()\nend\n\ndef em$fail()\n    Common.Mcu.shutdown()\n    Common.GlobalInterrupts.disable()\n    while true\n        blink(2, blinkRate)\n        for auto i = 0; i < 800; i++\n            Common.BusyWait.wait(100)\n        end\n    end\nend\n\ndef blink(times, usecs)\n    auto k = (times * 2)\n    while --k\n        Led.toggle()\n        Common.BusyWait.wait(usecs)    \n    end\n    Led.toggle()\nend\n
"},{"location":"cargo/em.core/em.utils/BoardDriverI/","title":"BoardDriverI","text":""},{"location":"cargo/em.core/em.utils/BoardDriverI/#unit-boarddriveri","title":"unit BoardDriverI","text":"em.utils/BoardDriverI.em
package em.utils\n\ninterface BoardDriverI\n\n    host function bindParamsH(p: ptr_t)\n\n    template genImpl(dn: string)\n    template genSpec(dn: string)\n\nend\n
"},{"location":"cargo/em.core/em.utils/BoardDriversGenT/","title":"BoardDriversGenT","text":""},{"location":"cargo/em.core/em.utils/BoardDriversGenT/#unit-boarddriversgent","title":"unit BoardDriversGenT","text":"em.utils/BoardDriversGenT.em
package em.utils\n\nimport BoardInfo\n\ntemplate BoardDriversGenT\n\n    config driversPkg: string\n\nend\n\ndef em$generateUnit(pn, un)\n    auto brdRec = BoardInfo.readRecordH()\n    auto drvPkg = driversPkg\n            |->package `pn`\n            |-> \n    for dd in brdRec.drvDescs\n            |->from `drvPkg` import `dd.driver` as `dd.name`\n    end\n            |->\n            |->module `un`\n            |-> \n            |->end\nend\n
"},{"location":"cargo/em.core/em.utils/BoardInfo/","title":"BoardInfo","text":""},{"location":"cargo/em.core/em.utils/BoardInfo/#unit-boardinfo","title":"unit BoardInfo","text":"em.utils/BoardInfo.em
package em.utils\n\nfrom em$distro import BoardMeta as Meta\n\nhost module BoardInfo\n\n    const PROP_BOARD_CHAIN: string = \"em.lang.BoardChain_\"\n    const PROP_BOARD_KIND: string = \"em.lang.BoardKind\"\n\n    type PinMap: Meta.PinMap\n    type DrvDesc: Meta.DrvDesc\n    type Record: Meta.Record\n\n    function getKind(): string\n    function readRecordH(): Record&\n\nprivate:\n\n    function cacheGet(kind: string): Record&\n    function cacheSet(kind: string, rec: Record&)\n\n    function collapse(kind: string, db: ptr_t, set: ptr_t): ptr_t\n\n    function init()\n\n    function mergeBrd(baseBrd: ptr_t, extBrd: ptr_t)\n    function mergeDb(baseDb: ptr_t, extDb: ptr_t)\n\n    config baseFileLoc: string\n    config localFileLoc: string\n\n    config attrs: string[]\n    config pins: string[]\n\n    config boardKind: string\n\n    var initFlg: bool\n    var recCache: ptr_t\n\nend\n\ndef em$configure()\n    readRecordH()\nend\n\ndef cacheGet(kind)\n    ^^if (!BoardInfo.recCache) BoardInfo.recCache = {}^^\n    return ^^BoardInfo.recCache[kind]^^\nend\n\ndef cacheSet(kind, rec)\n    ^^BoardInfo.recCache[kind] = rec^^\nend\n\ndef collapse(kind, db, set)\n    return ^^db.$DEFAULTS^^ if ^^!kind || kind == '$DEFAULTS'^^\n    var ext: ptr_t = ^^db[kind]^^\n    if !ext\n        printf \"*** unknown board kind: '%s'\\n\", kind\n        fail\n    end\n    if ^^set.has(kind)^^\n        printf \"*** circular inheritance chain: '%s'\\n\", kind\n        fail\n    end\n    ^^set.add(kind)^^\n    var base: ptr_t = collapse(^^ext.$inherits^^, db, set)\n    mergeBrd(base, ext)\n    return base\nend\n\ndef getKind()\n    init()\n    return boardKind\nend\n\ndef init()\n    return if initFlg\n    initFlg = true\n    attrs = Meta.attrNames\n    pins = Meta.pinNames\n    baseFileLoc = Meta.baseFileLoc\n    auto path = ^^$Path.join(em$session.getRootDir(), 'em-boards-local')^^\n    localFileLoc = ^^$Fs.existsSync(path) ? path : null^^\n    boardKind = ^^em$props.get^^(PROP_BOARD_KIND)\nend\n\ndef mergeBrd(baseBrd, extBrd)\n    ^^var aTab = []^^\n    ^^for (a in extBrd) { aTab[a] = true; aTab.push(a) }^^\n    for a in attrs\n        ^^baseBrd[a] = extBrd[a]^^ if ^^a in extBrd^^\n        ^^aTab[a] = false^^\n    end\n    for i: uint8 = 0; i < ^^aTab.length^^; i++\n        var an: string = ^^aTab[i]^^\n        if an != \"pins\" && an != \"drvDescs\" && an != \"nvsFiles\" && ^^aTab[an]^^\n            printf \"*** unknown attribute name: %s\\n\", an\n            fail\n        end\n    end\n    #\n    ^^var pTab = []^^\n    ^^for (p in extBrd.pins) { pTab[p] = true; pTab.push(p) }^^\n    ^^baseBrd.pins = {}^^ if ^^!baseBrd.pins^^\n    for p in pins\n        ^^baseBrd.pins[p] = extBrd.pins[p]^^ if ^^extBrd.pins && p in extBrd.pins^^\n        ^^pTab[p] = false^^\n    end\n    for i: uint8 = 0; i < ^^pTab.length^^; i++\n        var pn: string = ^^pTab[i]^^\n        continue if ^^pn[0] == '$'^^\n        if ^^pTab[pn]^^\n            printf \"*** unknown pin name: %s\\n\", pn\n            fail\n        end\n    end\n    #\n    ^^baseBrd.drvDescs = extBrd.drvDescs^^ if ^^extBrd.drvDescs^^\n    ^^baseBrd.nvsFiles = extBrd.nvsFiles^^ if ^^extBrd.nvsFiles^^\nend\n\ndef mergeDb(baseDb, extDb)\n    ^^var brdSet = {}^^\n    ^^var brdArr = []^^\n    ^^for (b in baseDb) brdSet[b] = true^^\n    ^^for (b in extDb) brdSet[b] = true^^\n    ^^for (b in brdSet) brdArr.push(b)^^\n    for i: uint8 = 0; i < ^^brdArr.length^^; i++\n        ^^var brdKind = brdArr[i]^^\n        ^^var baseBrd = baseDb[brdKind]^^\n        ^^var extBrd = extDb[brdKind]^^\n        if ^baseBrd && ^extBrd\n            if ^^extBrd.$overrides^^\n                mergeBrd(^baseBrd, ^extBrd)\n            else\n                printf \"*** missing '$overrides' for %s\\n\", ^brdKind\n                fail\n            end\n        elif ^extBrd\n            if ^^extBrd.$overrides^^\n                printf \"*** no platform definition for '$overrides' for %s\\n\", ^brdKind\n                fail\n            else\n                ^^baseDb[brdKind] = extDb[brdKind]^^\n            end\n        end\n    end\nend\n\ndef readRecordH()\n    init()\n    if boardKind == null\n        printf \"*** null board kind\\n\"\n        fail\n    end\n    var rec: Record& = cacheGet(boardKind)\n    return rec if rec\n    var baseLoc: string = ^em$find(baseFileLoc)\n    var baseDb: ptr_t = ^^$Yaml.load($Fs.readFileSync(baseLoc), 'utf-8')^^\n    if localFileLoc != null\n        var localDb: ptr_t = ^^$Yaml.load($Fs.readFileSync(localFileLoc), 'utf-8')^^\n        mergeDb(baseDb, localDb)                    \n    end\n    var set: ptr_t = ^^new Set^^\n    var base: ptr_t = collapse(boardKind, baseDb, set)\n    var chain: ptr_t = ^^Array.from(set.values()).join('--')^^\n    ^^em$props.set^^(PROP_BOARD_CHAIN, chain)\n    rec = new <Record>\n    rec.pinMap = new <PinMap>\n    for a in attrs\n        ^^rec[a] = base[a]^^\n    end\n    for p in pins\n        ^^rec.pinMap[p] = base.pins[p]^^\n    end\n    ^^for (n in base.drvDescs) {^^\n        ^^var o = base.drvDescs[n]^^\n        rec.drvDescs[rec.drvDescs.length++] = new <DrvDesc> {\n            name: ^n, driver: ^^o.driver^^, params: ^^o.params^^\n        }\n    ^^}^^\n    cacheSet(boardKind, rec)\n    return rec\nend\n
"},{"location":"cargo/em.core/em.utils/BoardMeta/","title":"BoardMeta","text":""},{"location":"cargo/em.core/em.utils/BoardMeta/#unit-boardmeta","title":"unit BoardMeta","text":"em.utils/BoardMeta.em
package em.utils\n\nhost module BoardMeta\n\n    type PinMap: struct\n        pin: int8\n    end\n\n    type DrvDesc: struct\n        name: string\n        driver: string\n        params: ptr_t\n    end        \n\n    type Record: struct\n        attr: bool\n        pinMap: PinMap&\n        drvDescs: DrvDesc&[]\n    end\n\n    config baseFileLoc: string = \"biz.biosbob.distro.axm0f343/em-boards\"\n\n    config attrNames: string[] = [\n        \"$inherits\",\n        \"$overrides\",\n        \"attr\",\n    ]\n\n    config pinNames: string[] = [\n        \"pin\",\n    ] \n\nend\n
"},{"location":"cargo/em.core/em.utils/Bootup/","title":"Bootup","text":""},{"location":"cargo/em.core/em.utils/Bootup/#unit-bootup","title":"unit Bootup","text":"em.utils/Bootup.em
package em.utils\n\nmodule Bootup\n\n    type Fxn: function()\n\n    host function addFxnH(fxn: Fxn)\n\n    function exec()\n\nprivate:\n\n    config FXNTAB: Fxn volatile[]\n    config fxnCnt: uint8\n\nend\n\ndef em$construct()\n    FXNTABootMemory = true\nend\n\ndef addFxnH(fxn)\n    FXNTAB[fxnCnt++] = fxn\nend\n\ndef exec()\n    for auto i = 0; i < fxnCnt; i++\n        FXNTAB[i]()\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/BufPrint/","title":"BufPrint","text":""},{"location":"cargo/em.core/em.utils/BufPrint/#unit-bufprint","title":"unit BufPrint","text":"em.utils/BufPrint.em
package em.utils\n\nmodule BufPrint\n\n    config enabled: bool\n\n    function bswap(ptr: ptr_t, cnt: uint16, lab: string = null)\n    function bytes(ptr: ptr_t, cnt: uint16, lab: string = null)\n    function words(ptr: ptr_t, cnt: uint16, lab: string = null)\n\nprivate:\n\n    function label(lab: string)\n\nend\n\ndef bswap(ptr, cnt, lab)\n    if enabled\n        label(lab) if lab\n        printf \"[\"\n        auto pb = <uint8*>ptr\n        auto wc = ((cnt + 0x3) & ~0x3) / 4\n        auto sep = \"\"\n        while wc--\n            printf \"%s\", sep\n            sep = \", \"\n            var buf: uint8[4]\n            buf[0] = *pb++\n            buf[1] = *pb++\n            buf[2] = *pb++\n            buf[3] = *pb++\n            auto nb = cnt >= 4 ? 4 : cnt\n            cnt -= nb\n            auto idx = 3\n            while nb--\n                printf \"%02x\", buf[idx--]\n            end\n        end\n        printf \"]\\n\"\n    end\nend\n\ndef bytes(ptr, cnt, lab)\n    if enabled\n        label(lab) if lab\n        auto pb = <uint8*>ptr\n        while cnt--\n            printf \"%02x\", *pb++\n        end\n        printf \"\\n\"\n    end\nend\n\ndef label(lab)\n    printf \"%s = \", lab\nend\n\ndef words(ptr, cnt, lab)\n    if enabled\n        label(lab) if lab\n        printf \"[\"\n        auto pw = <uint32*>ptr\n        auto sep = \"\"\n        while cnt--\n            printf \"%s%08x\", sep, *pw++\n            sep = \", \"\n        end\n        printf \"]\\n\"\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/ButtonT/","title":"ButtonT","text":""},{"location":"cargo/em.core/em.utils/ButtonT/#unit-buttont","title":"unit ButtonT","text":"em.utils/ButtonT.em
package em.utils\n\ntemplate ButtonT\n\nend\n\ndef em$generateUnit(pn, un)\n|->>>\n    ## ---- generated by em.utils/ButtonT ---- ##\n    package `pn`\n\n    from em.hal import ButtonI\n    from em.hal import GpioEdgeDetectMinI\n\n    from em.mcu import Poller\n\n    from em.utils import FiberMgr\n\n    module `un`: ButtonI\n        #   ^| implements the ButtonI interface\n        proxy Edge: GpioEdgeDetectMinI\n        #   ^| a GPIO with edge-detection capabilities\n    private:\n\n        function buttonHandler: Edge.Handler\n        function debounceFB: FiberMgr.FiberBodyFxn\n\n        config debounceF: FiberMgr.Fiber&\n\n        var curDuration: uint16\n        var curCb: OnPressedCB\n        var maxDur: uint16\n        var minDur: uint16\n\n    end\n\n    def em$construct()\n        Edge.setDetectHandlerH(buttonHandler)\n        debounceF = FiberMgr.createH(debounceFB)\n    end \n\n    def em$startup()\n        Edge.makeInput()\n        Edge.setInternalPullup(true)\n        Edge.setDetectFallingEdge()\n    end\n\n    def buttonHandler()\n        Edge.clearDetect()\n        debounceF.post() if curCb\n    end\n\n    def debounceFB(arg)\n        curDuration = 0\n        for ;;\n            Poller.pause(minDur)\n            return if curDuration == 0 && !isPressed()\n            curDuration += minDur\n            break if !isPressed() || curDuration >= maxDur\n        end\n        curCb()\n    end\n\n    def isPressed()\n        return !Edge.get()\n    end\n\n    def onPressed(cb, minDurationMs, maxDurationMs)\n        curCb = cb\n        maxDur = maxDurationMs\n        minDur = minDurationMs\n        if cb == null\n            Edge.disableDetect()\n        else\n            Edge.enableDetect()\n        end\n    end\n|-<<<\nend\n
"},{"location":"cargo/em.core/em.utils/Checksum/","title":"Checksum","text":""},{"location":"cargo/em.core/em.utils/Checksum/#unit-checksum","title":"unit Checksum","text":"em.utils/Checksum.em
package em.utils\n\n# Fletcher-16 checksum\n\nmodule Checksum\n\n    type Obj: opaque\n        function addData(buf: uint8*, len: uint16)\n        function clear()\n        function getSum8(): uint8\n        function getSum16(): uint16\n    end\n\nprivate:\n\n    def opaque Obj\n        sum1: uint16\n        sum2: uint16\n    end\n\nend\n\ndef Obj.addData(ptr, len)\n    auto tl = <uint8>0\n    while len\n        tl = len >= 20 ? 20 : len\n        len -= tl\n        for ;;\n            this.sum2 += this.sum1 += *ptr++\n            tl -= 1\n            break if tl == 0\n        end\n        this.sum1 = (this.sum1 & 0xFF) + (this.sum1 >> 8)\n        this.sum2 = (this.sum2 & 0xFF) + (this.sum2 >> 8)\n    end\n    this.sum1 = (this.sum1 & 0xFF) + (this.sum1 >> 8)\n    this.sum2 = (this.sum2 & 0xFF) + (this.sum2 >> 8)\n#/*\n    for i: uint16 = 0; i < len; i++\n        this.sum1 += *ptr++\n        this.sum1 -= 255 if this.sum1 >= 255;\n        this.sum2 += this.sum1;\n        this.sum2 -= 255 if this.sum2 >= 255;\n    end\n#*/    \nend\n\ndef Obj.clear()\n    this.sum1 = this.sum2 = 0xFF\nend\n\ndef Obj.getSum8()\n    return <uint8>(this.sum1 ^ this.sum2)\nend\n\ndef Obj.getSum16()\n    return this.sum2 << 8 | this.sum1\nend\n
"},{"location":"cargo/em.core/em.utils/ConsoleProtocol/","title":"ConsoleProtocol","text":""},{"location":"cargo/em.core/em.utils/ConsoleProtocol/#unit-consoleprotocol","title":"unit ConsoleProtocol","text":"em.utils/ConsoleProtocol.em
package em.utils\n\nmodule ConsoleProtocol\n\n    const SOT_BYTE: uint8 = 0x3\n    const SOT_COUNT: uint8 = 13\n\n    const EOT_BYTE: uint8 = 0x4\n\nend\n
"},{"location":"cargo/em.core/em.utils/Copier/","title":"Copier","text":""},{"location":"cargo/em.core/em.utils/Copier/#unit-copier","title":"unit Copier","text":"em.utils/Copier.em
package em.utils\n\nfrom em.hal import CopierI\n\nmodule Copier: CopierI\n\nend\n\ndef exec(dst, src, cnt)\n    ^memcpy(dst, src, cnt)\nend\n
"},{"location":"cargo/em.core/em.utils/Crc16/","title":"Crc16","text":""},{"location":"cargo/em.core/em.utils/Crc16/#unit-crc16","title":"unit Crc16","text":"em.utils/Crc16.em
package em.utils\n\nmodule Crc16\n\n    type Obj: opaque\n        function addByte(b: uint8): uint8\n        function addData(src: uint8*, len: uint8)\n        function getSum(): uint16\n        function getSumLsb(): uint8\n        function getSumMsb(): uint8\n        function init()\n    end\n\n    host function createH(): Obj&\n\nprivate:\n\n    const POLY: uint16 = 0x8005\n\n    def opaque Obj\n        sum: uint16\n        function update(b: uint8)\n    end\n\nend\n\ndef createH()\n    return new<Obj>\nend\n\ndef Obj.addByte(b)\n    this.update(b)\n    return b\nend\n\ndef Obj.addData(src, len)\n    while len--\n        this.update(*src++)\n    end\nend\n\ndef Obj.getSum()\n    return this.sum\nend\n\ndef Obj.getSumLsb()\n    return <uint8>(this.sum & 0xFF)\nend\n\ndef Obj.getSumMsb()\n    return <uint8>(this.sum >> 8)\nend\n\ndef Obj.init()\n    this.sum = 0xFFFF\nend\n\ndef Obj.update(b)\n    auto tot = this.sum\n    for auto i = 0; i < 8; i++\n        if ((tot & 0x8000) >> 8) ^ (b & 0x80)\n            tot = (tot << 1) ^ POLY\n        else\n            tot = (tot << 1)\n        end\n        b <<= 1\n    end\n    this.sum = tot\nend\n
"},{"location":"cargo/em.core/em.utils/DebugPinAux/","title":"DebugPinAux","text":""},{"location":"cargo/em.core/em.utils/DebugPinAux/#unit-debugpinaux","title":"unit DebugPinAux","text":"em.utils/DebugPinAux.em
package em.utils\n\nfrom em.mcu import Common\n\nmodule DebugPinAux\n\n    type ToggleFxn: function()\n\n    config pulseDelay: int32 = -1\n\n    function pulse(toggleFxn: ToggleFxn)\n    function mark(toggleFxn: ToggleFxn, k: uint8)\n\nprivate:\n\n    function delay()\n\nend\n\ndef delay()\n    ## TODO -- finer granularity\n    Common.BusyWait.wait(<uint32>(-pulseDelay))\nend\n\ndef pulse(toggleFxn)\n    toggleFxn()\n    delay()\n    toggleFxn()\n    delay()\n\nend\n\ndef mark(toggleFxn, k)\n    while k--\n        pulse(toggleFxn)\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/DebugPinT/","title":"DebugPinT","text":""},{"location":"cargo/em.core/em.utils/DebugPinT/#unit-debugpint","title":"unit DebugPinT","text":"em.utils/DebugPinT.em
package em.utils\n\ntemplate DebugPinT\n\nend\n\ndef em$generateUnit(pn, un)\n|->>>\npackage `pn`\n\nfrom em.utils import DebugPinAux as Aux\nfrom em.lang import DebugPinI\nfrom em.hal import GpioI\n\nmodule `un`: DebugPinI\n\n    proxy Pin: GpioI\n\nend\n\ndef clear()\n    Pin.set()\nend\n\ndef get()\n    return Pin.get() != 0\nend\n\ndef set()\n    Pin.clear()\nend\n\ndef toggle()\n    Pin.toggle()\nend\n\ndef pulse()\n    Aux.pulse(<Aux.ToggleFxn>toggle)\nend\n\ndef mark(k)\n    Aux.mark(<Aux.ToggleFxn>toggle, k)\nend\n\ndef reset()\n    Pin.reset()\nend\n\ndef startup()\n    Pin.makeOutput()\n    Pin.set()\nend\n|-<<<\nend\n
"},{"location":"cargo/em.core/em.utils/EpochTime/","title":"EpochTime","text":""},{"location":"cargo/em.core/em.utils/EpochTime/#unit-epochtime","title":"unit EpochTime","text":"em.utils/EpochTime.em
package em.utils\n\nfrom em.hal import UptimerI\n\nmodule EpochTime\n\n    proxy Uptimer: UptimerI\n\n    type UpdateFxn: function(esecs: uint32, esubs: uint32)\n\n    host function bindUpdateFxnH(fxn: UpdateFxn)\n\n    function getCurrent(oSubs: uint32* = null): uint32\n    function getRaw(oSubs: uint32* = null): uint32\n    function mkSecs256(secs: uint32, subs: uint32): uint32\n    function setCurrent(eSecs: uint32, eSubs: uint32 = 0, syncFlag: bool = false)\n\nprivate:\n\n    config updateFxn: UpdateFxn\n\n    var deltaSecs: uint32\n    var deltaSubs: uint32\n\n    var lastSecs256: uint32\n    var lastTicks: uint32\n\n    function compute(time: Uptimer.Time&, oSubs: uint32*): uint32\n\nend\n\ndef bindUpdateFxnH(fxn)\n    updateFxn = fxn\nend\n\ndef compute(time, oSubs)\n    auto eSubs = time.subs + deltaSubs\n    auto inc = eSubs < time.subs ? 1 : 0\n    (*oSubs) = eSubs if oSubs\n    return time.secs + deltaSecs + inc\nend\n\ndef getCurrent(oSubs)\n    return compute(Uptimer.read(), oSubs)\nend\n\ndef getRaw(oSubs)\n    auto time = Uptimer.read()\n    *oSubs = time.subs if oSubs\n    return time.secs\nend\n\ndef mkSecs256(secs, subs)\n    return (secs << 8) | (subs >> 24)\nend\n\ndef setCurrent(eSecs, eSubs, syncFlag)\n    auto time = Uptimer.read()\n    deltaSubs = eSubs - time.subs\n    auto dec = deltaSubs > eSubs ? 1 : 0\n    deltaSecs = eSecs - time.secs - dec\n    auto eSecs256 = mkSecs256(eSecs, eSubs)\n    if syncFlag\n        Uptimer.calibrate(eSecs256 - lastSecs256, time.ticks - lastTicks) if lastSecs256\n        lastSecs256 = eSecs256\n        lastTicks = time.ticks\n    else\n        lastSecs256 = lastTicks = 0\n    end\n    var subs: uint32\n    auto secs = compute(time, &subs)\n    updateFxn(eSecs, eSubs) if updateFxn\nend\n
"},{"location":"cargo/em.core/em.utils/Error/","title":"Error","text":""},{"location":"cargo/em.core/em.utils/Error/#unit-error","title":"unit Error","text":"em.utils/Error.em
package em.utils\n\nimport Logger\n\nmodule Error\n\n    type Kind: enum\n        APPLICATION, ASSERTION, EXCEPTION, EXPIRATION, WATCHDOG\n    end\n\n    type RaiseFxn: function (kind: Kind, infoA: iarg_t, infoB: iarg_t)\n\n    host function bindOnRaiseH(fxn: RaiseFxn)\n    function raise: RaiseFxn\n\nprivate:\n\n    config KIND_ATOM: atom_t[] = [\n        @\"APPLICATION\", @\"ASSERTION\", @\"EXCEPTION\", @\"EXPIRATION\", @\"WATCHDOG\"\n    ]\n\n    config errorE: Logger.EventKind&\n    config onRaiseFxn: RaiseFxn\n\nend\n\ndef em$construct()\n    ## TODO -- atomize error kind\n    errorE = Logger.declareEventH(\"ERROR: $a [0x%08x, 0x%08x]\", \"*--*\")\nend\n\ndef bindOnRaiseH(fxn)\n    onRaiseFxn = fxn\nend\n\ndef raise(kind, infoA, infoB)\n    errorE.log(<addr_t>KIND_ATOM[<uint8>kind], <addr_t>infoA, <addr_t>infoB)\n    onRaiseFxn(kind, infoA, infoB) if onRaiseFxn\nend\n
"},{"location":"cargo/em.core/em.utils/FftC32/","title":"FftC32","text":""},{"location":"cargo/em.core/em.utils/FftC32/#unit-fftc32","title":"unit FftC32","text":"em.utils/FftC32.em
package em.utils\n\nfrom em.lang import Math\n\nmodule FftC32\n\n    type Complex: class\n        re: int16\n        im: int16\n        function get(): uint32\n        function set(w: uint32)\n    end\n\n    config fftSize: uint16 = 128\n    config shift: uint8 = 1\n\n    function exec(buf: Complex[])\n\nprivate:\n\n    config N_WAVE: uint16\n    config N_WAVE_LOG2: uint8\n\n    config SINE_WAVE: int16[]\n\n    function fixMul(a: int16, b: int16): int16\n\nend\n\ndef em$construct()\n    N_WAVE = fftSize\n    N_WAVE_LOG2 = Math.log2(N_WAVE)\n    auto numHalf = N_WAVE / 2\n    auto numQtr = N_WAVE / 4\n    SINE_WAVE.length = N_WAVE - numQtr\n    auto rng = Math.PI / 2\n    for auto i = 0; i < SINE_WAVE.length; i++\n        if i <= numQtr\n            auto sx = Math.sin((rng / numQtr) * i)\n            SINE_WAVE[i] = Math.round(sx * 32767) >> shift\n        elif i < numHalf\n            SINE_WAVE[i] = SINE_WAVE[numHalf - i]\n        else\n            SINE_WAVE[i] = -(SINE_WAVE[i - numHalf])\n        end\n    end\nend\n\ndef exec(buf)\n    auto mr = 0\n    for auto m = 1; m < fftSize; m++\n        auto l = fftSize\n        for ;;\n            l >>= 1\n            continue if mr + l > fftSize - 1\n            break\n        end\n        mr = (mr & (l - 1)) + l\n        continue if mr <= m\n        auto t = buf[m].get()\n        buf[m].set(buf[mr].get())\n        buf[mr].set(t)\n    end\n    auto stage = 1\n    auto sineStep = N_WAVE_LOG2 - 1\n    while stage < fftSize\n        auto twiddleStep = stage << 1\n        for auto grp = 0; grp < stage; grp++\n            auto idx = grp << sineStep\n            auto wr = SINE_WAVE[idx + N_WAVE / 4]\n            auto wi = -SINE_WAVE[idx]\n            for auto i = grp; i < fftSize; i += twiddleStep\n                auto j = i + stage\n                auto fci = &buf[i]\n                auto fcj = &buf[j]\n                auto tr = fixMul(wr, fcj.re) - fixMul(wi, fcj.im)\n                auto ti = fixMul(wr, fcj.im) + fixMul(wi, fcj.re)\n                auto qr = fci.re >> shift\n                auto qi = fci.im >> shift\n                fcj.re = qr - tr\n                fcj.im = qi - ti\n                fci.re = qr + tr\n                fci.im = qi + ti\n            end\n        end\n        sineStep -= 1\n        stage = twiddleStep\n    end\nend\n\n\ndef fixMul(a, b)\n    auto c = (<int32>a * <int32>b) >> 14\n    b = <int16>(<uint32>c & 0x01)\n    a = <int16>((c >> 1) + b)\n    return a\nend\n\ndef Complex.get()\n    return *(<uint32*>this)\nend\n\ndef Complex.set(w)\n    *(<uint32*>this) = w\nend\n
"},{"location":"cargo/em.core/em.utils/FftQ15/","title":"FftQ15","text":""},{"location":"cargo/em.core/em.utils/FftQ15/#unit-fftq15","title":"unit FftQ15","text":"em.utils/FftQ15.em
package em.utils\n\nfrom em.lang import Math\n\nmodule FftQ15\n\n    config fftSize: uint16 = 128\n    config shift: uint8 = 1\n\n    function exec(fr: int16[], fi: int16[])\n\nprivate:\n\n    config N_WAVE: uint16\n    config N_WAVE_LOG2: uint8\n\n    config SINE_WAVE: int16[]\n\n    function fixMul(a: int16, b: int16): int16\n\nend\n\ndef em$construct()\n    N_WAVE = fftSize\n    N_WAVE_LOG2 = Math.log2(N_WAVE)\n    auto numHalf = N_WAVE / 2\n    auto numQtr = N_WAVE / 4\n    SINE_WAVE.length = N_WAVE - numQtr\n    auto rng = Math.PI / 2\n    for auto i = 0; i < SINE_WAVE.length; i++\n        if i <= numQtr\n            auto sx = Math.sin((rng / numQtr) * i)\n            SINE_WAVE[i] = Math.round(sx * 32767) >> shift\n        elif i < numHalf\n            SINE_WAVE[i] = SINE_WAVE[numHalf - i]\n        else\n            SINE_WAVE[i] = -(SINE_WAVE[i - numHalf])\n        end\n    end\nend\n\ndef exec(fr, fi)\n    auto mr = 0\n    for auto m = 1; m < fftSize; m++\n        auto l = fftSize\n        for ;;\n            l >>= 1\n            continue if mr + l > fftSize - 1\n            break\n        end\n        mr = (mr & (l - 1)) + l\n        continue if mr <= m\n        auto tr = fr[m]\n        fr[m] = fr[mr]\n        fr[mr] = tr\n        auto ti = fi[m]\n        fi[m] = fi[mr]\n        fi[mr] = ti\n    end\n    auto stage = 1\n    auto sineStep = N_WAVE_LOG2 - 1\n    while stage < fftSize\n        auto twiddleStep = stage << 1\n        for auto grp = 0; grp < stage; grp++\n            auto idx = grp << sineStep\n            auto wr = SINE_WAVE[idx + N_WAVE / 4]\n            auto wi = -SINE_WAVE[idx]\n            for auto i = grp; i < fftSize; i += twiddleStep\n                auto j = i + stage\n                auto tr = fixMul(wr, fr[j]) - fixMul(wi, fi[j])\n                auto ti = fixMul(wr, fi[j]) + fixMul(wi, fr[j])\n                auto qr = fr[i] >> shift\n                auto qi = fi[i] >> shift\n                fr[j] = qr - tr\n                fi[j] = qi - ti\n                fr[i] = qr + tr\n                fi[i] = qi + ti\n            end\n        end\n        sineStep -= 1\n        stage = twiddleStep\n    end\nend\n\ndef fixMul(a, b)\n    auto c = (<int32>a * <int32>b) >> 14\n    b = <int16>(<uint32>c & 0x01)\n    a = <int16>((c >> 1) + b)\n    return a\nend\n
"},{"location":"cargo/em.core/em.utils/FiberMgr/","title":"FiberMgr","text":""},{"location":"cargo/em.core/em.utils/FiberMgr/#unit-fibermgr","title":"unit FiberMgr","text":"em.utils/FiberMgr.em
package em.utils\n\nfrom em.mcu import Common\nfrom em.utils import ListMgr\n\nmodule FiberMgr\n            #   ^| manages opaque fiber objects\n    type FiberBodyFxn: function(arg: uarg_t)\n            #   ^| function signature of fiber body\n    type Fiber: opaque\n            #   ^| opaque fiber object - public specification\n        host function initH(fxn: FiberBodyFxn, arg: uarg_t = 0)\n            #   ^| initialize this fiber and bind its function and argument\n        function getArg(): uarg_t\n            #   ^| get this fiber's body function argument\n        function getFxn(): FiberBodyFxn\n            #   ^| get this fiber's body function\n        function post()\n            #   ^| make this fiber ready-to-run\n        function setArg(a: uarg_t)\n            #   ^| set this fiber's body function argument\n        function setFxn(f: FiberBodyFxn)\n            #   ^| set this fiber's body function\n    end\n\n    host function createH(fxn: FiberBodyFxn, arg: uarg_t = 0): Fiber&\n            #   ^| allocate and initialize a fiber; see Fiber.initH\n    function run()\n            #   ^| initiate dispatch of ready-to-run fibers\nprivate:\n\n    def opaque Fiber\n        elem: ListMgr.Element\n        fxn_: FiberBodyFxn\n        arg_: uarg_t\n    end\n\n    function dispatch()\n\n    var fiberTab: Fiber[]\n    var readyList: ListMgr.List\n\nend\n\ndef em$construct() \n    readyList.initH()\nend\n\ndef createH(fxn, arg)\n    var fiber: Fiber& = fiberTab[fiberTab.length++]\n    fiber.initH(fxn, arg)\n    return fiber\nend\n\ndef dispatch()\n    for ;;\n        break if readyList.hasElements() == 0\n        auto fiber = <Fiber&>readyList.get()\n        Common.GlobalInterrupts.enable()\n        auto fxn = fiber.fxn_\n        fxn(fiber.arg_)\n        Common.GlobalInterrupts.disable()\n    end   \nend\n\ndef run()\n    Common.Idle.wakeup()\n    Common.GlobalInterrupts.enable()\n    for ;;\n        Common.GlobalInterrupts.disable()\n        dispatch()\n        Common.Idle.exec()\n    end\nend\n\ndef Fiber.initH(fxn, arg)\n    this.elem.initH()\n    this.fxn_ = fxn\n    this.arg_ = arg\nend\n\ndef Fiber.post()\n    auto key = Common.GlobalInterrupts.disable()\n    readyList.add(this.elem) if !this.elem.isActive()\n    Common.GlobalInterrupts.restore(key)\nend\n\ndef Fiber.getArg()\n    return this.arg_\nend\n\ndef Fiber.setArg(a)\n    this.arg_ = a\nend\n\ndef Fiber.setFxn(f)\n    this.fxn_ = f\nend\n\ndef Fiber.getFxn()\n    return this.fxn_\nend\n
"},{"location":"cargo/em.core/em.utils/Formatter/","title":"Formatter","text":""},{"location":"cargo/em.core/em.utils/Formatter/#unit-formatter","title":"unit Formatter","text":"em.utils/Formatter.em
package em.utils\n\nfrom em.lang import Console\n\nmodule Formatter\n\n    function print(fmt: string, a1: iarg_t = 0, a2: iarg_t = 0, a3: iarg_t = 0, a4: iarg_t = 0, a5: iarg_t = 0, a6: iarg_t = 0)\n    function puts(s: string)\n\nprivate:\n\n    const OUTMAX: uint8 = ((32 + 2) / 3) + 5\n\n    function c2d(c: char): uint8\n    function formatNum(buf: char*, num: uint32, base: uint8, pad: char, len: uint8): char*\n    function isDigit(c: char): bool\n\n    config hexDigs: string = \"0123456789abcdef\"\n\nend\n\ndef c2d(c)\n    return c - '0'\nend\n\ndef formatNum(buf, num, base, pad, len)\n    auto cnt = len\n    *(--buf) = 0\n    for ;;\n        *(--buf) = hexDigs[<uint8> (num % base)]\n        num /= base\n        break if len > 0 && --cnt == 0\n        break if num == 0\n    end\n    while cnt-- > 0\n        *(--buf) = pad\n    end\n    return buf\nend\n\ndef isDigit(c)\n    return c >= '0' && c <= '9'\nend\n\ndef print(fmt, a1, a2, a3, a4, a5, a6)\n    var ch: char\n    var buf: char[OUTMAX]\n    var args: iarg_t[6]\n    var argp: iarg_t* = &args[0]\n    args[0] = a1\n    args[1] = a2\n    args[2] = a3\n    args[3] = a4\n    args[4] = a5\n    args[5] = a6\n    while (ch = *fmt++) != 0\n        auto pad = ' '\n        auto len = 0\n        if (ch != '%') \n            Console.wrC(ch)\n            continue\n        end\n        ch = *fmt++\n        if ch == '0'\n            pad = '0'\n            ch = *fmt++\n            end\n        while isDigit(ch)\n            len = (len * 10) + c2d(ch)\n            ch = *fmt++\n            end\n        var out: char*\n        if ch == 'd'\n            var dn: int32 = <int32> *argp++\n            if dn < 0\n                Console.wrC('-')\n                dn = -dn\n            end\n            out = formatNum(&buf[OUTMAX], <uint32> dn, 10, pad, len)\n        elif ch == 'x' \n            var xn: uint32 = <uint32> *argp++\n            out = formatNum(&buf[OUTMAX], xn, 16, pad, len)\n        elif ch == 's'\n            out = <char*> *argp++\n        else\n            Console.wrC(ch == 'c' ? <char> *argp++ : ch)\n            continue\n        end\n        puts(<string>out)\n    end\nend\n\ndef puts(s)\n    var cp: char* = <char*>s\n    var ch: char\n    while (ch = *cp++) != 0\n        Console.wrC(ch)\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/FormattingConsole/","title":"FormattingConsole","text":""},{"location":"cargo/em.core/em.utils/FormattingConsole/#unit-formattingconsole","title":"unit FormattingConsole","text":"em.utils/FormattingConsole.em
package em.utils\n\nfrom em.lang import ConsoleProviderI\n\nfrom em.mcu import ConsoleUart\n\nimport Formatter\n\nmodule FormattingConsole: ConsoleProviderI\n\nend\n\ndef flush()\n    ConsoleUart.flush()\nend\n\ndef print(fmt, a1, a2, a3, a4, a5, a6)\n    Formatter.print(fmt, a1, a2, a3, a4, a5, a6)\nend\n\ndef put(data)\n    ConsoleUart.put(data)\nend\n
"},{"location":"cargo/em.core/em.utils/HeapMem/","title":"HeapMem","text":""},{"location":"cargo/em.core/em.utils/HeapMem/#unit-heapmem","title":"unit HeapMem","text":"em.utils/HeapMem.em
package em.utils\n\nfrom em.mcu import Common\nfrom em.mcu import Copier\n\nmodule HeapMem\n\n    config baseAddr: addr_t\n    config maxBytes: uint16\n\n    function alloc(size: uint16): ptr_t\n    function avail(): uint16\n    function mark()\n    function release()\n\nprivate:\n\n    var curTopPtr: uint32*\n    var savTopPtr: uint32*\n\nend\n\ndef em$startup()\n    return if Common.Mcu.isWarm()\n    curTopPtr = baseAddr\nend\n\ndef alloc(size)\n    auto ptr = curTopPtr\n    auto wc = ((size + 3) & ~0x3) / 4\n    curTopPtr += wc\n    return ptr\nend\n\ndef avail()\n    return <uint16>((baseAddr + maxBytes) - <uint32>curTopPtr)\nend\n\ndef mark()\n    *curTopPtr = <uint32>savTopPtr\n    savTopPtr = curTopPtr++\nend\n\ndef release()\n    fail if !savTopPtr\n    curTopPtr = savTopPtr\n    savTopPtr = <uint32*>*curTopPtr\n\n\nend\n
"},{"location":"cargo/em.core/em.utils/HeapStatic/","title":"HeapStatic","text":""},{"location":"cargo/em.core/em.utils/HeapStatic/#unit-heapstatic","title":"unit HeapStatic","text":"em.utils/HeapStatic.em
package em.utils\n\nfrom em.mcu import Common\n\nmodule HeapStatic\n\n    config baseAddr: addr_t\n    config maxBytes: uint16\n\n    host function allocH(size: uint16): ptr_t\n\n    function getTopAddr(): addr_t\n    host function getTopAddrH(): addr_t\n\nprivate:\n\n    const MASK: uint32 = 0x3\n    config topAddr: addr_t\nend\n\ndef em$construct()\n    return if baseAddr || maxBytes == 0\n    printf \"*** HeapStatic:  baseAddr == 0\\n\"\n    fail\nend\n\ndef em$startup()\n    return if Common.Mcu.isWarm()\n    ^memset(<ptr_t>baseAddr, 0, topAddr - baseAddr) if topAddr && Common.Mcu.getResetCode() <= Common.Mcu.COLD_RESET\nend\n\ndef allocH(size)\n    topAddr = baseAddr if topAddr == 0\n    auto p = <ptr_t>topAddr\n    topAddr += size\n    topAddr = (topAddr + MASK) & ~MASK\n    return p if (topAddr - baseAddr) < maxBytes\n    printf \"*** HeapStatic.allocH: maxBytes = %d, size = %d\\n\", maxBytes, size\n    fail\nend\n\ndef getTopAddr()\n    return topAddr\nend\n\ndef getTopAddrH()\n    return topAddr\nend\n
"},{"location":"cargo/em.core/em.utils/LedBlinkerI/","title":"LedBlinkerI","text":""},{"location":"cargo/em.core/em.utils/LedBlinkerI/#unit-ledblinkeri","title":"unit LedBlinkerI","text":"em.utils/LedBlinkerI.em
package em.utils\n\nfrom em.hal import LedI\n\ninterface LedBlinkerI: LedI\n\n    function blink(count: uint16, rateSecs: uint16 = 1, rateMs: uint16 = 0)\n\nend\n
"},{"location":"cargo/em.core/em.utils/LedBlinkerT/","title":"LedBlinkerT","text":""},{"location":"cargo/em.core/em.utils/LedBlinkerT/#unit-ledblinkert","title":"unit LedBlinkerT","text":"em.utils/LedBlinkerT.em
package em.utils\n\ntemplate LedBlinkerT\n\nend\n\ndef em$generateUnit(pn, un)\n|->>>\npackage `pn`\n\nfrom em.hal import LedI\n\nfrom em.utils import LedBlinkerAux\nfrom em.utils import LedBlinkerI\n\nmodule `un`: LedBlinkerI\n\n    proxy Led: LedI\n\nend\n\ndef isOn()\n    return Led.isOn()\nend\n\ndef on()\n    Led.on()\nend\n\ndef off()\n    Led.off()\nend\n\ndef toggle()\n    Led.toggle()\nend\n\ndef blink(count, rateSecs, rateMs)\n    LedBlinkerAux.setFxns(Led.on, Led.off)\n    LedBlinkerAux.blink(count, rateSecs, rateMs)\nend\n\ndef wink(onMs, offMs)\n    LedBlinkerAux.setFxns(Led.on, Led.off)\n    LedBlinkerAux.wink(onMs, offMs)\nend\n|-<<<\nend\n
"},{"location":"cargo/em.core/em.utils/LedT/","title":"LedT","text":""},{"location":"cargo/em.core/em.utils/LedT/#unit-ledt","title":"unit LedT","text":"em.utils/LedT.em
package em.utils\n\ntemplate LedT \n\nend\n\ndef em$generateUnit(pn, un)\n|->>>\n    package `pn`\n\n    from em.hal import LedI\n    from em.hal import GpioI\n\n    from em.mcu import Poller\n\n    module `un`: LedI\n        proxy Pin: GpioI\n        config activeLow: bool = false\n    end\n\n    def em$startup()\n        Pin.makeOutput()\n        if activeLow\n            Pin.set()            \n        else \n            Pin.clear()                \n        end\n    end\n\n    def on()\n        if activeLow\n            Pin.clear()            \n        else \n            Pin.set()                \n        end   \n    end\n\n    def off()\n        if activeLow\n            Pin.set()            \n        else \n            Pin.clear()                \n        end   \n    end\n\n    def toggle()\n        Pin.toggle()\n    end\n\n    def isOn()\n        return activeLow ? !Pin.get() : Pin.get()\n    end\n\n    def wink(msecs)\n        on()\n        Poller.pause(msecs)\n        off()\n    end          \n|-<<<\nend\n
"},{"location":"cargo/em.core/em.utils/ListManagerI/","title":"ListManagerI","text":""},{"location":"cargo/em.core/em.utils/ListManagerI/#unit-listmanageri","title":"unit ListManagerI","text":"em.utils/ListManagerI.em
package em.utils\n\n#! Implemented by a List Manager module\n#! Element and List declarations.\n\ninterface ListManagerI \n\n    type Element: opaque \n\n        #! Target and Host function to initialize an Element\n        function init()\n        host function initH()\n\n        #! Returns non-null if the Element is currently a member of a List\n        function isActive(): uarg_t\n    end\n\n    type List: opaque \n\n        #! Target and Host function to initialize a List\n        function init()\n        host function initH()\n\n        #! Adds an element to the List as defined by the List Manager\n        function add(elem: Element&)\n\n        #! Returns a reference to an Element and removes it from the List\n        function get(): ref_t\n\n        #! Returns a reference to the Element at the specified index\n        function getAt(index: uint8): ref_t\n\n        #! Returns a reference to the next Element from the specified Element\n        function getNext(elem: Element&): ref_t\n\n        #! Returns a non-zero value if the List is not empty\n        function hasElements(): uarg_t\n\n        #! Displays information about the List\n        function print()\n\n        #! Removes the specified Element from the List\n        function remove(elem: Element&)\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/ListMgr/","title":"ListMgr","text":""},{"location":"cargo/em.core/em.utils/ListMgr/#unit-listmgr","title":"unit ListMgr","text":"em.utils/ListMgr.em
package em.utils\n\nmodule ListMgr\n\n    type Element: opaque \n\n        function init()\n        host function initH()\n\n        function isActive(): uarg_t\n    end\n\n    type List: opaque \n\n        function init()\n        host function initH()\n\n        function add(elem: Element&)\n        function get(): ref_t\n        function getAt(index: uint8): ref_t\n        function getNext(elem: Element&): ref_t\n        function hasElements(): uarg_t\n        function print()\n        function remove(elem: Element&)\n    end\n\nprivate:\n\n    def opaque Element \n        next: Element& volatile\n    end\n\n    def opaque List \n        first: Element& volatile\n        last: Element& volatile\n    end\nend\n\ndef Element.init() \n    this.next = null\nend\n\ndef Element.initH() \n    this.next = null\nend\n\ndef Element.isActive() \n    return <uarg_t> this.next\nend\n\ndef List.init() \n    this.first = this.last = <Element&> &this.first\nend\n\ndef List.initH() \n    this.first = this.last = <Element&> &this.first;\nend\n\ndef List.add(elem)\n    this.last.next = elem\n    this.last = elem\n    elem.next = <Element&> this\nend\n\ndef List.get() \n    auto elem = this.first\n    this.last = <Element&>this if (this.first = elem.next) == <Element&>this\n    elem.next = null\n    return elem\nend\n\ndef List.getAt(index)\n    auto elem = this.first\n    auto i = 0\n    if this.hasElements()\n        for ;;\n            break if i++ == index                \n            elem = elem.next                \n            break if elem == <Element&> this\n        end\n        elem = null if elem == <Element&> this\n    else \n        elem = null\n    end\n    return elem\nend\n\ndef List.getNext(elem) \n    return elem == this.last ? null : elem.next\nend\n\ndef List.hasElements() \n    return (<uarg_t> this.first) ^ <uarg_t> this\nend\n\ndef List.print() \n    auto elem = this.first\n    auto i = 0\n    if this.hasElements()\n        for ;;\n            printf \"elem%d %p\\n\", i++, elem\n            elem = elem.next\n            break if elem == <Element&> this\n        end\n    else \n        printf \"list empty\\n\"\n    end\n    printf \"\\n\" \nend\n\ndef List.remove(elem)\n    auto e = this.first\n    if this.hasElements()\n        if elem == this.first\n            this.first = this.first.next\n        else \n            for ;; \n                if e.next == elem\n                    e.next = elem.next                    \n                    break    \n                end \n                break if e == <Element&> this\n            end\n        end\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/LoaderAuxI/","title":"LoaderAuxI","text":""},{"location":"cargo/em.core/em.utils/LoaderAuxI/#unit-loaderauxi","title":"unit LoaderAuxI","text":"em.utils/LoaderAuxI.em
package em.utils\n\ninterface LoaderAuxI\n\n    function jumpTo(codeAddr: addr_t)\n\nend\n
"},{"location":"cargo/em.core/em.utils/Logger/","title":"Logger","text":""},{"location":"cargo/em.core/em.utils/Logger/#unit-logger","title":"unit Logger","text":"em.utils/Logger.em
package em.utils\n\nfrom em.hal import FlashI\nfrom em.hal import FlashN\n\nfrom em.lang import Assert\nfrom em.mcu import Common\nfrom em.lang import Console\n\nimport EpochTime\nimport Formatter\nimport HeapStatic\n\nmodule Logger\n\n    proxy Flash: FlashI\n\n    type Accum: opaque\n        function add(val: uint32 = 0)\n        function clear()\n        function getBin(idx: uint8): uint32\n        function getCount(): uint32\n        function getMax(): uint32\n        function print()\n    end\n\n    type EventKind: opaque\n        function cache(a1: addr_t = 0, a2: addr_t = 0, a3: addr_t = 0)\n        function log(a1: addr_t = 0, a2: addr_t = 0, a3: addr_t = 0)\n        function print(a1: addr_t = 0, a2: addr_t = 0, a3: addr_t = 0)\n    end\n\n    type Policy: enum\n        NIL, QUIET, PRINT, STORE\n    end\n\n    config POLICY: Policy = Policy.NIL\n    config ENTRY_COUNT: uint16 = 16\n    config STORE_SECTOR: uint8 = 0\n\n    host function createAccumH(lab: string, grp: string, lims: uint32[] = null): Accum&\n    host function declareEventH(msg: string, grp: string): EventKind&\n\n    function flush()\n    function isEmpty(): bool\n    function mkTime(): uint32\n    function print()\n    function putBytes(bp: uint8*, cnt: uint16)\n    function putc(b: uint8)\n    function store()\n\nprivate:\n\n    const PKT_CODE: uint8 = 0xFE\n    const EVT_CODE: uint8 = 0xFD\n    const ACC_CODE: uint8 = 0xFC\n    const BEG_CODE: uint8 = 0xFB\n    const END_CODE: uint8 = 0xFA\n\n    type Group: class\n        chars: char[4]\n        host function initH(gs: string)\n    end\n\n    def opaque Accum\n        data: uint32[]\n        metaIdx: uint8\n        function getMeta(): AccumMeta&\n    end\n\n    type AccumMeta: struct\n        lab: string\n        lims: uint32[]\n        hasMax: bool\n        limCnt: uint8\n        group: Group\n        size: uint8\n    end\n\n    def opaque EventKind\n        msg: string\n        kidx: uint16\n        group: Group\n    end\n\n    type EventInst: class\n        time: uint32\n        a1: iarg_t\n        a2: iarg_t\n        a3: iarg_t\n        kidx: uint16\n        function put()\n    end\n\n    type Cursor: class\n        idx: uint16\n        function next(): EventInst&\n    end\n\n    config accMetaTab: AccumMeta[]\n\n    config sectBeg: addr_t\n    config sectEnd: addr_t\n\n    config totalAccSize: uint16\n\n    var accTab: Accum&[..]\n    var evkTab: EventKind&[..]\n\n    var buf: EventInst[]\n    var curs: Cursor&\n\nend\n\ndef em$configure()\n    Flash ?= FlashN\nend\n\ndef em$construct()\n    buf = HeapStatic.allocH(sizeof<EventInst> * ENTRY_COUNT) if POLICY != Policy.NIL\n    curs = HeapStatic.allocH(sizeof<Cursor>) if POLICY != Policy.NIL\n    sectBeg = <addr_t>(Flash.getSectorSizeH() * STORE_SECTOR)\n    sectEnd = sectBeg + Flash.getSectorSizeH()\n end\n\ndef createAccumH(lab, grp, lims)\n    return null if POLICY == Policy.NIL\n    auto accMeta = <AccumMeta&>accMetaTab[accMetaTab.length++]\n    accMeta.lab = lab\n    accMeta.group.initH(grp)\n    accMeta.hasMax = (lims != null)\n    accMeta.lims = lims if accMeta.hasMax\n    accMeta.limCnt = <uint8>lims.length if accMeta.hasMax\n    accMeta.size = (1 + (!accMeta.hasMax ? 0 : (1 + accMeta.limCnt))) * sizeof<uint32>\n    auto acc = new<Accum>\n    accTab[accTab.length++] = acc\n    acc.data = HeapStatic.allocH(accMeta.size)\n    acc.metaIdx = <uint8>accMetaTab.length\n    totalAccSize += accMeta.size\n    return acc\nend\n\ndef declareEventH(msg, grp)\n    return null if POLICY == Policy.NIL\n    auto ek = new<EventKind>\n    evkTab[evkTab.length++] = ek\n    ek.kidx = evkTab.length\n    ek.msg = <string>msg\n    ek.group.initH(grp)\n    return ek\nend\n\ndef flush()\n    print() if POLICY == Policy.PRINT\n    store() if POLICY == Policy.QUIET || POLICY == Policy.STORE\nend\n\ndef isEmpty()\n    if POLICY != Policy.NIL\n        for acc in accTab\n            return false if acc.data[0]\n        end\n        for auto i = 0; i < ENTRY_COUNT; i++\n            return false if buf[i].kidx != 0\n        end\n    end\n    return true\nend\n\ndef mkTime()\n    var subs: uint32\n    auto secs = EpochTime.getRaw(&subs)\n    return (secs << 8) | (subs >> 24)\nend\n\ndef print()\n    if POLICY > Policy.QUIET\n        putc(PKT_CODE)\n        putc(BEG_CODE)\n        for acc in accTab\n            acc.print()\n        end\n        for auto i = 0; i < ENTRY_COUNT; i++\n            auto evt = curs.next()\n            continue if evt.kidx == 0\n            evt.put()\n        end\n        putc(PKT_CODE)\n        putc(END_CODE)\n    end\nend\n\ndef putBytes(bp, cnt)\n    while cnt--\n        auto b = *bp++\n        putc(PKT_CODE) if b == PKT_CODE\n        putc(b)\n    end\nend\n\ndef putc(b)\n    Console.Provider.put(b)\nend\n\ndef store()\n    if POLICY != Policy.NIL && STORE_SECTOR > 0\n        auto saddr = sectBeg\n        Flash.erase(saddr)\n        var et: uint32 = EpochTime.getCurrent()\n        saddr = Flash.write(saddr, &et, sizeof<uint32>)\n        for acc in accTab\n            saddr = Flash.write(saddr, &acc.data[0], acc.getMeta().size)\n        end\n        for auto i = 0; i < ENTRY_COUNT; i++\n            auto evt = curs.next()\n            continue if evt.kidx == 0\n            saddr = Flash.write(saddr, evt, sizeof<EventInst>)\n            evt.kidx = 0\n        end\n    end\nend\n\ndef Accum.add(val)\n    auto accMeta = this.getMeta()\n    this.data[0] += 1\n    return if !accMeta.hasMax\n    this.data[1] = val if val > this.data[1]\n    for auto i = 0; i < accMeta.limCnt; i++\n        this.data[2 + i] += 1 if val < accMeta.lims[i]\n    end\nend\n\ndef Accum.clear()\n    auto accMeta = this.getMeta()\n    auto words = accMeta.hasMax ? (2 + accMeta.limCnt) : 1\n    ^memset(&this.data[0], 0, words * sizeof<uint32>)\nend\n\ndef Accum.getBin(idx)\n    return this.data[idx + 2]\nend\n\ndef Accum.getCount()\n    return this.data[0]\nend\n\ndef Accum.getMax()\n    return this.data[1]\nend\n\ndef Accum.getMeta()\n    return <AccumMeta&>(&accMetaTab[this.metaIdx-1])\nend\n\ndef Accum.print()\n    if POLICY > Policy.QUIET\n        auto accMeta = this.getMeta()\n        putc(PKT_CODE)\n        putc(ACC_CODE)\n        putc(this.metaIdx)\n        putBytes(<uint8*>&this.data[0], accMeta.size)\n    end\nend\n\ndef Cursor.next()\n    auto evt = &buf[this.idx++]\n    this.idx = 0 if this.idx >= ENTRY_COUNT\n    return evt\nend\n\ndef EventInst.put()\n    putc(PKT_CODE)\n    putc(EVT_CODE)\n    putBytes(<uint8*>this, sizeof<EventInst> - sizeof<uint16>)\nend\n\ndef EventKind.cache(a1, a2, a3)\n    if POLICY != Policy.NIL && ENTRY_COUNT > 0\n        auto evt = curs.next()\n        evt.time = mkTime()\n        evt.kidx = this.kidx\n        evt.a1 = <iarg_t>a1\n        evt.a2 = <iarg_t>a2\n        evt.a3 = <iarg_t>a3\n    end\nend\n\ndef EventKind.log(a1, a2, a3)\n    this.cache(a1, a2, a3) if POLICY == Policy.STORE || POLICY == Policy.QUIET\n    this.print(a1, a2, a3) if POLICY == Policy.PRINT\nend\n\ndef EventKind.print(a1, a2, a3)\n    if POLICY > Policy.QUIET\n        var evt: EventInst\n        evt.time = mkTime()\n        evt.kidx = this.kidx\n        evt.a1 = <iarg_t>a1\n        evt.a2 = <iarg_t>a2\n        evt.a3 = <iarg_t>a3\n        evt.put()\n    end\nend\n\ndef Group.initH(gs)\n    for auto i = 0; i < this.chars.length; i++\n        this.chars[i] = ^^gs && gs[i] ? gs.charCodeAt(i) : \" \".charCodeAt(0)^^\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/MemDump/","title":"MemDump","text":""},{"location":"cargo/em.core/em.utils/MemDump/#unit-memdump","title":"unit MemDump","text":"em.utils/MemDump.em
package em.utils\n\nmodule MemDump\n\n    function print32(addr: ptr_t, count: uint8)\n\nend\n\ndef print32(addr, count)\n    auto p32 = <uint32*>addr\n    while count--\n        auto v = *p32\n        printf \"%08x: %08x\\n\", p32, v\n        p32 += 1\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/MinConsole/","title":"MinConsole","text":""},{"location":"cargo/em.core/em.utils/MinConsole/#unit-minconsole","title":"unit MinConsole","text":"em.utils/MinConsole.em
package em.utils\n\nfrom em.lang import ConsoleProviderI\n\nfrom em.mcu import ConsoleUart\n\nimport Formatter\n\nmodule MinConsole: ConsoleProviderI\n\nend\n\ndef flush()\n    ConsoleUart.flush()\nend\n\ndef print(fmt, a1, a2, a3, a4, a5, a6)\nend\n\ndef put(data)\n    ConsoleUart.put(data)\nend\n
"},{"location":"cargo/em.core/em.utils/MsCounterUptimer/","title":"MsCounterUptimer","text":""},{"location":"cargo/em.core/em.utils/MsCounterUptimer/#unit-mscounteruptimer","title":"unit MsCounterUptimer","text":"em.utils/MsCounterUptimer.em
package em.utils\n\nfrom em.hal import MsCounterI\nfrom em.hal import UptimerI\n\nmodule MsCounterUptimer: MsCounterI\n\n    proxy Uptimer: UptimerI\n\nprivate:\n\n    var t0: uint32\n\n    function readMsecs(): uint32\n\nend\n\ndef readMsecs()\n    auto time = Uptimer.read()\n    return ((time.secs & 0xFF) << 16) + (time.subs >> 16)\nend\n\ndef start()\n    t0 = readMsecs()\nend\n\ndef stop()\n    return 0 if t0 == 0\n    auto dt = readMsecs() - t0\n    t0 = 0\n    return (dt * 1000) >> 16\nend\n
"},{"location":"cargo/em.core/em.utils/PollerAux/","title":"PollerAux","text":""},{"location":"cargo/em.core/em.utils/PollerAux/#unit-polleraux","title":"unit PollerAux","text":"em.utils/PollerAux.em
package em.utils\n\nfrom em.hal import OneShotMilliI\nfrom em.hal import PollerI\n\nfrom em.mcu import Common\n\nmodule PollerAux: PollerI\n\n    proxy OneShot: OneShotMilliI\n\n    config pauseOnly: bool = false\n\nprivate:\n\n    function handler: OneShot.Handler\n    function pause(msecs: uint32)\n\n    var doneFlag: bool volatile\n\nend\n\ndef handler(arg)\n    doneFlag = true\nend\n\ndef pause(msecs)\n    return if msecs == 0\n    doneFlag = false\n    OneShot.enable(msecs, handler, null)\n    while !doneFlag\n        Common.Idle.exec()\n    end\nend\n\ndef poll(rate, count, fxn)\n    if pauseOnly\n        pause(rate)\n        return 1\n    else\n        count = 0 if rate == 0\n        while count\n            pause(rate)\n            count -= 1\n            break if fxn && fxn()\n        end\n        return count        \n    end\nend\n
"},{"location":"cargo/em.core/em.utils/ProcMgr/","title":"ProcMgr","text":""},{"location":"cargo/em.core/em.utils/ProcMgr/#unit-procmgr","title":"unit ProcMgr","text":"em.utils/ProcMgr.em
package em.utils\n\nfrom em.mcu import Common\nfrom em.utils import BasicListManager\n\nmodule ProcMgr\n\n    type ProcFxn: function(arg: uarg_t)\n\n    type Proc: opaque\n        host function declareStartH()\n        host function initH(fxn: fxn_t, arg: uarg_t = 0)\n        function arg(a: uarg_t)\n        function fxn(f: fxn_t)\n        function getArg(): uarg_t\n        function getFxn(): fxn_t\n        function post()\n    end\n\n    host function createH(fxn: fxn_t, arg: uarg_t = 0): Proc&\n\n    function run()\n\nprivate:\n\n    def opaque Proc\n        elem: BasicListManager.Element\n        fxn_: fxn_t\n        arg_: uarg_t\n    end\n\n    function dispatch()\n\n    config startP: Proc&\n\n    var procList: BasicListManager.List\n\nend\n\ndef em$construct() \n    procList.initH()\nend\n\ndef em$startup()\n    startP.post() if startP && !Common.Mcu.isWarm()\nend\n\ndef createH(fxn, arg)\n    auto proc = new<Proc>\n    proc.initH(fxn, arg)\n    return proc\nend\n\ndef dispatch()\n    for ;;\n        break if procList.hasElements() == 0\n        auto proc = <Proc&>procList.get()\n        Common.GlobalInterrupts.enable()\n        auto fxn = <ProcFxn>proc.fxn_\n        fxn(proc.arg_)\n        Common.GlobalInterrupts.disable()\n    end   \nend\n\ndef run()\n    Common.Idle.wakeup()\n    Common.GlobalInterrupts.enable()\n    for ;;\n        Common.GlobalInterrupts.disable()\n        dispatch()\n        Common.Idle.exec()\n    end\nend\n\ndef Proc.declareStartH()\n    startP = this\nend\n\ndef Proc.initH(fxn, arg)\n    this.elem.initH()\n    this.fxn_ = fxn\n    this.arg_ = arg\nend\n\ndef Proc.arg(a)\n    this.arg_ = a\nend\n\ndef Proc.fxn(f)\n    this.fxn_ = f\nend\n\ndef Proc.getArg()\n    return this.arg_\nend\n\ndef Proc.getFxn()\n    return this.fxn_\nend\n\ndef Proc.post()\n    auto key = Common.GlobalInterrupts.disable()\n    procList.add(this.elem) if !this.elem.isActive()\n    Common.GlobalInterrupts.restore(key)\nend\n
"},{"location":"cargo/em.core/em.utils/SoftUart/","title":"SoftUart","text":""},{"location":"cargo/em.core/em.utils/SoftUart/#unit-softuart","title":"unit SoftUart","text":"em.utils/SoftUart.em
package em.utils\n\nfrom em.hal import ConsoleUartI\nfrom em.hal import GpioI\nfrom em.hal import UsThreshI\n\nfrom em.lang import Math\n\nfrom em.mcu import Common\n\nmodule SoftUart: ConsoleUartI\n\n    proxy TxPin: GpioI\n    proxy UsThresh: UsThreshI\n\nprivate:\n\n    config baudRate: uint32 = 115200\n    config bitTime: uint16 = 7\n\nend\n\ndef em$startup()\n    TxPin.makeOutput()\n    TxPin.set()\nend\n\ndef setBaudH(rate)\n    ## TODO -- implement\nend\n\ndef flush()\nend\n\ndef put(data)\n    var bitCnt: uint8 = 10                              # Load Bit counter, 8data + ST/SP/SP\n    var txByte: uint16 = (data << 1) | 0x600            # Add mark stop bits and space start bit\n    var key: uarg_t = Common.GlobalInterrupts.disable()\n    for ;;\n        UsThresh.set(bitTime)\n        if bitCnt-- == 0\n            TxPin.set()\n            break\n        else\n            if txByte & 0x01\n                TxPin.set()\n            else\n                TxPin.clear()\n            end\n            txByte = txByte >> 1                        # shift next bit\n        end\n        UsThresh.pause()\n    end\n    Common.GlobalInterrupts.restore(key)\nend\n
"},{"location":"cargo/em.core/em.utils/TickerMgr/","title":"TickerMgr","text":""},{"location":"cargo/em.core/em.utils/TickerMgr/#unit-tickermgr","title":"unit TickerMgr","text":"em.utils/TickerMgr.em
package em.utils\n\nimport AlarmMgr\nimport FiberMgr\n\nmodule TickerMgr\n            #   ^|\n    type TickCallback: function()\n            #   ^|\n    type Ticker: opaque\n            #   ^|\n        host function initH()\n            #   ^|\n        function start(rate256: uint32, tickCb: TickCallback)\n            #   ^|        \n        function stop()\n            #   ^|        \n    end\n\n    host function createH(): Ticker&\n            #   ^|\nprivate:\n\n    def opaque Ticker\n        alarm: AlarmMgr.Alarm&\n        fiber: FiberMgr.Fiber&\n        rate256: uint32\n        tickCb: TickCallback\n    end\n\n    function alarmFB: FiberMgr.FiberBodyFxn\n\n    var tickerTab: Ticker[]\n\nend\n\ndef createH()\n    var ticker: Ticker& = tickerTab[tickerTab.length++]\n    ticker.initH()\n    return ticker\nend\n\ndef Ticker.initH()\n    this.fiber = FiberMgr.createH(alarmFB, ^^this.$$cn^^)\n    this.alarm = AlarmMgr.createH(this.fiber)\nend\n\ndef alarmFB(arg)\n    auto ticker = <Ticker&>arg\n    return if ticker.tickCb == null\n    ticker.tickCb() \n    ticker.alarm.wakeupAt(ticker.rate256)\nend\n\ndef Ticker.start(rate256, tickCb)\n    this.rate256 = rate256\n    this.tickCb = tickCb\n    this.alarm.wakeupAt(rate256)\nend\n\ndef Ticker.stop()\n    this.alarm.cancel()\n    this.tickCb = null\nend\n
"},{"location":"cargo/em.core/em.utils/TimeoutAux/","title":"TimeoutAux","text":""},{"location":"cargo/em.core/em.utils/TimeoutAux/#unit-timeoutaux","title":"unit TimeoutAux","text":"em.utils/TimeoutAux.em
package em.utils\n\nfrom em.hal import OneShotMilliI\nfrom em.hal import TimeoutI\n\nmodule TimeoutAux: TimeoutI\n\n    proxy OneShot: OneShotMilliI\n\nprivate:\n\n    var flag: bool volatile\n\n    function handler: OneShot.Handler\n\nend\n\ndef active()\n    return flag\nend\n\ndef cancel()\n    flag = false\n    OneShot.disable()\nend\n\ndef handler(arg)\n    cancel()\nend\n\ndef set(msecs)\n    flag = true\n    OneShot.enable(msecs, handler, null)\nend\n
"},{"location":"cargo/em.docs/","title":"Index","text":""},{"location":"cargo/em.docs/#bundle-emdocs","title":"bundle em.docs","text":""},{"location":"cargo/em.docs/em.examples.basic/","title":"Index","text":""},{"location":"cargo/em.docs/em.examples.basic/#package-emexamplesbasic","title":"package em.examples.basic","text":""},{"location":"cargo/em.docs/em.examples.basic/Alarm1P/","title":"Alarm1P","text":""},{"location":"cargo/em.docs/em.examples.basic/Alarm1P/#unit-alarm1p","title":"unit Alarm1P","text":"em.examples.basic/Alarm1P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.utils import AlarmMgr\nfrom em.utils import FiberMgr\n\nmodule Alarm1P\n\nprivate:\n\n    function blinkFB: FiberMgr.FiberBodyFxn\n\n    config alarm: AlarmMgr.Alarm&\n    config blinkF: FiberMgr.Fiber&\n\n    var counter: uint32\n\nend\n\ndef em$construct()\n    blinkF = FiberMgr.createH(blinkFB)\n    alarm = AlarmMgr.createH(blinkF)\nend\n\ndef em$run()\n    blinkF.post()\n    FiberMgr.run()\nend\n\ndef blinkFB(arg)\n    %%[c]\n    AppLed.wink(100)            # 100ms\n    counter += 1\n    if counter & 0x1\n        alarm.wakeup(512)       # 2s\n    else\n        alarm.wakeup(192)       # 750ms\n    end\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/Alarm2P/","title":"Alarm2P","text":""},{"location":"cargo/em.docs/em.examples.basic/Alarm2P/#unit-alarm2p","title":"unit Alarm2P","text":"em.examples.basic/Alarm2P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.utils import AlarmMgr\nfrom em.utils import FiberMgr\n\nmodule Alarm2P\n\nprivate:\n\n    function blinkFB: FiberMgr.FiberBodyFxn\n\n    config alarm: AlarmMgr.Alarm&\n    config blinkF: FiberMgr.Fiber&\n\n    var counter: uint32\n\nend\n\ndef em$construct()\n    blinkF = FiberMgr.createH(blinkFB)\n    alarm = AlarmMgr.createH(blinkF)\nend\n\ndef em$run()\n    blinkF.post()\n    FiberMgr.run()\nend\n\ndef blinkFB(arg)\n    %%[c]\n    counter += 1\n    if counter & 0x1\n        AppLed.wink(100)    # 100ms\n    else\n        AppLed.wink(5)      # 5ms\n    end\n    alarm.wakeupAt(384)     # 1.5s window \nend\n
"},{"location":"cargo/em.docs/em.examples.basic/BlinkerDbgP/","title":"BlinkerDbgP","text":""},{"location":"cargo/em.docs/em.examples.basic/BlinkerDbgP/#unit-blinkerdbgp","title":"unit BlinkerDbgP","text":"em.examples.basic/BlinkerDbgP.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.mcu import Common\n\nmodule BlinkerDbgP\n\n    config dbgFlag: bool = true\n\n    config minCnt: uint16 = 1000\n    config maxCnt: uint16 = 1020 \n\nend\n\ndef em$run()\n    AppLed.on()\n    for cnt: uint16 = minCnt; cnt < maxCnt; cnt++\n        %%[d+]\n        Common.BusyWait.wait(500 * 1000L)\n        %%[d-]\n        AppLed.toggle()\n        continue if !dbgFlag\n        fail if cnt > ((minCnt + maxCnt) / 2)\n        %%[>cnt]\n        var bits11: uint8 = cnt & 0b0011\n        %%[>bits11]\n        %%[c:bits11]\n        printf \"cnt = %d (0x%04x), bits11 = %d\\n\", cnt, cnt, bits11\n    end\n    AppLed.off()\n    halt\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/BlinkerP/","title":"BlinkerP","text":""},{"location":"cargo/em.docs/em.examples.basic/BlinkerP/#unit-blinkerp","title":"unit BlinkerP","text":"em.examples.basic/BlinkerP.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.mcu import Common\n\nmodule BlinkerP\n\nend\n\ndef em$run()\n    AppLed.on()\n    for auto i = 0; i < 10; i++\n        Common.BusyWait.wait(500 * 1000L)\n        AppLed.toggle()\n    end\n    AppLed.off()\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/Button1P/","title":"Button1P","text":""},{"location":"cargo/em.docs/em.examples.basic/Button1P/#unit-button1p","title":"unit Button1P","text":"em.examples.basic/Button1P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em$distro import McuC\nfrom McuC import AppButEdge\n\nfrom em.mcu import Common\n\nmodule Button1P\n\nprivate:\n\n    function handler: AppButEdge.Handler\n\nend\n\ndef em$construct()\n    AppButEdge.setDetectHandlerH(handler)\nend\n\ndef em$startup()\n    AppButEdge.makeInput()\n    AppButEdge.setInternalPullup(true)\n    AppButEdge.setDetectFallingEdge()\nend\n\ndef em$run()\n    Common.GlobalInterrupts.enable()\n    for ;;\n        AppButEdge.enableDetect()\n        Common.Idle.exec()\n    end\nend\n\ndef handler()\n    %%[c]\n    AppButEdge.clearDetect()\n    AppLed.on()\n    Common.BusyWait.wait(5000)\n    AppLed.off()\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/Button2P/","title":"Button2P","text":""},{"location":"cargo/em.docs/em.examples.basic/Button2P/#unit-button2p","title":"unit Button2P","text":"em.examples.basic/Button2P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em$distro import McuC\nfrom McuC import AppButEdge\n\nfrom em.mcu import Common\n\nfrom em.utils import FiberMgr\n\nmodule Button2P\n\nprivate:\n\n    function blinkFB: FiberMgr.FiberBodyFxn\n    function handler: AppButEdge.Handler\n\n    config blinkF: FiberMgr.Fiber&\n\nend\n\ndef em$construct()\n    AppButEdge.setDetectHandlerH(handler)\n    blinkF = FiberMgr.createH(blinkFB)\nend\n\ndef em$startup()\n    AppButEdge.makeInput()\n    AppButEdge.setInternalPullup(true)\n    AppButEdge.setDetectFallingEdge()\nend\n\ndef em$run()\n    AppButEdge.enableDetect()\n    FiberMgr.run()\nend\n\ndef blinkFB(arg)\n    %%[d]\n    AppLed.on()\n    Common.BusyWait.wait(5000)\n    AppLed.off()\n    AppButEdge.enableDetect()\nend\n\ndef handler()\n    %%[c]\n    AppButEdge.clearDetect()\n    blinkF.post()\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/Button3P/","title":"Button3P","text":""},{"location":"cargo/em.docs/em.examples.basic/Button3P/#unit-button3p","title":"unit Button3P","text":"em.examples.basic/Button3P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppBut\nfrom BoardC import AppLed\nfrom BoardC import SysLed\n\nfrom em.mcu import Common\nfrom em.utils import FiberMgr\n\nmodule Button3P\n\nprivate:\n\n    function onPressedCB: AppBut.OnPressedCB\n\nend\n\ndef em$run()\n    AppBut.onPressed(onPressedCB)\n    FiberMgr.run()\nend\n\ndef onPressedCB()\n    %%[c]\n    if AppBut.isPressed()\n        SysLed.on()\n        Common.BusyWait.wait(40000)  # 40ms\n        SysLed.off()\n    else\n        AppLed.on()\n        Common.BusyWait.wait(5000)  # 5ms\n        AppLed.off()\n    end\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/FiberP/","title":"FiberP","text":""},{"location":"cargo/em.docs/em.examples.basic/FiberP/#unit-fiberp","title":"unit FiberP","text":"em.examples.basic/FiberP.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.mcu import Common\nfrom em.utils import FiberMgr\n\nmodule FiberP\n\nprivate:\n\n    function blinkFB: FiberMgr.FiberBodyFxn\n\n    config blinkF: FiberMgr.Fiber&\n\n    var count: uint8 = 5\n\nend\n\ndef em$construct()\n    blinkF = FiberMgr.createH(blinkFB)\nend\n\ndef em$run()\n    blinkF.post()\n    FiberMgr.run()\nend\n\ndef blinkFB(arg)\n    %%[d]\n    halt if --count == 0\n    AppLed.on()\n    Common.BusyWait.wait(100000)\n    AppLed.off()\n    Common.BusyWait.wait(100000)\n    blinkF.post()\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/HelloP/","title":"HelloP","text":""},{"location":"cargo/em.docs/em.examples.basic/HelloP/#unit-hellop","title":"unit HelloP","text":"em.examples.basic/HelloP.em
package em.examples.basic\n\nfrom em$distro import BoardC\n\nmodule HelloP\n\nend\n\ndef em$run()\n    printf \"hello world\\n\"\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/OneShot1P/","title":"OneShot1P","text":""},{"location":"cargo/em.docs/em.examples.basic/OneShot1P/#unit-oneshot1p","title":"unit OneShot1P","text":"em.examples.basic/OneShot1P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em$distro import McuC\nfrom McuC import OneShotMilli\n\nfrom em.mcu import Common\n\nmodule OneShot1P\n\nprivate:\n\n    function handler: OneShotMilli.Handler\n\n    var doneFlag: bool volatile = true\n\nend\n\ndef em$run()\n    Common.GlobalInterrupts.enable()\n    for auto i = 0; i < 5; i++\n        %%[d]\n        AppLed.on()\n        Common.BusyWait.wait(5000)\n        AppLed.off()\n        doneFlag = false\n        OneShotMilli.enable(100, handler)\n        while !doneFlag\n            Common.Idle.exec()\n        end\n    end\nend\n\ndef handler(arg)\n    %%[c]\n    doneFlag = true\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/OneShot2P/","title":"OneShot2P","text":""},{"location":"cargo/em.docs/em.examples.basic/OneShot2P/#unit-oneshot2p","title":"unit OneShot2P","text":"em.examples.basic/OneShot2P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em$distro import McuC\nfrom McuC import OneShotMilli\n\nfrom em.mcu import Common\nfrom em.utils import FiberMgr\n\nmodule OneShot2P\n\nprivate:\n\n    function blinkFB: FiberMgr.FiberBodyFxn\n    function handler: OneShotMilli.Handler\n\n    config blinkF: FiberMgr.Fiber&\n    var count: uint8 = 5\n\nend\n\ndef em$construct()\n    blinkF = FiberMgr.createH(blinkFB)\nend\n\ndef em$run()\n    blinkF.post()\n    FiberMgr.run()\nend\n\ndef blinkFB(arg)\n    %%[d]\n    AppLed.on()\n    Common.BusyWait.wait(5000)\n    AppLed.off()\n    halt if --count == 0\n    OneShotMilli.enable(100, handler, null)\nend\n\ndef handler(arg)\n    %%[c]\n    blinkF.post()\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/PollerP/","title":"PollerP","text":""},{"location":"cargo/em.docs/em.examples.basic/PollerP/#unit-pollerp","title":"unit PollerP","text":"em.examples.basic/PollerP.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.mcu import Common\nfrom em.mcu import Poller\n\nmodule PollerP\n\nend\n\ndef em$run()\n    Common.GlobalInterrupts.enable()\n    auto k = 5\n    while k--\n        Poller.pause(100)   # 100ms\n        AppLed.wink(5)      # 5ms\n    end\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/TickerP/","title":"TickerP","text":""},{"location":"cargo/em.docs/em.examples.basic/TickerP/#unit-tickerp","title":"unit TickerP","text":"em.examples.basic/TickerP.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\nfrom BoardC import SysLed\n\nfrom em.utils import FiberMgr\nfrom em.utils import TickerMgr\n\nmodule TickerP\n\nprivate:\n\n    function appTickCb: TickerMgr.TickCallback\n    function sysTickCb: TickerMgr.TickCallback\n\n    config appTicker: TickerMgr.Ticker&\n    config sysTicker: TickerMgr.Ticker&\n\nend\n\ndef em$construct()\n    appTicker = TickerMgr.createH()\n    sysTicker = TickerMgr.createH()\nend\n\ndef em$run()\n    appTicker.start(256, appTickCb)\n    sysTicker.start(384, sysTickCb)\n    FiberMgr.run()\nend\n\ndef appTickCb()\n    %%[c]\n    AppLed.wink(100)\nend\n\ndef sysTickCb()\n    %%[d]\n    SysLed.wink(100)\nend\n
"},{"location":"cargo/ti.cc23xx/","title":"Index","text":""},{"location":"cargo/ti.cc23xx/#bundle-ticc23xx","title":"bundle ti.cc23xx","text":""},{"location":"cargo/ti.cc23xx/ti.build.cc23xx/","title":"Index","text":""},{"location":"cargo/ti.cc23xx/ti.build.cc23xx/#package-tibuildcc23xx","title":"package ti.build.cc23xx","text":""},{"location":"cargo/ti.cc23xx/ti.build.cc23xx/GccBuilder/","title":"GccBuilder","text":""},{"location":"cargo/ti.cc23xx/ti.build.cc23xx/GccBuilder/#unit-gccbuilder","title":"unit GccBuilder","text":"ti.build.cc23xx/GccBuilder.em
package ti.build.cc23xx\n\nfrom em.build.misc import UniFlash\nfrom em.build.misc import Utils\n\nfrom em.build.gcc import BuilderBase as Base\n\nfrom em.lang import BuilderI\nfrom em.lang import BuildC\n\nmodule GccBuilder: BuilderI\n\nend\n\ndef em$configure()\n    Base.gccFlav ?= \"arm-none-eabi\"\n    if BuildC.bootFlash\n        Base.dmemBase ?= 0x20005000\n        Base.dmemSize ?= 0x4000\n        Base.imemBase ?= 0x20000000\n        Base.imemSize ?= 0x5000\n        Base.lmemBase ?= 0x00000000\n        Base.lmemSize ?= 0x80000\n    else\n        Base.dmemBase ?= 0x20000000\n        Base.dmemSize ?= 0x9000\n        Base.imemBase ?= 0x00000000\n        Base.imemSize ?= 0x80000\n    end\n    Base.vectSize ?= 0x90\n    Utils.addInclude(\"com.ti/devices/cc23x0r5\")\n    Utils.addSection(0x4e020000, 0x800, \"FLASH_CCFG\", \".ccfg\")\nend\n\ndef compile(buildDir)\n    return <CompileInfo&>Base.compile(buildDir)\nend\n\ndef getTypeInfo()\n    return <TypeInfo&>Base.getTypeInfo()\nend\n\ndef populate(buildDir, sysFlag)\n    Base.populate(buildDir, sysFlag)\n    Utils.copy(buildDir, \"CC2340R5.ccxml\", \"ti.build.cc23xx\")\n    UniFlash.genLoadScript(buildDir, \"CC2340R5\")\nend\n
"},{"location":"cargo/ti.cc23xx/ti.build.cc23xx/SeggerBuilder/","title":"SeggerBuilder","text":""},{"location":"cargo/ti.cc23xx/ti.build.cc23xx/SeggerBuilder/#unit-seggerbuilder","title":"unit SeggerBuilder","text":"ti.build.cc23xx/SeggerBuilder.em
package ti.build.cc23xx\n\nfrom em.build.misc import UniFlash\nfrom em.build.misc import Utils\n\nfrom em.build.segger import BuilderBase as Base\n\nfrom em.lang import BuilderI\nfrom em.lang import BuildC\n\nmodule SeggerBuilder: BuilderI\n\nend\n\ndef em$configure()\n    if BuildC.bootFlash\n        Base.dmemBase ?= 0x20005000\n        Base.dmemSize ?= 0x4000\n        Base.imemBase ?= 0x20000000\n        Base.imemSize ?= 0x5000\n        Base.lmemBase ?= 0x00000000\n        Base.lmemSize ?= 0x80000\n    else\n        Base.dmemBase ?= 0x20000000\n        Base.dmemSize ?= 0x9000\n        Base.imemBase ?= 0x00000000\n        Base.imemSize ?= 0x80000\n    end\n    Base.vectSize ?= 0x90\n    Utils.addInclude(\"com.ti/devices/cc23x0r5\")\n    Utils.addInclude(\"com.ti/devices/cc23x0r5/cmsis/core\")\n    Utils.addSection(0x4e020000, 0x800, \"FLASH_CCFG\", \".ccfg\")\nend\n\ndef compile(buildDir)\n    return <CompileInfo&>Base.compile(buildDir)\nend\n\ndef getTypeInfo()\n    return <TypeInfo&>Base.getTypeInfo()\nend\n\ndef populate(buildDir, sysFlag)\n    Base.populate(buildDir, sysFlag)\n    Utils.copy(buildDir, \"CC2340R5.ccxml\", \"ti.build.cc23xx\")\n    UniFlash.genLoadScript(buildDir, \"CC2340R5\")\nend\n
"},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/","title":"Index","text":""},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/#package-tidistrocc23xx","title":"package ti.distro.cc23xx","text":""},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/BoardC/","title":"BoardC","text":""},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/BoardC/#unit-boardc","title":"unit BoardC","text":"ti.distro.cc23xx/BoardC.em
package ti.distro.cc23xx\n\nfrom em.lang import Atom                    # force ordering\n\nimport McuC\nfrom McuC import AppButEdge\nfrom McuC import AppLedPin\nfrom McuC import AppOutPin\nfrom McuC import AppOutUart\nfrom McuC import SysDbgA\nfrom McuC import SysDbgB\nfrom McuC import SysDbgC\nfrom McuC import SysDbgD\nfrom McuC import SysLedPin\nfrom McuC import OneShotMilli\nfrom McuC import Uptimer\nfrom McuC import WakeupTimer\n\nfrom em.lang import Console\nfrom em.lang import Debug\n\nfrom em.mcu import ConsoleUart\nfrom em.mcu import Poller\n\nfrom em.utils import AlarmMgr\nfrom em.utils import BoardController\nfrom em.utils import BoardInfo\nfrom em.utils import EpochTime\nfrom em.utils import FormattingConsole\nfrom em.utils import PollerAux\n\nfrom em.utils import DebugPinT {} as DbgA\nfrom em.utils import DebugPinT {} as DbgB\nfrom em.utils import DebugPinT {} as DbgC\nfrom em.utils import DebugPinT {} as DbgD\n\nfrom em.utils import LedT {} as AppLed\nfrom em.utils import LedT {} as SysLed\n\nfrom em.utils import ButtonT {} as AppBut\n\nexport AppBut\nexport AppLed\nexport SysLed\n\ncomposite BoardC\n\nend\n\ndef em$configure()\n    auto brdRec = BoardInfo.readRecordH()\n    auto pm = brdRec.pinMap\n    AlarmMgr.WakeupTimer ?= WakeupTimer\n    AppBut.Edge ?= AppButEdge\n    AppLed.activeLow ?= brdRec.activeLowLeds\n    AppLed.em$used ?= true\n    AppLed.Pin ?= AppLedPin\n    AppOutUart.TxPin ?= AppOutPin\n    BoardController.em$used ?= true\n    BoardController.Led ?= SysLed\n    Console.em$used ?= true\n    Console.Provider ?= FormattingConsole\n    ConsoleUart.Impl ?= AppOutUart\n    DbgA.Pin ?= SysDbgA\n    DbgB.Pin ?= SysDbgB\n    DbgC.Pin ?= SysDbgC\n    DbgD.Pin ?= SysDbgD\n    Debug.Pin_a ?= DbgA\n    Debug.Pin_b ?= DbgB\n    Debug.Pin_c ?= DbgC\n    Debug.Pin_d ?= DbgD\n    EpochTime.Uptimer ?= Uptimer\n    Poller.Impl ?= PollerAux\n    PollerAux.OneShot ?= OneShotMilli\n    SysLed.activeLow ?= brdRec.activeLowLeds\n    SysLed.em$used ?= true\n    SysLed.Pin ?= SysLedPin\nend\n
"},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/BoardMeta/","title":"BoardMeta","text":""},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/BoardMeta/#unit-boardmeta","title":"unit BoardMeta","text":"ti.distro.cc23xx/BoardMeta.em
package ti.distro.cc23xx\n\nfrom em.utils import BoardMeta as BaseMeta\n\nhost module BoardMeta\n\n    type DrvDesc: BaseMeta.DrvDesc\n\n    type PinMap: struct\n        appBut: int8\n        appLed: int8\n        appOut: int8\n        extFlashCS: int8\n        extFlashCLK: int8\n        extFlashPICO: int8\n        extFlashPOCI: int8\n        sysDbgA: int8\n        sysDbgB: int8\n        sysDbgC: int8\n        sysDbgD: int8\n        sysLed: int8\n    end\n\n    type Record: struct\n        activeLowLeds: bool\n        baudRate: uint32\n        clockFreq: uint32\n        extFlashDisable: bool\n        lfXtalEnable: bool\n        pinMap: PinMap&\n        drvDescs: DrvDesc&[]\n    end\n\n    config baseFileLoc: string = \"ti.distro.cc23xx/em-boards\"\n\n    config attrNames: string[] = [\n        \"$inherits\",\n        \"$overrides\",\n        \"activeLowLeds\",\n        \"baudRate\",\n        \"clockFreq\",\n        \"extFlashDisable\",\n        \"lfXtalEnable\",\n    ]\n\n    config pinNames: string[] = [\n        \"appBut\",\n        \"appLed\",\n        \"appOut\",\n        \"extFlashCS\",\n        \"extFlashCLK\",\n        \"extFlashPICO\",\n        \"extFlashPOCI\",\n        \"sysDbgA\",\n        \"sysDbgB\",\n        \"sysDbgC\",\n        \"sysDbgD\",\n        \"sysLed\",\n    ] \n\nend\n
"},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/McuC/","title":"McuC","text":""},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/McuC/#unit-mcuc","title":"unit McuC","text":"ti.distro.cc23xx/McuC.em
package ti.distro.cc23xx\n\nfrom ti.mcu.cc23xx import Regs     # force ordering\n\nfrom ti.mcu.cc23xx import EdgeDetectGpioT {} as AppButEdge\nfrom ti.mcu.cc23xx import GpioT {} as AppLedPin\nfrom ti.mcu.cc23xx import GpioT {} as AppOutPin\nfrom ti.mcu.cc23xx import GpioT {} as SysDbgA\nfrom ti.mcu.cc23xx import GpioT {} as SysDbgB\nfrom ti.mcu.cc23xx import GpioT {} as SysDbgC\nfrom ti.mcu.cc23xx import GpioT {} as SysDbgD\nfrom ti.mcu.cc23xx import GpioT {} as SysLedPin\n\nfrom ti.mcu.cc23xx import ConsoleUart0 as AppOutUart\nfrom ti.mcu.cc23xx import BusyWait\nfrom ti.mcu.cc23xx import ExtFlashDisabler\nfrom ti.mcu.cc23xx import GlobalInterrupts\nfrom ti.mcu.cc23xx import Idle\nfrom ti.mcu.cc23xx import IntrVec\nfrom ti.mcu.cc23xx import Mcu\nfrom ti.mcu.cc23xx import MsCounter\nfrom ti.mcu.cc23xx import OneShotGpt3 as OneShotMilli\nfrom ti.mcu.cc23xx import Uptimer\nfrom ti.mcu.cc23xx import UsCounter\nfrom ti.mcu.cc23xx import WakeupTimer\n\nfrom em.mcu import Common\nfrom em.mcu import CommonC\n\nfrom em.utils import BoardInfo\n\nexport AppButEdge\nexport AppLedPin\nexport AppOutPin\nexport AppOutUart\nexport OneShotMilli\nexport SysDbgA\nexport SysDbgB\nexport SysDbgC\nexport SysDbgD\nexport SysLedPin\nexport Uptimer\nexport WakeupTimer\n\ncomposite McuC\n\nend\n\ndef em$preconfigure()\n    auto brdRec = BoardInfo.readRecordH()\n    auto pm = brdRec.pinMap\n    AppButEdge.pin ?= pm.appBut\n    AppLedPin.pin ?= pm.appLed\n    AppOutPin.pin ?= pm.appOut\n    AppOutUart.setBaudH(brdRec.baudRate)\n    ExtFlashDisabler.em$used ?= brdRec.extFlashDisable\n    ExtFlashDisabler.CLK_pin ?= pm.extFlashCLK\n    ExtFlashDisabler.CS_pin ?= pm.extFlashCS\n    ExtFlashDisabler.PICO_pin ?= pm.extFlashPICO\n    ExtFlashDisabler.POCI_pin ?= pm.extFlashPOCI\n    IntrVec.em$used ?= true\n    Mcu.hasLfXtal ?= brdRec.lfXtalEnable\n    Mcu.mclkFrequency ?= brdRec.clockFreq\n    Regs.em$used ?= true\n    SysDbgA.pin ?= pm.sysDbgA\n    SysDbgB.pin ?= pm.sysDbgB\n    SysDbgC.pin ?= pm.sysDbgC\n    SysDbgD.pin ?= pm.sysDbgD\n    SysLedPin.pin ?= pm.sysLed\nend\n\ndef em$configure()\n    Common.BusyWait ?= BusyWait\n    Common.GlobalInterrupts ?= GlobalInterrupts\n    Common.Idle ?= Idle\n    Common.Mcu ?= Mcu\n    Common.MsCounter ?= MsCounter\n    Common.UsCounter ?= UsCounter\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/","title":"Index","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/#package-timcucc23xx","title":"package ti.mcu.cc23xx","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWait/","title":"BusyWait","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWait/#unit-busywait","title":"unit BusyWait","text":"ti.mcu.cc23xx/BusyWait.em
package ti.mcu.cc23xx\n\nfrom em.hal import BusyWaitI\n\nmodule BusyWait: BusyWaitI\n\nend\n\ndef wait(usecs)\n    ^HapiWaitUs(usecs)\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWaitSysTick/","title":"BusyWaitSysTick","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWaitSysTick/#unit-busywaitsystick","title":"unit BusyWaitSysTick","text":"ti.mcu.cc23xx/BusyWaitSysTick.em
package ti.mcu.cc23xx\n\nfrom em.hal import BusyWaitI\n\nmodule BusyWaitSysTick: BusyWaitI\n\nend\n\ndef wait(usecs)\n    ^^SysTick->VAL^^ = 0\n    ^^SysTick->LOAD^^ = usecs\n    ^^SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk^^\n    while ^^SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk^^ != 0\n        %%[d]\n    end\n    ^^SysTick->CTRL^^ = 0\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/ConsoleUart0/","title":"ConsoleUart0","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/ConsoleUart0/#unit-consoleuart0","title":"unit ConsoleUart0","text":"ti.mcu.cc23xx/ConsoleUart0.em
package ti.mcu.cc23xx\n\nfrom em.hal import ConsoleUartI\nfrom em.hal import GpioI\n\nfrom em.lang import Math\n\nimport Idle\nimport Mcu\n\nmodule ConsoleUart0: ConsoleUartI\n\n    proxy TxPin: GpioI\n\nprivate:\n\n    config baud: uint32\n    config fbrd: uint32\n    config ibrd: uint32\n\n    function sleepEnter: Idle.Callback\n    function sleepLeave: Idle.Callback\n\nend\n\ndef em$construct()\n    Idle.addSleepEnterCbH(sleepEnter)\n    Idle.addSleepLeaveCbH(sleepLeave)\n    auto brd = <num_t>(Mcu.mclkFrequency / (baud * 16))\n    ibrd = Math.floor(brd)\n    fbrd = Math.round((brd - ibrd) * 64)\nend\n\ndef em$startup()\n    sleepLeave()\nend\n\ndef setBaudH(rate)\n    baud = rate\nend\n\ndef sleepEnter()\n    ^^HWREG(CLKCTL_BASE + CLKCTL_O_CLKENCLR0)^^ = ^CLKCTL_CLKENSET0_UART0\n    TxPin.reset()\nend\n\ndef sleepLeave()\n    ^^HWREG(CLKCTL_BASE + CLKCTL_O_CLKENSET0)^^ = ^CLKCTL_CLKENSET0_UART0\n    TxPin.makeOutput()\n    TxPin.set()\n    TxPin.functionSelect(2)\n    ^^HWREG(UART0_BASE + UART_O_CTL)^^ &= ~^UART_CTL_UARTEN\n    ^^HWREG(UART0_BASE + UART_O_IBRD)^^ = ibrd\n    ^^HWREG(UART0_BASE + UART_O_FBRD)^^ = fbrd\n    ^^HWREG(UART0_BASE + UART_O_LCRH)^^ = ^UART_LCRH_WLEN_BITL8\n    ^^HWREG(UART0_BASE + UART_O_CTL)^^ |= ^UART_CTL_UARTEN\nend\n\ndef flush()\n    while (^^HWREG(UART0_BASE + UART_O_FR)^^ & ^UART_FR_BUSY) != 0\n    end\nend\n\ndef put(data)\n    ^^HWREG(UART0_BASE + UART_O_DR)^^ = data\n    flush()\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioAux/","title":"EdgeDetectGpioAux","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioAux/#unit-edgedetectgpioaux","title":"unit EdgeDetectGpioAux","text":"ti.mcu.cc23xx/EdgeDetectGpioAux.em
package ti.mcu.cc23xx\n\nimport InterruptT { name: \"GPIO_COMB\" } as Intr\n\nmodule EdgeDetectGpioAux\n\n    type Handler: function ()\n\n    type HandlerInfo: struct\n        link: HandlerInfo&\n        mask: uint32\n        handler: Handler\n    end\n\n    function addHandler(hi: HandlerInfo&)\n\n private:\n\n    var handlerList: HandlerInfo&\n    function edgeIsr: Intr.Handler\n\nend\n\ndef em$construct()\n    Intr.setHandlerH(edgeIsr)\nend\n\ndef em$startup()\n    Intr.enable()\nend\n\ndef addHandler(hi)\n    hi.link = handlerList\n    handlerList = hi\nend\n\ndef edgeIsr()\n    auto mis = <uint32>^^HWREG(GPIO_BASE + GPIO_O_MIS)^^\n    for hi: HandlerInfo& = handlerList; hi != null; hi = hi.link\n        hi.handler() if (mis & hi.mask) && hi.handler\n    end\n    ^^HWREG(GPIO_BASE + GPIO_O_ICLR)^^ = 0xffffffff\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioT/","title":"EdgeDetectGpioT","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioT/#unit-edgedetectgpiot","title":"unit EdgeDetectGpioT","text":"ti.mcu.cc23xx/EdgeDetectGpioT.em
package ti.mcu.cc23xx\n\ntemplate EdgeDetectGpioT\n\n    const UNDEF: int8 = -1\n\n    config pin: int8 = UNDEF\n\nend\n\ndef em$generateUnit(pn, un)\n    auto bq = \"`\"\n    auto p = pin\n    auto pre = ^^pn.replace(/[.]/g, '_') + '_' + un + '__'^^\n|->>>\n    package `pn`\n\n    from ti.mcu.cc23xx import EdgeDetectGpioAux as Aux\n    from ti.mcu.cc23xx import GpioT {} as Pin\n\n    from em.hal import GpioEdgeDetectMinI\n\n    module `un`: GpioEdgeDetectMinI\n\n        config pin: int16 = `p`\n\n    private:\n\n        config isDef: bool\n        config mask: uint32        \n\n        var info: Aux.HandlerInfo\n\n    end\n\n    def em$configure()\n        Pin.pin ?= pin\n    end\n\n    def em$construct()\n        isDef = pin != `UNDEF`\n        mask = isDef ? <uint32>(1 << <uint8>pin) : 0\n        info.mask = mask\n    end\n\n    def em$startup()\n        Aux.addHandler(info)\n    end    \n\n    def clear() \n        Pin.clear()\n    end\n\n    def set()\n        Pin.set()\n    end\n\n    def get()\n        return Pin.get()\n    end\n\n    def toggle()\n        Pin.toggle()\n    end\n\n    def isInput()\n        return Pin.isInput()\n    end\n\n    def isOutput()\n        return Pin.isOutput()\n    end\n\n    def makeInput()\n        Pin.makeInput()\n    end\n\n    def makeOutput()\n        Pin.makeOutput()\n    end\n\n    def functionSelect(select)\n        Pin.functionSelect(select)\n    end\n\n    def setInternalPullup(enable)\n        Pin.setInternalPullup(enable)\n    end\n\n    def pinId()\n        return pin\n    end\n\n    def reset()\n        Pin.reset()\n    end\n\n    def enableDetect()\n        ^^HWREG(GPIO_BASE + GPIO_O_IMSET)^^ = mask if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ |= ^IOC_IOC0_WUENSB if isDef\n    end\n\n    def disableDetect()\n        ^^HWREG(GPIO_BASE + GPIO_O_IMCLR)^^ = mask if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ &= ~^IOC_IOC0_WUENSB if isDef\n    end\n\n    def clearDetect()\n        ^^HWREG(GPIO_BASE + GPIO_O_ICLR)^^ = mask if isDef\n    end\n\n    def setDetectRisingEdge()\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ &= ~^IOC_IOC0_EDGEDET_M if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ |= ^IOC_IOC0_EDGEDET_EDGE_POS if isDef\n    end\n\n    def setDetectFallingEdge()\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ &= ~^IOC_IOC0_EDGEDET_M if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ |= ^IOC_IOC0_EDGEDET_EDGE_NEG if isDef\n    end\n\n    def setDetectHandlerH(h)\n        info.handler = <Aux.Handler>h\n    end\n|-<<<\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/ExtFlashDisabler/","title":"ExtFlashDisabler","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/ExtFlashDisabler/#unit-extflashdisabler","title":"unit ExtFlashDisabler","text":"ti.mcu.cc23xx/ExtFlashDisabler.em
package ti.mcu.cc23xx\n\nimport GpioT {} as CS\nimport GpioT {} as CLK\nimport GpioT {} as PICO\nimport GpioT {} as POCI\n\nfrom em.mcu import Common\n\nmodule ExtFlashDisabler\n\n    config CS_pin: int8\n    config CLK_pin: int8\n    config PICO_pin: int8\n    config POCI_pin: int8\n\nprivate:\n\n    const SD_CMD: uint8 = 0xb9\n\nend\n\ndef em$construct()\n    CS.pin = CS_pin\n    CLK.pin = CLK_pin\n    PICO.pin = PICO_pin\n    POCI.pin = POCI_pin\nend\n\ndef em$startup()\n    %%[c+]\n    CS.makeOutput()\n    CLK.makeOutput()\n    PICO.makeOutput()\n    POCI.makeInput()\n    # attention\n    CS.set()\n    Common.BusyWait.wait(1)\n    CS.clear()\n    Common.BusyWait.wait(1)\n    CS.set()\n    Common.BusyWait.wait(50)\n    # shutdown command\n    CS.clear()\n    for auto i = 0; i < 8; i++\n        CLK.clear()\n        if ((SD_CMD >> (7 - i)) & 0x01) == 0\n            PICO.clear()\n        else\n            PICO.set()\n        end\n        CLK.set()\n        Common.BusyWait.wait(1)\n    end\n    CLK.clear()\n    CS.set()\n    Common.BusyWait.wait(50)\n    #\n    CS.reset()\n    CLK.reset()\n    PICO.reset()\n    POCI.reset()\n    %%[c-]\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/GlobalInterrupts/","title":"GlobalInterrupts","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/GlobalInterrupts/#unit-globalinterrupts","title":"unit GlobalInterrupts","text":"ti.mcu.cc23xx/GlobalInterrupts.em
package ti.mcu.cc23xx\n\nfrom em.hal import GlobalInterruptsI\n\nmodule GlobalInterrupts: GlobalInterruptsI\n\nend\n\ndef disable()\n    auto key = <uarg_t>(^^__get_PRIMASK()^^)\n    ^^__set_PRIMASK(1)^^\n    return key\nend\n\ndef enable()\n    ^^__set_PRIMASK(0)^^\nend\n\ndef restore(key)\n    ^^__set_PRIMASK(key)^^\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/GpioT/","title":"GpioT","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/GpioT/#unit-gpiot","title":"unit GpioT","text":"ti.mcu.cc23xx/GpioT.em
package ti.mcu.cc23xx\n\ntemplate GpioT\n\n    const UNDEF: int16 = -1\n\n    config pin: int16 = UNDEF\n\nend\n\ndef em$generateUnit(pn, un)\n    auto bq = \"`\"\n    auto pre = ^^pn.replace(/[.]/g, '_') + '_' + un + '__'^^\n|->>>\n    package `pn`\n\n    from em.hal import GpioI\n\n    module `un`: GpioI\n\n        config pin: int16 = `pin`\n\n        function pinMask(): uint32    \n\n    private:\n\n        config isDef: bool\n        config mask: uint32\n\n    end\n\n    def em$construct()\n        isDef = pin != `UNDEF`\n        mask = isDef ? <uint32>(1 << <uint8>pin) : 0\n    end\n\n    def clear() \n        ^^HWREG(GPIO_BASE + GPIO_O_DOUTCLR31_0)^^ = mask if isDef\n    end\n\n    def set()\n        ^^HWREG(GPIO_BASE + GPIO_O_DOUTSET31_0)^^ = mask if isDef\n    end\n\n    def get()\n        return 0 if !isDef\n        return isInput() ? ((^^HWREG(GPIO_BASE + GPIO_O_DIN31_0)^^ & mask) != 0) : ((^^HWREG(GPIO_BASE + GPIO_O_DOUT31_0)^^ & mask) != 0)\n    end\n\n    def toggle()\n        ^^HWREG(GPIO_BASE + GPIO_O_DOUTTGL31_0)^^ = mask if isDef\n    end\n\n    def isInput()\n        return isDef && (^^HWREG(GPIO_BASE + GPIO_O_DOE31_0)^^ & mask) == 0\n    end\n\n    def isOutput()\n        return isDef && (^^HWREG(GPIO_BASE + GPIO_O_DOE31_0)^^ & mask) != 0\n    end\n\n    def makeInput()\n        ^^HWREG(GPIO_BASE + GPIO_O_DOECLR31_0)^^ = mask if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ |= ^IOC_IOC0_INPEN if isDef\n    end\n\n    def makeOutput()\n        ^^HWREG(GPIO_BASE + GPIO_O_DOESET31_0)^^ = mask if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ &= ~^IOC_IOC0_INPEN if isDef\n    end\n\n    def functionSelect(select)\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ = select if isDef\n    end\n\n    def setInternalPullup(enable)\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ |= ^IOC_IOC0_PULLCTL_PULL_UP if isDef && enable\n    end\n\n    def pinId()\n        return pin\n    end\n\n    def pinMask()\n        return mask\n    end\n\n    def reset()\n        ^^HWREG(GPIO_BASE + GPIO_O_DOECLR31_0)^^ = mask if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ |= (^IOC_IOC0_IOMODE_M | ^IOC_IOC0_PULLCTL_M) if isDef\n    end\n|-<<<\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Idle/","title":"Idle","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Idle/#unit-idle","title":"unit Idle","text":"ti.mcu.cc23xx/Idle.em
package ti.mcu.cc23xx\n\nfrom em.hal import IdleI\nfrom em.lang import Debug\n\nmodule Idle: IdleI\n\n    type Callback: function()\n\n    host function addSleepEnterCbH(cb: Callback) \n    host function addSleepLeaveCbH(cb: Callback) \n\n    function doSleep()\n    function doWait()\n\n    function setWaitOnly(val: bool)\n\nprivate:\n\n    config sleepEnterCbTab: Callback[..]\n    config sleepLeaveCbTab: Callback[..]\n\n    var waitOnly: bool\n\nend\n\ndef em$startup()\n    %%[b+]\n    ^^HWREG(PMCTL_BASE + PMCTL_O_VDDRCTL)^^ = ^PMCTL_VDDRCTL_SELECT     # LDO\n    ^^HWREG(EVTULL_BASE + EVTULL_O_WKUPMASK)^^ = ^EVTULL_WKUPMASK_AON_RTC_COMB | ^EVTULL_WKUPMASK_AON_IOC_COMB\nend\n\ndef addSleepEnterCbH(cb)\n    sleepEnterCbTab[sleepEnterCbTab.length++] = cb\nend\n\ndef addSleepLeaveCbH(cb)\n    sleepLeaveCbTab[sleepLeaveCbTab.length++] = cb\nend\n\ndef doSleep()\n    for cb in sleepEnterCbTab\n        cb()\n    end\n    %%[b:2]\n    %%[b-]\n    Debug.sleepEnter()\n    ^^HWREG(CKMD_BASE + CKMD_O_LDOCTL)^^ = 0x0\n    ^^__set_PRIMASK(1)^^\n    ^^HapiEnterStandby(NULL)^^\n    Debug.sleepLeave()\n    %%[b+]\n    for cb in sleepLeaveCbTab\n        cb()\n    end\n    ^^__set_PRIMASK(0)^^\nend\n\ndef doWait()\n    %%[b:1]\n    %%[b-]\n    ^^__set_PRIMASK(1)^^\n    ^^asm(\"wfi\")^^\n    %%[b+]\n    ^^__set_PRIMASK(0)^^\nend\n\n\ndef exec()\n    if waitOnly\n        doWait()\n    else\n        doSleep()\n    end\nend\n\ndef setWaitOnly(val)\n    waitOnly = val\nend\n\ndef wakeup()\n    ## TODO -- implement\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/InterruptT/","title":"InterruptT","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/InterruptT/#unit-interruptt","title":"unit InterruptT","text":"ti.mcu.cc23xx/InterruptT.em
package ti.mcu.cc23xx\n\ntemplate InterruptT\n\n    config name: string\n\nend\n\ndef em$generateUnit(pn, un) \n    auto intrName = name\n    auto handlerNameQ = \"`\" + un + \".handlerName`\"\n|->>>\n    package `pn`\n\n    from ti.mcu.cc23xx import IntrVec\n\n    from em.hal import InterruptSourceI\n\n    module `un`: InterruptSourceI \n\n    private:\n        host var handlerName: string\n    end\n\n    def em$construct()\n        IntrVec.addIntrH(\"`intrName`\")\n    end\n\n    def em$generateCode( prefix )\n        if `un`.handlerName\n            |-> void `intrName`_Handler() {\n            |->     `handlerNameQ`();\n            |-> }\n        end\n    end\n\n    def setHandlerH(h)\n        handlerName = h ? ^^String(h).substring(1)^^ : null\n    end\n\n    def enable() \n        ^^NVIC_EnableIRQ(`intrName`_IRQn)^^\n    end\n\n    def disable() \n        ^^NVIC_DisableIRQ(`intrName`_IRQn)^^\n    end\n\n    def clear()\n        ^^NVIC_ClearPendingIRQ(`intrName`_IRQn)^^\n    end\n\n    def isEnabled() \n        return ^^NVIC_GetEnableIRQ(`intrName`_IRQn)^^\n    end\n|-<<<\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/IntrVec/","title":"IntrVec","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/IntrVec/#unit-intrvec","title":"unit IntrVec","text":"ti.mcu.cc23xx/IntrVec.em
package ti.mcu.cc23xx\n\nfrom em.hal import IntrVecI\n\nmodule IntrVec: IntrVecI\n\n    host function addIntrH(name: string)\n\nprivate:\n\n    const HARD_FAULT: uint32 = 3\n\n    type IsrFxn: function()\n\n    host config nameTab: string[] = [\n        \"NMI\",\n        \"HardFault\",\n        null,\n        null,\n        null,\n        null,\n        null,\n        null,\n        null,\n        \"SVC\",\n        null,\n        null,\n        \"PendSV\",\n        \"SysTick\",\n        \"CPUIRQ0\",\n        \"CPUIRQ1\",\n        \"CPUIRQ2\",\n        \"CPUIRQ3\",\n        \"CPUIRQ4\",\n        \"GPIO_COMB\",     \n        \"LRFD_IRQ0\",     \n        \"LRFD_IRQ1\",     \n        \"DMA_DONE_COMB\",     \n        \"AES_COMB\",      \n        \"SPI0_COMB\",     \n        \"UART0_COMB\",    \n        \"I2C0_IRQ\",     \n        \"LGPT0_COMB\",    \n        \"LGPT1_COMB\",    \n        \"ADC0_COMB\",     \n        \"CPUIRQ16\", \n        \"LGPT2_COMB\",    \n        \"LGPT3_COMB\",\n    ]\n\n    host config usedTab: string[]\n\n    config excHandler: ExceptionHandler\n\n    function nullIsr()\n\nend\n\ndef em$generateCode(prefix)\n|->>>\ntypedef void( *intfunc )( void );\ntypedef union { intfunc fxn; void* ptr; } intvec_elem;\n\n|-<<<\n    for n in nameTab\n        continue if n == null\n        |-> extern void `n`_Handler( void );\n        |-> #define `n`_ISR `prefix`::nullIsr\n    end    \n|->>>\n\n|-<<<\n    for u in usedTab\n        |-> #undef `u`_ISR\n        |-> #define `u`_ISR `u`_Handler\n    end    \n|->>>\n\nextern em_uint32 __stack_top__;\nextern \"C\" void __em_program_start( void );\nextern \"C\" const intvec_elem  __attribute__((section(\".intvec\"))) __vector_table[] = {\n    { .ptr = (void*)&__stack_top__ },\n    { .fxn = __em_program_start },\n|-<<<\n    for n in nameTab\n        if n == null\n            |->     0,\n        else\n            |->     { .fxn = `n`_ISR },\n        end\n    end    \n    |-> };\n|->>>\n\n|-<<<\nend\n\ndef em$startup()\n    ^^SCB->VTOR = (uint32_t)(&__vector_table)^^\nend\n\ndef addIntrH(name)\n    usedTab[usedTab.length++] = name\nend\n\ndef bindExceptionHandlerH(handler)\n    excHandler = handler\nend\n\ndef nullIsr()\n    auto vecNum = <uint32>(^^__get_IPSR()^^)\n    %%[b:4]\n    %%[><uint8>vecNum]\n    auto frame = <uint32[]>(^^__get_MSP()^^)\n    %%[><uint32>&frame[0]]\n    for auto i = 0; i < 8; i++\n        %%[b]\n        %%[>frame[i]]\n    end\n    fail\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Mcu/","title":"Mcu","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Mcu/#unit-mcu","title":"unit Mcu","text":"ti.mcu.cc23xx/Mcu.em
package ti.mcu.cc23xx\n\nfrom em.hal import McuI\n\nfrom em.lang import Debug\n\nmodule Mcu: McuI\n\n    config noCache: bool\n    config hasLfXtal: bool\n\nend\n\ndef getResetCode()\n    ## TODO -- implement\n    return 0\nend\n\ndef getStashAddr()\n    ## TODO -- implement\n    return null\nend\n\ndef isWarm()\n    ## TODO -- implement\n    return false\nend\n\ndef readEui48(dst)\n    ## TODO -- implement\nend\n\ndef reset(code)\n    ## TODO -- implement\nend\n\ndef startup()\n    Debug.startup()\n    if hasLfXtal\n        ^^HWREG(CKMD_BASE + CKMD_O_LFINCOVR) = 0x001E8480 | CKMD_LFINCOVR_OVERRIDE_M^^\n        ^^HWREG(CKMD_BASE + CKMD_O_LFCLKSEL) = CKMD_LFCLKSEL_MAIN_LFXT^^\n        ^^HWREG(CKMD_BASE + CKMD_O_LFXTCTL) = CKMD_LFXTCTL_EN^^\n        ^^HWREG(CKMD_BASE + CKMD_O_IMSET) = CKMD_IMASK_LFCLKGOOD^^\n    else\n        ^^HWREG(CKMD_BASE + CKMD_O_TRIM1) |= CKMD_TRIM1_NABIAS_LFOSC^^\n        ^^HWREG(CKMD_BASE + CKMD_O_LFCLKSEL) = CKMD_LFCLKSEL_MAIN_LFOSC^^\n        ^^HWREG(CKMD_BASE + CKMD_O_LFOSCCTL) = CKMD_LFOSCCTL_EN^^\n        ^^HWREG(CKMD_BASE + CKMD_O_LFINCCTL) &= ~CKMD_LFINCCTL_PREVENTSTBY_M^^\n        ^^HWREG(CKMD_BASE + CKMD_O_IMSET) = CKMD_IMASK_LFCLKGOOD^^\n    end\n    ^^HWREG(CLKCTL_BASE + CLKCTL_O_IDLECFG)^^ = 1 if noCache\n    ^^HWREG(VIMS_BASE + VIMS_O_CCHCTRL)^^ = 0 if noCache\nend\n\ndef shutdown()\n    ## TODO -- implement\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/MsCounter/","title":"MsCounter","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/MsCounter/#unit-mscounter","title":"unit MsCounter","text":"ti.mcu.cc23xx/MsCounter.em
package ti.mcu.cc23xx\n\nfrom em.hal import MsCounterI\n\nimport Rtc\n\nmodule MsCounter: MsCounterI\n\nprivate:\n\n    var t0: uint32\n\nend\n\ndef start()\n    t0 = Rtc.getMsecs()\nend\n\ndef stop()\n    return 0 if t0 == 0\n    auto t1 = Rtc.getMsecs()\n    auto dt = (t1 > t0) ? (t1 - t0) : (t0 - t1)\n    t0 = 0\n    return dt\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotGpt3/","title":"OneShotGpt3","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotGpt3/#unit-oneshotgpt3","title":"unit OneShotGpt3","text":"ti.mcu.cc23xx/OneShotGpt3.em
package ti.mcu.cc23xx\n\nimport InterruptT { name: \"LGPT3_COMB\" } as Intr\n\nimport BusyWait\nimport Idle\nimport Mcu\n\nfrom em.hal import OneShotMilliI\n\nmodule OneShotGpt3: OneShotMilliI\n\nprivate:\n\n    var curArg: ptr_t\n    var curFxn: Handler\n\n    function isr: Intr.Handler\n\nend\n\ndef em$construct()\n    Intr.setHandlerH(isr)\nend\n\ndef disable()\n    curFxn = null\n    Idle.setWaitOnly(false)\n    Intr.disable()\n    ^^HWREG(LGPT3_BASE + LGPT_O_ICLR) = LGPT_ICLR_TGT^^\nend\n\ndef enable(msecs, handler, arg)\n    curFxn = handler\n    curArg = arg\n    Idle.setWaitOnly(true)\n    Intr.enable()\n    ^^HWREG(CLKCTL_BASE + CLKCTL_O_CLKENSET0)^^ = ^CLKCTL_CLKENSET0_LGPT3\n    ^^HWREG(LGPT3_BASE + LGPT_O_IMSET) = LGPT_IMSET_TGT^^\n    ^^HWREG(LGPT3_BASE + LGPT_O_TGT)^^ = msecs * (Mcu.mclkFrequency / 1000)\n    ^^HWREG(LGPT3_BASE + LGPT_O_CTL) = LGPT_CTL_MODE_UP_ONCE | LGPT_CTL_C0RST^^\nend\n\ndef isr()\n    auto fxn = curFxn\n    disable()\n    fxn(curArg) if fxn\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTick/","title":"OneShotSysTick","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTick/#unit-oneshotsystick","title":"unit OneShotSysTick","text":"ti.mcu.cc23xx/OneShotSysTick.em
package ti.mcu.cc23xx\n\nimport InterruptT { name: \"SysTick\" } as Intr\n\nimport Idle\nimport Mcu\n\nfrom em.hal import OneShotMilliI\n\nmodule OneShotSysTick: OneShotMilliI\n\nprivate:\n\n    var curArg: ptr_t\n    var curFxn: Handler\n\n    function isr: Intr.Handler\n\nend\n\ndef em$construct()\n    Intr.setHandlerH(isr)\nend\n\ndef em$startup()\n    ^^SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk^^\nend\n\ndef disable()\n    curFxn = null\n    Idle.setWaitOnly(false)\n    Intr.disable()\n    ^^SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk)^^\nend\n\ndef enable(msecs, handler, arg)\n    curFxn = handler\n    curArg = arg\n    Idle.setWaitOnly(true)\n    Intr.enable()\n    ^^SysTick->LOAD^^ = msecs * (Mcu.mclkFrequency / 1000)\n    ^^SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk^^\nend\n\ndef isr()\n    auto fxn = curFxn\n    disable()\n    fxn(curArg) if fxn\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTim0/","title":"OneShotSysTim0","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTim0/#unit-oneshotsystim0","title":"unit OneShotSysTim0","text":"ti.mcu.cc23xx/OneShotSysTim0.em
package ti.mcu.cc23xx\n\nimport InterruptT { name: \"CPUIRQ1\" } as Intr\n\nimport Idle\nimport Mcu\n\nfrom em.hal import OneShotMilliI\n\nmodule OneShotSysTim0: OneShotMilliI\n\nprivate:\n\n    var curArg: ptr_t\n    var curFxn: Handler\n\n    function isr: Intr.Handler\n\nend\n\ndef em$construct()\n    Intr.setHandlerH(isr)\nend\n\ndef disable()\n    curFxn = null\n    Idle.setWaitOnly(false)\n    Intr.disable()\n    ^^HWREG(SYSTIM_BASE + SYSTIM_O_ICLR) = SYSTIM_ICLR_EV0^^\nend\n\ndef enable(msecs, handler, arg)\n    curFxn = handler\n    curArg = arg\n    Idle.setWaitOnly(true)\n    Intr.clear()\n    Intr.enable()\n    ^^HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ1SEL) = EVTSVT_CPUIRQ1SEL_PUBID_SYSTIM0^^\n    ^^HWREG(SYSTIM_BASE + SYSTIM_O_IMSET) = SYSTIM_IMSET_EV0^^\n    auto time1u = <uint32>(^^HWREG(SYSTIM_BASE + SYSTIM_O_TIME1U)^^)\n    auto thresh = time1u + (msecs * 1000)\n    ^^HWREG(SYSTIM_BASE + SYSTIM_O_CH0CC)^^ = thresh\n    printf \"time1u = %d, thresh = %d\\n\", time1u, thresh\nend\n\ndef isr()\n    %%[a]\n    auto fxn = curFxn\n    disable()\n    fxn(curArg) if fxn\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Regs/","title":"Regs","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Regs/#unit-regs","title":"unit Regs","text":"ti.mcu.cc23xx/Regs.em
package ti.mcu.cc23xx\n\nmodule Regs\n\nend\n\ndef em$generateCode(prefix)\n|->>>\n    #include \"cmsis/cc23x0r5.h\"\n    #include \"cmsis/core/core_cm0plus.h\"\n\n    #include \"driverlib/hapi.h\"\n\n    #include \"inc/hw_memmap.h\"\n    #include \"inc/hw_types.h\"\n\n    #include \"inc/hw_ckmd.h\"\n    #include \"inc/hw_clkctl.h\"\n    #include \"inc/hw_evtull.h\"\n    #include \"inc/hw_evtsvt.h\"\n    #include \"inc/hw_gpio.h\"\n    #include \"inc/hw_ioc.h\"\n    #include \"inc/hw_lgpt.h\"\n    #include \"inc/hw_lgpt3.h\"\n    #include \"inc/hw_pmctl.h\"\n    #include \"inc/hw_rtc.h\"\n    #include \"inc/hw_systim.h\"\n    #include \"inc/hw_uart.h\"\n    #include \"inc/hw_vims.h\"\n\n    #include \"inc/hw_ccfg.h\"\n\n#if 0\n\n    extern \"C\" const ccfg_t __ccfg __attribute__((section(\".ccfg\"), used)) = {\n\n        .bootCfg.pBldrVtor = XCFG_BC_PBLDR_UNDEF,\n\n        .bootCfg.bldrParam.serialRomBldrParamStruct.bldrEnabled = XCFG_BC_BLDR_DIS,\n        .bootCfg.bldrParam.serialRomBldrParamStruct.serialIoCfgIndex = 0,\n        .bootCfg.bldrParam.serialRomBldrParamStruct.pinTriggerDio = 0,\n        .bootCfg.bldrParam.serialRomBldrParamStruct.pinTriggerEnabled = XCFG_BC_PINTRIG_DIS,\n        .bootCfg.bldrParam.serialRomBldrParamStruct.pinTriggerLevel = XCFG_BC_PINTRIG_LEVEL_LO,\n        .bootCfg.pAppVtor = (void*)0x0,\n\n        .hwOpts = {0xffffffff, 0xffffffff},\n\n        .permissions.allowDebugPort = CCFG_PERMISSION_ALLOW,\n        .permissions.allowEnergyTrace = CCFG_PERMISSION_ALLOW,\n        .permissions.allowFlashVerify = CCFG_PERMISSION_ALLOW,\n        .permissions.allowFlashProgram = CCFG_PERMISSION_ALLOW,\n        .permissions.allowChipErase = CCFG_PERMISSION_ALLOW,\n        .permissions.allowToolsClientMode = CCFG_PERMISSION_ALLOW,\n        .permissions.allowFakeStby = CCFG_PERMISSION_ALLOW,\n        .permissions.allowReturnToFactory = CCFG_PERMISSION_ALLOW,\n\n        .misc.saciTimeoutOverride = 1U,\n        .misc.saciTimeoutExp = 7,\n\n        .flashProt.writeEraseProt.mainSectors0_31 = 0xffffffff,\n        .flashProt.writeEraseProt.mainSectors32_255 = 0xffffffff,\n\n        .flashProt.writeEraseProt.ccfgSector = 0,\n        .flashProt.writeEraseProt.fcfgSector = 0,\n        .flashProt.writeEraseProt.engrSector = 0,\n\n        .flashProt.res = 0xFFFFFFFFU,\n\n        .flashProt.chipEraseRetain.mainSectors0_31 = 0x0,\n        .flashProt.chipEraseRetain.mainSectors32_255 = 0x0,\n\n        .debugCfg.authorization = CCFG_DBGAUTH_DBGOPEN,\n        .debugCfg.allowBldr = CCFG_DBGBLDR_ALLOW,\n        .debugCfg.pwdId = {0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15},\n        .debugCfg.pwdHash = {0x6d, 0xd7, 0xe4, 0x36, 0xeb, 0xf4, 0x31, 0xdf,\n                            0x95, 0xae, 0x15, 0xee, 0x03, 0xba, 0x8e, 0xe4,\n                            0xc4, 0xc6, 0x3f, 0xd8, 0x45, 0x3f, 0x67, 0x5e,\n                            0x74, 0xd7, 0xc2, 0x01, 0x2c, 0x90, 0x58, 0xe5},\n    };\n\n#else\n\n    extern \"C\" const uint32_t __ccfg[] __attribute__((section(\".ccfg\"), used)) = {\n        0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,\n        0xFFFFFFFF, 0xFFFFFFFF, 0xAAAAAAAA, 0x0000000F,\n        0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x0000A55A, 0x03020101, 0x150D0805, 0x36E4D76D,\n        0xDF31F4EB, 0xEE15AE95, 0xE48EBA03, 0xD83FC6C4,\n        0x5E673F45, 0x01C2D774, 0xE558902C, 0x00000000,\n    };\n#endif\n|-<<<\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Rtc/","title":"Rtc","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Rtc/#unit-rtc","title":"unit Rtc","text":"ti.mcu.cc23xx/Rtc.em
package ti.mcu.cc23xx\n\nimport InterruptT { name: \"CPUIRQ0\" } as Intr\n\nmodule Rtc\n\n    type Handler: function()\n\n    function disable()\n    function enable(thresh: uint32, handler: Handler)\n    function getMsecs(): uint32\n    function getRaw(oSubs: uint32*): uint32\n    function toThresh(ticks: uint32): uint32\n    function toTicks(secs256: uint32): uint32\n\nprivate:\n\n    const MSECS_SCALAR: uint16 = 1000 / 8\n    const RES_BITS: uint8 = 20\n\n    var curHandler: Handler\n\n    function isr: Intr.Handler\n\nend\n\ndef em$construct()\n    Intr.setHandlerH(isr)\nend\n\ndef em$startup()\n    ^^HWREG(CKMD_BASE + CKMD_O_LFINCOVR)^^ = 0x80000000 + (1 << RES_BITS)\n    ^^HWREG(RTC_BASE + RTC_O_CTL)^^ = ^RTC_CTL_RST\n    ^^HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ0SEL) = EVTSVT_CPUIRQ0SEL_PUBID_AON_RTC_COMB^^\n    Intr.enable()\nend\n\ndef disable()\n    curHandler = null\n    ^^HWREG(RTC_BASE + RTC_O_IMCLR)^^ = ^RTC_IMCLR_EV0\nend\n\ndef enable(thresh, handler)\n    curHandler = handler\n    ^^HWREG(RTC_BASE + RTC_O_CH0CC8U)^^ = thresh\n    ^^HWREG(RTC_BASE + RTC_O_IMSET)^^ = ^RTC_IMSET_EV0\nend\n\ndef getMsecs()\n    auto ticks = <uint32>^^HWREG(RTC_BASE + RTC_O_TIME8U)^^\n    return (ticks * MSECS_SCALAR) >> (RES_BITS - 7)\nend\n\ndef getRaw(oSubs)\n    var lo: uint32\n    var hi: uint32\n    for ;;\n        lo = ^^HWREG(RTC_BASE + RTC_O_TIME8U)^^\n        hi = ^^HWREG(RTC_BASE + RTC_O_TIME524M)^^\n        break if lo == ^^HWREG(RTC_BASE + RTC_O_TIME8U)^^\n    end\n    *oSubs = lo << 16\n    return hi\nend\n\ndef isr()\n    ^^HWREG(RTC_BASE + RTC_O_ICLR)^^ = ^RTC_ICLR_EV0\n    curHandler() if curHandler\nend\n\n\ndef toThresh(ticks)\n    return ^^HWREG(RTC_BASE + RTC_O_TIME8U)^^ + ticks\nend\n\ndef toTicks(secs256)\n    return secs256 << 8\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Uptimer/","title":"Uptimer","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Uptimer/#unit-uptimer","title":"unit Uptimer","text":"ti.mcu.cc23xx/Uptimer.em
package ti.mcu.cc23xx\n\nimport Rtc\n\nfrom em.hal import UptimerI\n\nmodule Uptimer: UptimerI\n\nprivate:\n\n    var curTime: Time\n\nend\n\ndef calibrate(secs256, ticks)\n    ## TODO -- implement\n    return 0\nend\n\ndef read()\n    curTime.secs = Rtc.getRaw(&curTime.subs)\n    return curTime\nend\n\ndef resetSync()\n    ## TODO -- implement\nend\n\ndef trim()\n    ## TODO -- implement\n    return 0\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/UsCounter/","title":"UsCounter","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/UsCounter/#unit-uscounter","title":"unit UsCounter","text":"ti.mcu.cc23xx/UsCounter.em
package ti.mcu.cc23xx\n\nfrom em.hal import UsCounterI\n\nimport Mcu\n\nmodule UsCounter: UsCounterI\n\nend\n\ndef start()\n    ^^SysTick->CTRL = (1 << SysTick_CTRL_CLKSOURCE_Pos) | (1 << SysTick_CTRL_ENABLE_Pos)^^\n    ^^SysTick->LOAD = 0xFFFFFF^^\n    ^^SysTick->VAL = 0^^\nend\n\ndef stop()\n    auto lr = <uint32>^^SysTick->LOAD^^\n    auto vr = <uint32>^^SysTick->VAL^^\n    auto dt = (((lr - vr) << 1) / (Mcu.mclkFrequency / 1000000)) >> 1\n    ^^SysTick->CTRL = 0^^\n    return dt\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/WakeupTimer/","title":"WakeupTimer","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/WakeupTimer/#unit-wakeuptimer","title":"unit WakeupTimer","text":"ti.mcu.cc23xx/WakeupTimer.em
package ti.mcu.cc23xx\n\nfrom em.hal import WakeupTimerI\n\nimport Rtc\n\nmodule WakeupTimer: WakeupTimerI\n\nend\n\ndef disable()\n    Rtc.disable()\nend\n\ndef enable(secs256, handler)\n    Rtc.enable(secs256, <Rtc.Handler>handler)\nend\n\ndef secs256ToTicks(secs256)\n    return secs256 << 8\nend\n\ndef ticksToThresh(ticks)\n    return Rtc.toThresh(ticks)\nend\n\ndef timeToTicks(secs, subs)\n    return (secs << 16) | (subs >> 16)\nend\n
"},{"location":"intro/","title":"Why another language\u2009???","text":"

For the past fifty years, the C Programming Language has significantly streamlined software development for resource-constrained embedded microcontrollers [MCUs]. Already coming into maturity by 1980, C had proven itself as a practical \u201cmedium-level\u201d language for many of the first 8\u2009/\u200916\u2009/\u200932-bit MCUs \u2013 enabling full entitlement to the underlying silicon, while offering developers greater software productivity and portability over native assembly language.

As a testimony to its staying power, C continues to this day as the dominant programming language for resource-constrained MCUs; and given that we still write embedded software targeting 8\u2009/\u200916\u2009/\u200932-bit processors \u2013 often with less than 32K of memory \u2013 do we really have a practical alternative to C\u2009???\u00a0\u00a0 Yes, we do \u2013 EM.

Other embedded programming languages

Besides C and assembler, practitioners cite C++, Java, and Python as other languages of choice for embedded software development \u2013 with interest in Go and Rust starting to grow. For a variety of reasons, none of these languages come close to overtaking the dominant position of C:\u00a0 developers often fear a steep learning curve with a new language, offsetting any potential gain in productivity; and the language itself might introduce additional runtime overhead in time and (especially) space that render it impractical for the most resource-constrained MCUs.

"},{"location":"intro/#the-big-picture","title":"The big picture","text":"

The EM software platform comprises a novel programming language and run-time environment which targets resource-constrained embedded hardware \u2013 on the low-end, systems potentially managed by 8-bit MCUs using as little as 4\u2009K of program memory and 256\u2009B of data. Compared with C, EM features a higher-level programming paradigm centered around highly-reusable software modules which embody the principles of encapsulation, abstraction, and composition.

At the same time, higher-level language constructs introduced by EM don't necessarily cause higher-levels of run-time overhead; modular EM applications designed using modern software techniques will often outperform comparable C programs written in a more conventional style. As you'll learn later on, the EM language translator will in fact generate monolithic C/C++ programs from a set of EM source modules \u2013 leveraging the maturity and ubiquity of optimizing C/C++compilers for embedded MCUs.

More than a programming language, the EM platform also features a modular run-time environment (written in EM, of course\u2009!!!) which streamlines developer productivity through software re-use as well as increases application portability through abstraction \u2013 all without compromising overall system performance. The EM run-time modules include basic services which handle and dispatch real-time application events, as well as device-drivers which manage hardware peripherals typically found within embedded MCUs.

Write once, run anywhere

Not unlike other software platforms ranging from Java and Linux to Ruby and Python, EM offers up a \"write once, run anywhere\u2009...\" value-proposition for its application developers. The difference, needless to say, lies in the underlying hardware configurations targeted by EM \u2013 memory-constrained MCUs otherwise incapable of supporting Java or Linux (let alone Ruby or Python), for which C has remained the dominant programming environment for over a half-century.

"},{"location":"intro/#tiny-code-tiny-chips","title":"Tiny code \u2192 Tiny chips","text":"

EM programs typically consume less memory than their C counterparts \u2013 a critical feature when targeting resource-constrained MCUs. With 3\u2009X\u2009\u2013\u20095\u2009X reductions in program size not uncommon in practice, many real-world EM applications can comfortably fit in (say) a 32K memory space.

The latest 32-bit MCUs deployed in edge-computing applications will often feature generous amounts of flash memory [\u2009\u2265\u2009512K\u2009] for storing program code, as well as large blocks of SRAM [\u2009\u2265\u200964K\u2009] for reading\u2009+\u2009writing program data; these MCUs also feature processors with sophisticated pipelines as well as advanced memory caches \u2013 all boosting the performance of large (and ever-growing\u2009!!!) bodies of legacy C code used in today's applications.

But what if our EM-based applications really did require only 32\u2009K of memory\u2009???

We could take conventional MCU designs \"over-the-edge\" by embracing a radically simple set of hardware featues which collectively would define the fringe of embedded processing:

\u00a0entry-level CPU core\u00a0 \u2009 no larger than Arm Cortex-M0+ \u00a0tightly-coupled memories (TCMs)\u00a0 \u2009code\u2009+\u2009data; \u2264\u200932K per bank; zero wait-state SRAM \u00a0bulk flash and NO cache\u00a0 \u2009TCMs loaded under firmware control \u00a0rudimentary peripherals\u00a0 \u2009 no specialized auxiliary CPU cores \u00a0always-on domain\u00a0 \u2009 wakeup events from deep-sleep power modes \u00a0\u2265\u2009100MHz system clock\u00a0 \u2009no TCM wait-states \u2192 maximize CPU throughput

Features through would collectively minimize the number of logic gates and memory cells required to implement this MCU in silicon \u2013 resulting in a smaller chip die compared with a more fully-featured design, which (holding other factors constant) forecasts lower manufacturing costs as well as lower leakage power.

To support \"sleepy applications\" with short active-duty cycles, feature enables our MCU to execute for years on small batteries \u2013 or even indefinitely using harvested energy. Because of its relatively small die-size, our MCU could likely consume \u2264\u20091\u03bcW of power when sleeping; and by retaining all program state in the (small) TCMs of , our MCU can quickly return to its fully-powered active mode when awoken by an event.

Feature , however, seems at odds with achieving an energy-efficient design \u2013 faster clocks proportionally increase switching (dynamic) power consumption; but since the CPU can access its TCMs without stalling, increased clock speed also results in proportionally faster software execution \u2013 enabling our duty-cycled application to spend more time in deep-sleep. In practice, this approach actually improves overall energy(1)utilization by reducing the (static) overhead of leakage power during active execution periods.

  1. E = \u222b\u2009 (Pleakage + Pswitching) dt

Given that feature enables faster execution, the peripherals of can now leverage software running on the main CPU core to perform functions that would otherwise require additional hardware \u2013 such as advanced encryption modes or the upper layers of a comm stack. Unlike conventional cryto or radio blocks (which often contain their own dedicated cores) our peripherals embody a \"RISC-like\" approach which efficiently implements only rudimentary primitives in hardware and then relegates higher-levels functions to software.

EM programs that target our idealized MCU will often exhibit a simple, cyclic structure:

wake-up from deep-sleep

acquire data from the environment

analyze this data using an algorithm

transmit results (wirelessly) to the edge

re-enter deep-sleep

Because of their single-threaded design, these programs would only require a single CPU core to maximize application throughput; software functions normally relegated (say) to an auxiliary cyrto or radio core can now execute exclusively on the main CPU. Consolidating all software onto a single core not only maximizes re-use of MCU logic elements, but can further reduce cost and power by minimizing the silicon footprint of certain peripherals.(1)

  1. We'll return to this topic further downstream.

So thanks to EM \u2013 10\u2009X fewer bytes, 10\u2009X fewer transistors, 10\u2009X lower power, 10\u2009X lower cost\u2009!!!

The promise of RISC-V

The emergence of RISC-V as an open instruction-set architecture has triggered an abundance of innovation in MCU design; you can literally find dozens of open-source projects containing synthesizable cores expressed in languages like Verilog and VHDL. While much of the RISC-V community has set its sights on high-performance computing from the edge up to the cloud, some practitioners have focused on \"tiny cores\" suitable for low-power, low-cost applications on the fringe; visit the X-HEEP and NEORV32 projects as examples.

With more degrees of freedom when implementing the entry-level RV32ICM instruction set \u2013 often compared against the ARM Cortex-M0+ \u2013 MCU designers can truly innovate when realizing our earlier feature \u2013 all in the interest of further shrinking silicon and software:

Here again, the tiny-code of EM serves as a catalyst which can drive novel RISC-V tiny-chips.

"},{"location":"intro/#technical-overview","title":"Technical overview","text":"

Building upon the tiny\u00a0code\u2009\u2192\u2009tiny\u00a0chips premise behind EM, let's dive into some technical details.\u00a0 The following chapters each focus on a particular aspect of the language and its runtime enviorment, and collectively provide a technical overview of the EM platform:

1)\u2003 EM modules & interfaces \u2022\u2022\u2022 The client/server dichotomy\u2003\u2003 2)\u2003 EM composites & templates \u2022\u2022\u2022 Assembling application elements\u2003\u2003 3)\u2003 EM program life-cycle \u2022\u2022\u2022 From build-time to run-time\u2003\u2003 4)\u2003 EM runtime bundles \u2022\u2022\u2022 Software platform content\u2003\u2003

We encourage you to read these chapters in sequence, as each subsequent chapter builds on material covered by its predecessors. At the same time, we recognize that this document introduces a lot of (new) information about a (new) programming environment; feel free to proceed iteratively, skimming the content on your first pass before circling back for a more thorough reading.

The technical overivew also includes exemplary source-code fragments, written in the EM programming language and formatted as follows:

Hello.em
# we've omitted a few details here\n# but you should get the basic idea\n\nmodule Hello\nend\n\ndef em$run()\n    printf \"Hello world\\n\"\nend\n

Even if you don't plan to (initially) install and use EM, these fragments should give you an intuitive sense of the language \u2013 which relies upon familiar programming constructs (such as seen at line 8 above) that you've likely encountered elsewhere.

So with that, let's move onward to Chapter 1 and begin our technical overview of EM.

"},{"location":"intro/#the-history-of-em","title":"The history of EM","text":"

EM's origin story

The EM programming language first appeared at UC Santa Barbara in 2010, where undergraduate students taking CS190C\u2009/\u2009ECE1940 would develop \u201creal-world\u201d embedded applications targeting resource-constrained MCUs \u2013 with all software written in EM, of course, using this (now outdated) language primer as a guide.

The EM language had emerged through deep discussion and intense interaction with Amichai Amar \u2013 a UCSB PhD candidate at that time. Consult his thesis for more details on the outcome of our undergraduate course, as well as a more comprehensive exposition of programming resource-constrained MCUs using EM.

But the true EM backstory actually began decades before its debut at UCSB. In 1998, Texas Instruments acquired Spectron Microsystems \u2013 whose SPOX and DSP\u2009/\u2009BIOS products had already emerged as de facto industry standards. This milestone validated the importance of software technology in further solidifying TI's leadership as a DSP silicon vendor, and in fact triggered a flurry of similar acquisitions during the dot-com boom.

Once inside TI, the Spectron team broadened the application of its patented configuration technology \u2013 which had already enabled DSP\u2009/\u2009BIOS to fit comfortably within the 2\u2009K boot ROM of broadly-deployed, low-power DSPs. This effort culminated in the open-source RTSC project, hosted at the Eclipse Foundation beginning in 2007 and still used today within TI software products. But RTSC fell a bit short in fulfilling its vision \u2013 and provided some much needed impetus for the birth of EM a few years later.

EM's coming-of-age began in 2011 with the founding of Emmoco \u2013 an early player offering an embedded\u2009\u2194\u2009mobile connectivity stack targeting new TI wireless MCUs which supported the emerging BLE standard. Acquired by Shelfbucks in late 2015, the Emmoco stack ultimately evolved to support long-range, low-power subGHz radios in which just one cloud-connected HUB could interact with (say) 10,000 TAGs in a 500,000 sq ft venue.

After Shelfbucks ceased operations in 2019 \u2013 and thanks to some legacy licensing agreements \u2013 EM found its way onto other low-power wireless MCUs from vendors such as NXP, Analog Devices, and ON Semiconductor; EM's foray into the world of RISC-V (as detailed in an earlier note) also began in this time frame. Targeting very high-volume applications for over a decade now, EM's uncanny ability to reduce firmware footprint proved critical in keeping system size, power, and cost in check.

As of today, EM has supported more than twenty 8\u2009/\u200916\u2009/\u200932-bit MCUs from almost a dozen silicon vendors. The EM language translator \u2013 which ultimately outputs ANSI C/C++ code for portability \u2013 has also targeted the most popular toolchains for embedded development [GCC, IAR, Keil, LLVM].\u00a0 Thanks to a recent rewrite of the translator into TypeScript, EM now enjoys robust language support within the VS Code IDE.

More important, perhaps, just a handful of EM programmers have developed thousands of EM modules used (and often re-used\u2009) across a broad spectrum of IoT applications targeting these MCUs. But due to the proprietary nature of these applications, the EM language and its runtime has remained closed \u2013 until now\u2009!!!

"},{"location":"intro/to-1/","title":"The client/supplier dichotomy","text":"

EM revolves around the concept of a concrete module, a programmatic construct that plays a seminal role within the language comparable to the position held by a class within C++ or Java. Not unlike classes, each EM module defines a programmatic boundary between its clients \u2013 users of the module \u2013 and the supplier of the module itself.

To minimize direct coupling between clients and suppliers \u2013 and therefore to increase software re-use \u2013 EM also supports module abstraction through an interface construct which clients in turn can leverage through a module proxy.

"},{"location":"intro/to-1/#source-code-structure","title":"Source-code structure","text":"

Reflecting a basic dichotomy between module clients and module suppliers, consider the overall organization of a sample EM module named Mod1, whose source code will reside in a file named Mod1.em:

bob.pkg/Mod1.em
package bob.pkg\n\nmodule Mod1         # client-visible feature declarations\n    const C: ...\n    type T:  ...\n    function f( ... )\n    # etc\n\nprivate:            # supplier-proprietary feature declarations\n    var x: ...\n    function g( ... )\n    # etc\nend\n\ndef f(...)          # supplier-proprietary function definitions\n    # body of 'f'\nend\n\ndef g(...)\n    # body of 'g'\nend\n\n# etc...\n

Starting from the top, each EM module lives within the logical scope of a package which physically corresponds to a file-system directory of the same name. As in Java or Python, an EM package will generally bear a globally-unique qualified name that identifies its supplier \u2013 bob.pkg, bob.pkg.test, dave.pkg, and so forth. By extension, all EM modules have a (globally-unique) fully-qualified canonical name \u2013 bob.pkg/Mod1 in the current example \u2013 though in practice you'll invariably refer to modules using simple names like Mod1.

Flat directory structure

But unlike Java or Python, where the contents of a package named bob.pkg would actually reside in a nested directory structure with the path bob/pkg, EM employs a flat organization in which the logical package-name and physical directory-name must match exactly.

Moving on, the declarations beginning at line 3 comprise the public specification of this module \u2013 a coherent collection of constants, types, and functions (what others might term an \"API\"\u2009) available for direct use by clients of Mod1. Taken together, these externally-visible features of the module constitute a programmatic contract in which future changes on the part of the supplier should (hopefully!!!\u2009) not violate prior client assumptions.

By contrast, features of Mod1 declared beginning at line 9 along with all definitions of its public and private functions beginning at line 15 remain hidden from any clients of this module. The supplier of Mod1 can consequently change the internal implementation of this module \u2013 optimizing performance or improving robustness \u2013 while maintaining a measure of \"plug-compatibility\" from its clients' perspective.

Separation of concerns

By enforcing crisp boundaries between clients and suppliers, EM modules encourage a software \"best-practice\" known as separation of concerns \u2013 organizing application functionality into discrete programmatic elements that encapsulate specific implementation decisions. Besides helping us digest software-rich systems in \"bite-sized\" chunks (where each EM module becomes a small world unto itself), our ability to manage change throughout the software life-cycle emerges as the most enduring benefit of modularity in general.

"},{"location":"intro/to-1/#importing-modules","title":"Importing modules","text":"

To gain access to public features of bob.pkg/Mod1, clients must explicitly import this module within their own\u2009.em files prior to any direct usage. As an illustration, consider a sample module named dave.pkg/Mod2:

dave.pkg/Mod2.em
package dave.pkg\n\nfrom bob.pkg import Mod1\n\nmodule Mod2       # client-visible feature declarations\n    function f( ... )\n\nprivate:          # supplier-proprietary feature declarations\n    var t: Mod1.T\nend\n\ndef f(...)        # supplier-proprietary function definitions\n    Mod1.f( ... )\nend\n

The directive at line 3 effectively adds the identifier Mod1 to this file's top-level namespace, which already includes all public\u2009/\u2009private feature names of Mod2; an optional trailing as clause can resolve name conflicts, should they arise. Through their import directives, EM modules organize themselves into a static hierarchy of clients and suppliers. As a rule, this client-supplier relation must remain acyclic; an EM module can neither directly nor indirectly import itself.

After importing Mod1, the example accesses this module's public type T at line 9 followed by its public function f at line 13 using a qualified name of the form Mod1.feature. This syntax enables client modules using Mod1 to (coincidentally) declare their own features with identical names, such as the function f defined here within the scope of Mod2; unqualified identifiers always refer to features defined within the current module.

Main programs

By implementing a special (intrinsic) function named em$run, any EM module can potentially serve as the entry-point for an executable application \u2013 a common pattern in many modern languages. Said another way, EM has no inherent notion of a \"main-program\"; instead, application developers will designate a particular module as the top of a client-supplier hierarchy defined via import directives.

"},{"location":"intro/to-1/#abstracting-suppliers","title":"Abstracting suppliers","text":"

At the end of the day, EM application programs comprise a set of concrete modules \u2013 each contributing some measure of encapsulated code and data to the final executable image. In the example above, where we directly imported bob.pkg/Mod1, this module will auto\u00admatically and unconditionally become an element of any application program that directly or indirectly uses dave.pkg/Mod2.

As an alternative to this mode of direct coupling between modules, EM introduces a language construct known as a proxy that adds a level of indirection between clients and suppliers \u2013 abstracting a particular supplier's identity from the client's perspective. Akin to polymorphism within object-oriented programming, EM proxies can enhance application flexibility and improve software re-use by further decoupling clients from suppliers; the same client module, as you'll soon see, can effectively (re-)use different supplier imple\u00admentations of otherwise common functionality.

And even more important than re-use, we can better manage change\u2009!!!

By not having to modify client modules that employ proxies, our software becomes more resilient and malleable when \u2013 and not if \u2013 application requirements evolve over time.

To capture commonality amongst a family of \"plug-compatible\" modules, EM enables us to separately publish a set of client-visible features as an interface \u2013 a public specification independent of any particular supplier implementation. As an illustration, let's refactor the bob.pkg/Mod1 module presented earlier.

bob.pkg/ModI.em

package bob.pkg\n\ninterface ModI             # public specification only  \n    const C: ...\n    type T:  ...\n    function f( ... )\nend\n
bob.pkg/Mod1.em
package bob.pkg\n\nfrom bob.pkg import ModI\n\nmodule Mod1: ModI         # public specification  \n    # additional features\n\nprivate:                  # internal implementation\n    # same as before\nend\n\ndef f()\n    # body of 'f'\nend\n\n# etc...\n

The declarations beginning at line 3 mimic the earlier public specification of bob.pkg/Mod1; but unlike a concrete module, an abstract EM interface cannot have an internal implementation. Our new rendition of Mod1 now inherits its public specification from the interface ModI at line 3, while declaring any additional (public) features unique to this module; the private portion of Mod1 beginning at line 8 remains unchanged from before.

More on interfaces

In practice, abstract interfaces and implementing modules will often reside in different packages: for instance, the EM runtime contains a package named em.hal holding ConsoleUartI, GpioI, WakeupTimerI, and other interfaces; packages such as ti.mcu.cc23xx then hold concrete implementations of these abstract interfaces targeting a particular MCU architecture.

Returning to the matter at hand \u2013 abstracting suppliers \u2013 we'll now refactor our original dave.pkg/Mod2 client module to remove its direct dependence on bob.pkg/Mod1 and instead leverage a local proxy implementing the ModI interface.

dave.pkg/Mod2.em
package dave.pkg\n\nfrom bob.pkg import ModI\n\nmodule Mod2       # client-visible feature declarations\n    proxy ModX: ModI\n    function f( ... )\n\nprivate:          # supplier-proprietary feature declarations\n    var t: ModX.T\nend\n\ndef f(...)        # supplier-proprietary function definitions\n    ModX.f( ... )\nend\n

The syntax at line 6 adds the name ModX to the top-level scope of Mod2, as well as declares that the proxy ModX provides all client features specified within the interface ModI; access to the public type T and the public function f at lines 10 and 14 respectively mirror earlier direct usage of bob.pkg/Mod1.

Once again, we should emphasize that client Mod2 has no overt coupling to the concrete module Mod1; instead, Mod2 only knows about the abstract interface ModI \u2013 which would admit an unbounded number of alternate implementations beyond that provided by Mod1.

The proxy\u2009\u2013\u2009interface pattern

The pattern exemplified here occurs extensively within the EM runtime, and largely holds the key to maintaining platform portability. As a case in point, the package em.utils contains only portable modules such as AlarmMgr which declares a local proxy implementing the em.hal/WakeupTimerI interface. Client application modules likewise desiring hardware independence can simply follow suit, using the proxy\u2009\u2013\u2009interface pattern at each point of potential variability.

Moving on to Chapter 2, we'll now explore the process of binding the Mod2.ModX proxy to the Mod1 module.

"},{"location":"intro/to-2/","title":"Assembling application elements","text":"

By leveraging the proxy\u2009\u2013\u2009interface design pattern, EM modules exhibit component-like qualities \u2013 enabling third-party integrators to effectively compose a set of modules that otherwise have no direct knowledge of one another.

To facilitate general aggregation and assembly of discrete modules into larger application entities, the EM language introduces a multi-faceted construct known as a composite to service these needs.

"},{"location":"intro/to-2/#aggregating-modules","title":"Aggregating modules","text":"

Like modules and interfaces, each EM composite resides under a named package and will import other units \u2013 modules, interfaces, even composites \u2013 into its top-level namespace. Consistent with their role as higher-level collection points for discrete modules, EM composites will often import surprisingly large numbers of modules in practice.(1)

  1. ti.distro.cc23xx/McuC for example

In their most elementary form, EM composites will selectively export a group of concrete modules under logical names known to higher-level clients.

bob.pkg/CompC.em
package bob.pkg\n\nimport Mod1 as ModX     # omit redundant 'from' clause\n\nexport ModX             # a logical module\n\ncomposite CompC             \nend\n

After re-labeling bob.pkg/Mod1 at line 3 using an as clause, the export directive at line 5 publicizes the name ModX; clients importing CompC can then use the (logical) module named ModX, otherwise oblivious to its true identity as bob.pkg/Mod1. While not declared explicitly, ModX in fact belongs to the ModI family of modules \u2013 serving as a concrete delegate suitable for binding to an abstract proxy implementing a common programmatic interface.

Component-oriented programming

Programming with components \u2013 which takes modularity, separation of concerns, and resilience in the face of change to entirely new levels \u2013 dictates that (abstract) interfaces define all functional interactions between independently-replaceable elements. As such, each (concrete) software component \"provides\" and \"requires\" services defined by some set of interfaces \u2013 not unlike the standardized \"plugs\" and \"sockets\" found in hardware components. Through disciplined use of export directives within EM composites and proxy declarations within EM modules, we can emulate the provides\u2009\u2013\u2009requires paradigm that forms the backbone of all component-oriented systems.

"},{"location":"intro/to-2/#binding-proxies","title":"Binding proxies","text":"

Besides aggregating modules, EM composites will often take on the task of \"wiring\" together a set of modules into a more integrated assembly \u2013 especially modules like our last version of dave.pkg/Mod2, which utilize local proxies to further decouple themselves from potential suppliers. To illustrate:

geof.pkg/CompC.em
package geof.pkg\n\nfrom bob.pkg import Mod1      # concrete delegate\nfrom dave.pkg import Mod2     # exposes abstract proxy\n\ncomposite CompC\n    # no features\nend\n\ndef em$configure()\n    Mod2.ModX ?= Mod1         # bind proxy to its delegate\nend\n

Reflecting its higher-level position within the application hierarchy, this particular composite reaches across multiple packages starting at line 3 when importing a set of modules. The actual binding of bob.pkg/Mod1 to dave.pkg/Mod2 via the latter's ModX proxy then occurs at line 11, using a special single-assignment operator [\u2009?=\u2009] which we'll explain later. We'll also have more to say about the role played by the intrinsic function em$configure.

EM distro packages

To use the EM language, you'll need an EM distro \u2013 a multi-tiered sub-system that melds portable runtime content in packages like em.utils with hardware-specific content in packages like ti.mcu.cc23xx. By design, each EM distro will publish a top-level composite with a fully-qualified name like ti.distro.cc23xx/BoardC. This BoardC composite in turn builds upon other composites \u2013 whether hardware-specific ti.distro.cc23xx/McuC or else portable em.mcu/CommonC.

"},{"location":"intro/to-2/#configuring-parameters","title":"Configuring parameters","text":"

Just as individual functions may have parameters, EM modules as a whole can publicize a special kind of parameter known as a config which clients in turn can selectively assign inside of em$configure. To illustrate typical usage, let's expand our earlier versions of bob.pkg/Mod1 and dave.pkg2/Mod2 to now expose some new client-visible features in the form of configuration parameters.

bob.pkg/Mod1.em
package bob.pkg\n\nmodule Mod1\n\n    config flag: bool\n        #   ^| Enable some functionality\n    # other public features\n\nprivate:\n\n# etc...\n
dave.pkg/Mod2.em
package dave.pkg\n\nmodule Mod2\n\n    config count: uint8\n        #   ^| Establish some threshold\n    # other public features\n\nprivate:\n\n# etc...\n

As you might glean from the special documentation comments, the flag parameter declared at Mod1 6 and the count parameter declared at Mod2 6 should each render these modules more flexible than before, and hence increase opportunities for clients to (re-)use Mod1 and Mod2 in a wider range of applications. Syntactically similar to const and var declarations within the language, config parameters have a very special semantic property:

An EM config behaves like an assignable var at build-time, but like a read-only const at run-time.

Once we delve into the EM program life-cycle \u2013 from build-time through run-time \u2013 you'll understand the rationale behind this paradox, as well as more fully appreciate the implications of module configuration for resource-constrained embedded applications. For now, suffice it to say that EM composites serve as an ideal site for assigning module config parameters when assembling application programs. Expanding our earlier example:

geof.pkg/CompC.em
package geof.pkg\n\nfrom bob.pkg import Mod1\nfrom dave.pkg import Mod2\n\ncomposite CompC\nend\n\ndef em$configure()\n    Mod2.ModX ?= Mod1         # bind proxy to its delegate\n\n    Mod1.flag ?= true         # assign config parameters\n    Mod2.count ?= 100\nend\n

Just as we bound proxies to delegates, the single-assignment statements at lines 12 and 13 bind parameter values consistent with the types used in corresponding config declarations found at Mod1 6 and Mod2 6. In this light, clients can treat proxies as a special kind of con\u00adfiguration parameter \u2013 assigned module values implementing a declared interface type.

More configuration examples

The em$preconfigure and em$configure functions defined within McuC provide a realistic example of configuration \u2013 starting with a call to BoardInfo.readRecordH, which returns a data-structure of board-specific parameter values read from a YAML source file. The (portable) implementation of readRecordH found within the em.utils/BoardInfo module hints at the range of programmability we can bring to bear during configuration.

"},{"location":"intro/to-2/#instantiating-templates","title":"Instantiating templates","text":"

The EM language provides a general-purpose template mechanism for synthesizing other source-level artifacts \u2013 from fragments of C code to complete\u2009.em files \u2013 during the program build process. The latter scenario, which we'll focus on here, enables suppliers to deliver concrete modules in a more generic embodiment \u2013 one that clients will frequently instantiate within the context of an EM composite.

Starting from the client's perspective, the following composite effectively manufactures a pair of new modules \u2013 locally aliased as Clone1 and Clone2 \u2013 by instantiating a common imported template named thom.pkg/GenT.

geof.pkg/CompC.em
package geof.pkg\n\nfrom thom.pkg import GenT {flag: true, count: 100} as Clone1\nfrom thom.pkg import GenT {flag: false, count: 200} as Clone2\n\nexport Clone1\nexport Clone2\n\ncomposite CompC\nend\n\ndef em$configure()\n    # assign Clone<n> config parameters\n    # bind Clone<n> proxies to delegates\n    # delegate other proxies to Clone<n>\nend\n

Using an expanded form of import directive at lines 3 and 4, this composite works with (synthesized) modules Clone1 and Clone2 no differently than how we employed the bob.pkg/Mod1 or dave.pkg/Mod2 modules defined earlier. Since Clone1 and Clone2 have no prior outside identity, composites will often export these newly-formed modules for use by higher-level clients; composites may further configure and assemble these synthesized modules within the body of their own em$configure function.

The flag and count values bound at lines at lines 3 and 4 above \u2013 which shape the essential characteristics of the synthesized Clone1 and Clone2 modules \u2013 ultimately correspond to public configuration parameters declared within thom.pkg/GenT:

thom.pkg/GenT.em
package thom.pkg\n\ntemplate GenT\n\n    config flag: bool\n        #   ^| Enable some functionality\n    config count: uint8\n        #   ^| Establish some threshold\nend\n\ndef em$generateUnit(pn, un)\n            |-> package `pn`\n            |->\n            |-> module `un`\n            |->\n    if flag\n            |-> const MAX: Uint8 = `count`\n    end\n            # generate remainder of this module\nend\n

Like any other config, the parameters declared after line 5 become assignable variables at program build-time \u2013 in this case, via import directives beginning at line 3 of CompC. The GenT template will then consume these configuration parameters within the body of its em$generateUnit function, which synthesizes lines of source code using special EM output statements prefixed by the |-> symbol.

The flag config declared at 6 impacts the generated output by controlling execution flow within em$generateUnit; by contrast, this function directly interpolates the count config declared at 9 within the generated output. When invoked, em$generateUnit receives pn and un arguments bound to strings like \"geof.pkg\" and \"CompC__Clone1\" \u2013 reflecting the original context in which the geof.pkg/CompC composite imported and instantiated the GenT template back on the earlier line 3.

More template examples

Our McuC composite instantiates a module-per-pin using this GpioT template. Inspecting this template's em$generateUnit function, note how the pin config ultimately shapes the synthesized module through interpolation within the |-> output statements. Though not a rule, synthesized modules will often implement an interface that captures their commonality \u2013 em.hal/GpioI in the example at hand.

To further grasp the special role played by composite and template units, let's proceed onward to Chapter 3 and explore EM's rather unique build flow.

"},{"location":"intro/to-3/","title":"From build-time to run-time","text":"

We turn now to the life-cycle of an EM program \u2013 covering its build-time transformation from a single \"main\" source module into a binary program image comprising multiple modules, as well as its run-time execution phases from hardware reset to system shutdown.

Along the way, you'll understand the role played by EM language intrinsics throughout the program life-cycle \u2013 not only to demarcate execution phases at program run-time (em$run), but also to enable active participation by content suppliers at various stages during program build-time (em$configure and em$generateUnit).

"},{"location":"intro/to-3/#high-level-build-flow","title":"High-level build flow","text":"

The following figure depicts the four principal phases of the EM program life-cycle, as well as maps out the high-level flow of build-time artifacts \u2013 starting with a ModP.em source file and ending with a main.out binary image. The first three of these phases unfold on your host computer, and collectively constitute program build-time; the final phase, needless to say, represents run-time execution of the generated program on target hardware.

Program build flow"},{"location":"intro/to-3/#unit-translation","title":"Unit translation","text":"

Each\u2009.em source file \u2013 whether a module, interface, composite, or template \u2013 represents an independent unit of translation within EM. Starting from a designated top-level unit \u2013 in our case, a module named ModP which would implement the em$run intrinsic \u2013 EM will (recursively) process an N-element hierarchy of other translation units that ModP directly or indirectly imports; since the relation defined by import directives cannot have cycles, translating ModP effectively yields a top-to-bottom (partial) ordering of its dependent units.

Translating concrete modules such as ModP will generally produce three corresponding output files, consumed in subsequent phases of the program build process:

ModP.hpp the public\u2009/\u2009private features of ModP translated into a C++ header file ModP.cpp internal function definitions within ModP translated into equivalent C++ code ModP.js a JavaScript rendition of ModP which will contribute during program configuration

Translating abstract interfaces such as our earlier ModI example will only yield a ModI.js and ModI.hpp output file. Translating composites or templates such as our earlier CompC or GenT examples \u2013 which contribute at build-time but not run-time \u2013 will only yield a CompC.js or GenT.js output file.

Finally, all template instantiations encountered en route through import directives (such as the references to GenT in CompC) will trigger immediate execution of the designated template's em$generateUnit intrinsic \u2013 already translated to JavaScript within the GenT.js output file. Unit translation of the new\u2009.em file produced at this step then proceeds recursively.

Translator efficiency

A top-level module such as ModP could easily have static dependencies on more than 100 other translation units \u2013 especially when imported composites aggressively instantiate templates managing discrete MCU resources like GPIO pins. To accelerate program build-time, the EM translator maintains an internal cache of all generated files and will only (re-)translate a particular\u2009.em file when deemed necessary.

"},{"location":"intro/to-3/#program-configuration","title":"Program configuration","text":"

The configuration phase of the EM program life-cycle \u2013 still upstream from the final compilation of all generated C++ code into a binary image \u2013 actually entails executing a special hosted version of the program rendered in JavaScript. Labeled main.js in the earlier figure, this fabricated program basically amalgamates the\u2009.js files output for each module or composite found within the N-element import hierarchy rooted at ModP itself.

But why JavaScript\u2009???

Seemingly, any hosted language (Java, Python, Ruby) could provide a suitable execution environment for this phase of the EM program life-cycle. Some might argue the case for Python, as this language already plays a similar role with respect to C/C++ code \u2013 especially in emerging platforms such as TinyML, which deploy machine-learning algorithms (developed in a hosted Python environment) onto embedded target hardware.

As it turns out, JavaScript had already claimed the host language role among EM's predecessors \u2013 notably the Eclipse\u2009/\u2009RTSC project which in turn drew upon earlier DSP/BIOS configuration technology. Given the Java-centricity of the Eclipse IDE, Mozilla's Rhino \u2013 a JavaScript engine written in Java and seemlessly integrated with the JVM runtime \u2013 served as an ideal environment at that point in time.

Indeed, an Eclipse plug-in (written in Java) provided almost a decade of IDE support for the EM language; and Rhino therefore remained our JavaScript platform of choice. But now that language support for EM has migrated to the VS Code IDE \u2013 written in TypeScript and running on the Chromium\u2009/\u2009V8 engine \u2013 Node.js provides an even richer JavaScript platform for hosting the configuration phase of the EM program life-cycle.

During its execution, the prog.js program makes three top-to-bottom passes over the N-element import hierarchy rooted in ModP \u2013 invoking JavaScript translations of certain EM intrinsics on a per-unit basis (if defined).

The 1st pass invokes em$preconfigure, which only composites may elect to define; public proxies and config parameters bound at this time using the single-assignment operator [\u2009?=\u2009] become immune to further modification in the next pass.

The 2nd pass invokes em$configure, which modules as well as composites may elect to define; proxies and configs bound here using the [\u2009?=\u2009] operator become immune to further modification by lower-level units yet to execute in this pass.

The 3rd pass invokes two intrinsics on modules whose special em$used config parameter tests true: em$construct, for initializing private module state; and em$generateCode, for synthesizing internal C/C++ code using the EM template mechanism illustrated in GenT.

The [\u2009?=\u2009] operator, as hinted earlier, implements single-assignment semantics \u2013 sealing the first value assigned to a configurable proxy or parameter, while silently ignoring all sub\u00adsequent assignments to the same feature. With a top-to-bottom ordering imposed on the ModP import hierarchy, [\u2009?=\u2009] operations executed by higher-level modules and composites essentially \"override\" (default) binding decisions made by lower-level units. By implementing em$configure, ModP itself can now preempt proxy\u2009/\u2009parameter assignments otherwise made by any modules or composites it may import.

More on pre-configuration

Higher-level modules such as ModP cannot, however, effect the values of configurable features already bound in the first configuration pass via em$preconfigure; the latter intrinsic enables suppliers of EM composites to selectively freeze proxy bindings and parameter values, tempering flexibility in the interest of robustly assembling elements for a fixed application setting. As an example, our McuC composite binds physical pin numbers read from a board-specific YAML file \u2013 reflecting the \"hard reality\" of the underlying hardware.

Referring to the earlier figure, one practical consequence of configuration becomes pruning the original (and often large) N\u2013element import hierarchy into a more tractable M\u2013element subset comprising those modules actually used within the program. In support, each module has an intrinsic em$used parameter \u2013 automatically bound in most cases, but explicitly con\u00adfigurable if necessary \u2013 that ultimately determines membership in the M\u2013element subset.

The top-level module ModP has its em$used parameter automatically set, and is always used within the program.

If module Mod1 is used and Mod1 imports module Mod2 (directly or via a composite), then Mod2 is used as well.

If module Mod1 is used and proxy Mod1.ModX ultimately delegates to module Mod2, then Mod2 is used as well.

Otherwise Mod1 is not used in the program, unless some higher-level module or composite explicitly sets Mod1.em$used.

The final configuration pass gives each used module within the M\u2013element subset an opportunity to focus internally; configuration of all public features of these modules would have already occurred. By defining the em$construct intrinsic, modules may programmatically initialize their private var, config, or even proxy features at this point within the flow.

But since em$construct actually executes on your host computer, module suppliers can now implement complex initialization algorithms at build-time that would otherwise prove far too costly to execute at run-time on resource-constrained MCUs.

With language constructs normally used to implement target-side functions like em$run also available in hosted functions like em$construct, module suppliers can now migrate (expensive) computations from run-time to build-time with little effort. Said another way, EM can serve as its own meta-language \u2013 synthesizing the final form of a concrete module by statically reflecting upon values assigned to its configurable parameters.

Examples of EM meta-programming \u2013 data initialization

The em$construct function of ti.mcu.cc23xx/ConsoleUart0 computes values for private configs ibrd and fbrd, eventually used to initialize hardware registers defining the UART's baud-rate; a less efficient implementation would perform this computation at run-time. Taking this approach to the next level, the em$construct function of em.utils/FftC32 initializes a custom sine-wave table at build-time.

Besides executing (costly) math functions, EM meta-programming can also initialize complex, linked data-structures at build-time \u2013 such as the em$construct function and createH functions of em.utils/FiberMgr, which in turn call build-time functions of em.utils/ListMgr. As a general rule, any static initialization of data at build-time results in more compact programs at run-time.

Complementing em$construct \u2013 oriented towards initializing private state \u2013 some modules will also implement the em$generateCode intrinsic. Using the same form of templatized output statements illustrated earlier in GenT, module suppliers can inject customized C/C++ code fragments into the final program image \u2013 with public config par\u00adameters typically shaping the synthesized output.

Examples of EM meta-programming \u2013 code generation

On the low end of the scale, MCU-specific modules like ti.mcu.cc23xx/Regs use the em$generateCode intrinsic to #include vendor-supplied header files; modules such as Rtc will then reference symbols and macros defined in these headers using a special ^^ escape token.

Moving up a notch, the ti.mcu.cc23xx/IntrVec module programmatically synthesizes the run-time vector table for this MCU using build-time bindings of interrupt handlers \u2013 complete with compiler-specific directives to control placement in memory. In the limit, em$generateCode can leverage the full capabilities of JavaScript executing on your host computer.

"},{"location":"intro/to-3/#program-compilation","title":"Program compilation","text":"

Referring back to the earlier figure, the ultimate outcome of executing the main.js (meta-) program within the overall EM build-flow becomes yet another program \u2013 this time, a single C++ program labeled main.cpp. As suggested earlier, this program only incorporates generated code from the M used modules selected from the original set of N imported units traced back to ModP.em.

Each module Mod participating in this consolidated C++ program respectively contributes (in order) the following portions of code, which collectively represents the bulk of the generated main.cpp file's content:

constant, type, variable, and function declarations from Mod.hpp, generated during the initial translation of Mod.em;

static data initializers reflecting the values assigned to public\u2009/\u2009private features of Mod during the prior configuration phase;

any C/C++ code synthesized by the Mod.em$generateCode intrinsic, executed during the prior configuration phase; and

definitions of declared and intrinsic functions from Mod.cpp, generated during the initial translation of Mod.em.

By merging all generated C/C++ code into a single input file, the underlying compiler for the target MCU can aggressively optimize the program as a whole \u2013 folding away constants, inlining small functions, and eliminating unused code or data. As a case in point, client function calls via abstract proxies to configured delegate modules \u2013 seemingly a double-indirection at run-time \u2013 will usually \"melt-away\" and leave the delegate function body inlined at the client call-site.

Example of whole-program optimization

Returning to FftC32, its exec function uses three config parameters at run-time which em$construct previously initialized by at build-time \u2013 N_WAVE, N_WAVE_LOG2, SINE_WAVE. Knowing the values of these parameters when digesting main.cpp, the compiler has greater latitude in making time\u2009/\u2009space tradeoffs when generating object code for FftC32.exec.

As another example, em.utils/FiberMgr makes many function calls via Common.GlobalInterrupts \u2013 a proxy which conforms to the GlobalInterruptsI interface, and ultimately delegates to a hardware-specific implementation such as ti.cc23xx.mcu/GlobalInterrupts. Knowing this particular proxy\u2009-\u2009delegate binding, the compiler would inline the delegate's (small) functions directly at each Common.GlobalInterrupts call site.

"},{"location":"intro/to-3/#program-execution","title":"Program execution","text":"

This final phase of the EM program life-cycle \u2013 which represents the transition from build-time to run-time \u2013 technically commences when you load the executable main.out image into target memory and reset the MCU. But as you'll see, run-time contributions from the M concrete modules used within this program won't occur until execution reaches main.

The path to main

The path actually taken from loading the main.out file to executing the C/C++ main function can vary widely from one target environment [MCU\u2009+\u2009compiler\u2009+\u2009board] to the next; but fortunately, each distribution of the EM software platform will render this process transparent to the application developer. In practice, each EM distro will leverage much of the tooling infrastructure supporting the underlying MCU \u2013 from flash loaders that operate on standard\u2009.bin or\u2009.hex files, to compiler startup files like crt0.s that manage the transition from MCU reset to C/C++ main as efficiently as possible.

For the M concrete modules bound within the main.out image, program run-time actually begins when target execution reaches the C/C++ main function. Since the un\u00adderlying compiler's own startup file does little more than prepare data memory and initialize critical CPU registers, more comprehensive startup of the target board and the MCU peri\u00adpherals still needs to occur prior to calling the top-level ModP.em$run intrinsic.

The main function initially calls a C++ rendition of Modr.em$reset, where Modr represents the first module to implement this intrinsic found by a top-to-bottom scan of the M modules used in this program; needless to say, this scan occurs at program build-time, not run-time. In practice, some target-specific module included with your EM distribution will assume responsibility for defining the em$reset intrinsic; higher-level application modules generally avoid (re-)defining this intrinsic.

The main function will next call C++ renditions of Modi.em$startup for each Modi found to implement this intrinsic; here too, a top-to-bottom scan of all M program modules occurs at build-time. Unlike em$reset, higher-level application modules down to target-specific driver modules will define this intrinsic in order to perform (run-time) initializations not possible during (build-time) execution of em$construct.

The main function then calls a C++ rendition of Mods.em$startupDone, where Mods represents the first module found to implement this intrinsic through a top-to-bottom scan of all M modules participating in the program. As with em$reset, your EM distribution will usually take responsibility for defining em$startupDone \u2013 which performs any final hardware setup before the application program assumes control.

The main function finally calls a C++ rendition of ModP.em$run, which effectively transfers control to the top-level module of this application. Since embedded applications often execute some form of \"run forever\" loop \u2013 whether explicitly coded within the program or else implicitly managed by some run-time task scheduler \u2013 in practice the em$run intrinsic will not return control back to the calling main function.

Examples of em$startup

Many modules that manage MCU hardware peripherals will define em$startup \u2013 such as Idle and Rtc found in the ti.mcu.cc23xx package; clearly, this sort of hardware setup must occur at run-time. By extension, portable modules like em.utils/SoftUart which leverage proxies to interact with underlying hardware may likewise rely upon em$startup to perform some run-time initialization \u2013 in this case, initializing a GpioI proxy named TxPin.

Should the top-level ModP.em$run intrinsic actually return to main, control then transfers to a distinguished __halt function \u2013 also generated prior to program compilation \u2013 which supervises an orderly shutdown of the target application. If necessary, any program module can explicitly initiate the shutdown sequence at run-time through a special halt statement that can appear inside EM function definitions.

The __halt function will first call C++ renditions of Modi.em$shutdown for each Modi found to implement this intrinsic; higher-level applications down to target-specific drivers modules will define this intrinsic in order to perform run-time finalization prior to halting the processor.

The __halt function then calls a C++ rendition of Modh.em$halt, where Modh represents the first module to implement this intrinsic found by a top-to-bottom scan; each EM distro offers a \"default\" version of em$halt, though higher-level modules may (re-)define this intrinsic in some cases.

Should the implementation of em$halt happen to return to __halt, program control would fall-through to a special block of code that simply spins within an infinite loop.

In cases where something goes \"seriously wrong\" within the system and execution should terminate more abruptly, EM also supports a special fail statement that can appear in any function definition. When executed at run-time, fail immediately transfers control to an implementation of the em$fail intrinsic \u2013 often found within the same module implementing em$halt; should em$fail return, the program likewise enters an infinite loop.

More on startup/shutdown intrinsics

By design, each EM distro relies upon the portable em.utils/BoardController module which centralizes definitions of the singleton intrinsics em$reset, em$startupDone, em$halt, and em$fail; configuration of the BoardController module and its dependents typically occurs within the distro's BoardC composite. In those (rare) circumstances where some higher-level module needs to \"override\" one of these special functions, the higher-level intrinsic definition would likely call the corresponding \"base\" function within BoardController.

While we've already directed you to browse selected\u2009.em source files drawn from EM platform runtime, Chapter 4 concludes our technical overview with more comprehensive picture of this environment.

"},{"location":"intro/to-4/","title":"Software platform content","text":"

While software design and development focuses on individual\u2009.em files \u2013 modules, interfaces, composites, templates \u2013 a more coarse-grained construct known as a bundle serves as the unit of software delivery within the EM platform. Like the packages they ultimately contain, each EM bundle bears a globally-unique qualified name suggestive of its publisher and purpose \u2013 though individual\u2009.em files will only reference packages by name, and never the containing bundle itself.

Representing \"components-in-the-large\", an EM bundle will not only publicize the elements it provides but will also identify other bundles it requires for successful deployment; de\u00adpendent bundles may in turn require other bundles \u2013 reminiscent of the hierarchic import relation between individual\u2009.em files. Bundles can also serve as a unit of software versioning within the platform, with dependencies optionally constrained to particular labeled releases.

In the sections that follow, we'll respectively explore these three EM bundles:

em.core

hardware-independent packages fundamental to EM

ti.cc23xx

hardware-dependent packages comprising a typical EM distro

em.docs

hardware-independent example programs which use the prior bundles

"},{"location":"intro/to-4/#portable-content","title":"Portable content","text":"

As its name suggests, the em.core bundle incorporates rudimentary and essential content present in all distributions of the EM software platform \u2013 some of which we've already visited earlier in this document. Through aggressive use of the proxy\u2009\u2013\u2009interface pattern, a critical subset of the em.core bundle \u2013 specifically, its em.mcu and em.utils packages \u2013 in fact remain 100% portable across all target environments.

em.hal

This package contains abstract interfaces reflecting the functionality of low-level hardware elements found within embedded MCUs \u2013 ConsoleUartI, LedI, WakeupTimerI, and many others; this package contains also contains \"empty\" implementations of these interfaces (ConsoleUartN, LedN, etc), often used as default proxy bindings. As such, this package serves as a critical hardware abstraction layer (HAL) \u2013 prescribing a fundamental architectural boundary that insulates portable (hardware-independent) content from target-specific (hardware-dependent) content.

em.utils

This package comprises a somewhat eclectic (and ever-expanding) collection of run-time application services \u2013 ranging from elementary modules like ListMgr and FiberMgr up to more sophisticated templates like ButtonT and LedT. While mostly supporting program run-time, special host modules like BoardInfo and BoardMeta offer (portable) services used by EM distros at program build-time.

em.mcu

Unlike em.utils, this package generally limits its contents to what we'll term as global proxies \u2013 a set of well-known modules that implement certain em.hal interfaces by effectively forwarding function calls to a conformant delegate; ConsoleUart and Poller illustrate this pattern. This package also contains the widely-used Common module, which conveniently aggregates additional global proxies into a single unit.

em.lang

Invisible to most clients, this package helps bootstrap the implementation of the EM language itself through several distinguished interfaces declaring intrinsic configs and functions:\u00a0 ModuleI, that all modules or interfaces will inherit; CompositeI, that all composites will inherit; and TemplateI, that all templates will inherit. This package also contains the Console module and its ConsoleProviderI interface \u2013 supporting printf statements innate to the language. Finally, this package houses common C/C++ and JavaScript code fragments interpolated during the EM program build-flow.

Using EM will take a more detailed look at the source code of specific\u2009.em files found in the first three of these packages.

"},{"location":"intro/to-4/#target-specific-content","title":"Target-specific content","text":"

Complementing em.core and its portable packages, the ti.cc23xx bundle delivers support for the Texas Instruments CC2340R5 wireless MCU. While specifically targeting a particular MCU family, the organization of the packages found within the ti.cc23xx bundle follows a pattern generally seen within any EM distro.

ti.distro.cc23xx

This package (and in fact the entire ti.cc23xx distro bundle) revolves around a single composite conventionally named BoardC \u2013 responsible for configuring parameters as well as binding proxies exposed by elements of em.core. This package also contains two other conventionally named units found in any EM distro:\u00a0 the McuC composite, which (in this case) focuses on the ti.mcu.cc23xx package; and the special host BoardMeta module, which effectively defines the schema of the board-specific YAML file mentioned earlier in the context of configuration and pre-configuration.

ti.mcu.cc23xx

Many of the modules in this package provide MCU-specific implementations of abstract interfaces found in em.hal \u2013 ConsoleUart0, Idle, OneShotGpt3, and others. Likewise, this package features templates such as GpioT and InterruptT whose em$generateUnit intrinsics synthesize MCU-specific implementations of other HAL interfaces at program build-time. Finally, this package contains even lower-level auxiliary modules (eg, Regs and Rtc) whose clients typically remain within the distro itself.

ti.build.cc23xx

This package contains host modules that control the compiling\u2009/\u2009linking of target EM programs using a particular C/C++ toolchain. The modules typically pass target-specific information such as memory maps or register declarations to generic modules found in a special em.build bundle, which we'll discuss in a later document.

Porting EM will dive into virtually all of the\u2009.em source files found in these three packages, as well as explore the em.build bundle mentioned above.

"},{"location":"intro/to-4/#elementary-programs","title":"Elementary programs","text":"

The em.examples.basic package within the em.docs bundle contains a curated set of programs described at length in Using EM. A live sequence of \"guided tours\" that view\u2009/\u2009build\u2009/\u2009load these programs revolve around the following modules:

HelloP hello world Tour 00 BlinkerP basic blinker Tour 01 BlinkerDbgP real-time debug Tour 02 FiberP threading with fibers Tour 03 Button1P button handlers Tour 04 Button2P button fibers Tour 05 Button3P button objects Tour 06 OneShot1P timer handlers Tour 07 OneShot2P timer fibers Tour 08 PollerP timer service Tour 09 Alarm1P wakeup alarms Tour 10 Alarm2P aligned wakeups Tour 11 TickerP cyclic tickers Tour 12

To ensure their portability, none of these programs explicitly reference the \"current\" EM distro package [\u2009ti.distro.cc23xx\u2009] by name; rather, these programs use a special language intrinsic [\u2009em$distro\u2009] as a logical name which you will bind to a particular distro package.

"},{"location":"intro/to-4/#learning-more-em","title":"Learning more EM","text":"

If you want to learn more about EM \u2013 but continue to fly at 10,000' for now \u2013 we strongly recommend reading through Using EM to get a sense for the platform's tooling and runtime from a ground-level perspective; a quick pass through the other documents at this site should prove informative as well.

When you want to hit the ground running and start coding, however, you'll definitely need to first work through Installing EM before proceeding onward to Using EM. Both of these documents also accomodate a special **\u2009FAST-TRACK\u2009** option, which enables you to rapidly experience the EM development environment as well as learn more about em.core.

The Porting EM document continues on the ground, exploring the ti.cc23xx bundle in greater detail as well as outlining the steps required to create new EM distros that support other MCUs. Over time, we expect Porting EM will draw upon a broader set of distro bundles to further reinforce the EM platform's architecture for encapsulating target-specific content.

Finally, Advancing EM contains an ever-growing collection of standalone articles addressing a wide-range of topics about EM. While many of these articles expect that you've already spent time on the ground coding, others presume just a 10,000' understanding of Using EM.

Case in point:\u00a0\u00a0 we strongly recommend the Energy Consumption article, which presents further evidence supporting a hypothesis about EM put forth earlier.

Happy coding\u2009!!! \u2002

"},{"location":"porting/","title":"Managing hardware diversity in EM","text":"

Under Construction \u2014 estimated completion in 1Q24 \u2009

"},{"location":"using/","title":"Writing portable applications in EM","text":"

If you've made it this far, let's hit the ground running and starting coding\u2009!!!\u00a0\u00a0 This document will first familiarize you with the mechanics of viewing, editing, building, and loading EM programs and their constituent units using the EM Builder extension for VS Code. If you haven't worked with VS Code, the web abounds with tutorials\u2009+\u2009references for this ever-popular IDE.

The main portion of this document comprises a series of tours that visit some basic programming examples \u2013 curated to introduce elements of the EM runtime environment, as well as to reinforce common coding idioms of the EM language(1). To support these documentation resources, EM Builder includes a \"tour guide\" utility that walks you through this material in a somewhat specialized fashion.

  1. consult Language Syntax as a reference

If you've chosen to bypass Installing EM for now, a quick read through this document would still have benefit \u2013 even if you can't execute real software on real hardware.

If you have elected to install EM Builder \u2013 but haven't received your hardware or else prefer the **\u2009FAST-TRACK\u2009** option \u2013 you can still build the programs featured in any of the tours. Until your board arrives and you can actually load these programs, studying the logic capture(s) associated with each example should help bridge the gap.

These captures in fact reveal subtle timing details otherwise invisible to the naked eye.

We've generated all of the captures presented later in this document using a Saleae Logic Analyzer \u2013 in our opinion, the single most valuable tool for \"debugging\" real-time embedded software running on target MCU hardware. At a minimum, you should download the (free) Saleae Logic 2 software and explore these logic capture files off-line.

If you can't see the problem, you can't fix it\u2009!!!

Software debuggers have traditionally focused upon a rich presentation of program state (variables, call stacks, peripherals) \u2013 but only after program execution halts (say) upon reaching a breakpoint. Given the general nature of embedded software, however, a dynamic presentation depicting state-changes over time proves far more helpful for troubleshooting real-world problems.

While modern debuggers attempt to address this need, they often do so by introducing significant amounts of hardware\u2009/\u2009software overhead \u2013 limiting their utility to software development rather than system deployment. These approaches may also preclude the underlying MCU from entering its \"deep-sleep\" mode \u2013 a serious limitation that can obscure real-world, real-time wakeup issues.

But armed with no more than a basic logic analyzer, the EM language provides intrinsic \"real-time debug\" capabilities that enable us to dynamically capture program state without incurring excessive program overhead. In the spirit of \"test what you fly, fly what you test\", these capabilities prove equally valuable during development in the factory and well as during deployment in the field.

At the same time, we also want you to experience the joy of blinking LEDs\u2009!!!\u00a0\u00a0 With that, let's first skill-up on EM Builder and then tour the EM runtime.\u00a0

When finished, circle back to Learning more EM and plan your next adventure.

"},{"location":"using/using-01/","title":"Working with EM Builder","text":"

To flatten your learning curve, we'll work exclusively within the VS Code environment \u2013 using the EM Builder extension which you've already installed. Besides introducing some core capabilities of the extension, the material that follows will also verify the integrity of your installation.

But what about the command line\u2009???

Strictly speaking, we don't need VS Code to develop EM software:\u00a0 you can create folders\u2009/\u2009files as you always have; you can create\u2009/\u2009modify\u2009.em sources in your favorite text editor; and you can build\u2009/\u2009load executable EM programs using the em-cli command-line interface.\u00a0 The implementation of EM Builder and em-cli, in fact, share quite a bit of common code \u2013 with the former often invoking the latter. The Command-line inteface reference material describes the em-cli tool in greater detail.

"},{"location":"using/using-01/#workspace-organization","title":"Workspace organization","text":"

The following animation illustrates the overall organization of your workspace folder when using the EM Builder extension, and picks up from where we left off when Installing EM.\u2009 We also encourage you to launch VS Code by entering code workspace from your PC's shell, and to simultaneously explore this environment at your own pace.

VS Code Screen Layout

VS Code Screen Layout"},{"location":"using/using-01/#building-em-programs","title":"Building EM programs","text":"

The following animation illustrates how to build HelloP.em using the EM - Build command, selected from this file's (right-click) context menu. Since this program contains a main em$run function, the EM translator produces a corresponding executable image; see the OUTPUT panel for details.

EM - Build

EM - Build"},{"location":"using/using-01/#loading-em-programs","title":"Loading EM programs","text":"

The following animation illustrates how to load the previously-built HelloP.em program using the EM - Load command \u2013 also selected from a context menu. Should loading the executable image fail for some reason (eg, you don't even have a target board), an error message would appear in the OUTPUT panel.

EM - Load

EM - Load"},{"location":"using/using-01/#monitoring-em-programs","title":"Monitoring EM programs","text":"

The following animation illustrates how to monitor any printf output from the currently loaded program image, by invoking EM - Open Console within the VS Code Command Palette\u2009. Once the special TERMINAL panel has launched, press the RESET button on your target board and enjoy the show\u2009!!!

EM - Open Console

EM - Open Console"},{"location":"using/using-01/#creating-em-artifacts","title":"Creating EM artifacts","text":"

The following animation illustrates how to create a workspace bundle using the EM - New Bundle command, likewise found in the Command Palette\u2009. In this case, we've named the new artifact as my.bundle; the remainder of this document will often refer to this folder as your \"personal\" bundle.

EM - New Bundle

EM - New Bundle

The following animation illustrates how to populate your personal bundle folder with other EM artifacts \u2013 packages, modules, interfaces, etc \u2013 created using commands selected from the (right-click) context menu of the containing folder. In this case, we'll invoke EM - New Package followed by EM - New Test Program to create a unit named my.pkg/Test.

EM - New Package | EM - New Test Program

EM - New Package | EM - New Test Program"},{"location":"using/using-01/#cloning-em-cargo","title":"Cloning EM cargo","text":"

The following animation illustrates the EM - Clone command, used to populate personal bundles with runtime content delivered by the EM Builder extension and housed under the special\u2009.em-cargo folder. In this case, we'll first locate em.examples.basic/FiberP and em.utils/FiberMgr under\u2009.em-cargo and then clone these units into my.bundle.

EM - Clone

EM - Clone"},{"location":"using/using-01/#exploring-em-sources","title":"Exploring EM sources","text":"

The following animation illustrates a few of the VS Code language features supported by the EM Builder extension. In this case, we'll hover over EM identifiers and jump between\u2009.em source files; we'll also use the OUTLINE panel to navigate amongst the declarations\u2009/\u2009definitions contained within individual EM units.

VS Code Language Support

VS Code Language Support

While these capabilities prove helpful when exploring EM source code, the EM Builder extension also provides support for \"smart completion\" (IntelliSense) \u2013 even more helpful when editing your code.\u00a0 At the same time, VS Code language support remains a never-ending journey of incremental improvement.

Help wanted \u2013 VS Code programmer

"},{"location":"using/using-02/","title":"Programming with EM","text":"

Turning now to the EM runtime, a series of curated \"guided tours\" will incrementally introduce components of the em.core bundle \u2013 many of which you may have browsed in your reading of Introducing EM.\u2009 By convention, each tour revolves around a specific EM program found in the em.examples.basic package \u2013 with each of these small programming examples motivating us to visit key elements of the EM runtime.

In the material that follows, we'll reference a number of logical MCU \"pins\" configured by the current EM distro and generally accessible through headers on your target board:

\u2003\u2003\u2003\u2003\u2003appBut application button pin \u2003\u2003\u2003\u2003\u2003appLed application LED pin (usually green) \u2003\u2003\u2003\u2003\u2003appOut application console TX pin \u2003\u2003\u2003\u2003\u2003sysDbgA system debug pin A \u2003\u2003\u2003\u2003\u2003sysDbgB system debug pin B \u2003\u2003\u2003\u2003\u2003sysDbgC system debug pin C \u2003\u2003\u2003\u2003\u2003sysDbgD system debug pin D \u2003\u2003\u2003\u2003\u2003sysLed system LED pin (usually red)

A special YAML file named em-boards found the em$distro package folder binds these logical pin names to physical pin numbers of your target board. Porting EM will have more to say about em-boards, as well as explain the special setup-*.properties files located in the root of your distro bundle.

"},{"location":"using/using-02/#tour-00-guided-tours","title":"Tour 00 \u2013 guided tours","text":"

The following animation illustrates the EM - Start Tour command, which you'll use to view each of the tours described in the remainder of this document. You'll find these tours in appropriately named\u2009.emtour files, located inside the\u2009.tours/101_Using_EM folder delivered with the em.docs bundle.

EM - Start Tour

EM - Start Tour

With that, go ahead and actually take tour 00_HelloP.emtour within your VS Code environment. Before proceeding to take Tour 01\u2009\u2013\u2009Tour 12\u2009, however, you should feel comfortable with the UI presented in Tour 00\u2009; and do retake any of these tours whenever necessary.

"},{"location":"using/using-02/#tour-01-basic-blinker","title":"Tour 01 \u2013 basic blinker","text":"

This tour centers around the BlinkerP program, which toggles the appLed pin on your target board \u2013 typically connected to a green LED. This tour also visits the BusyWaitI and LedI interfaces, as well as presents the Common module and its constituent proxies.

Tour 01 \u2013 Logic Capture

\u00a0 The EM runtime quickly blinks your board's sysLed at startup.

\u00a0 The BlinkerP program toggles appLed every ~0.5\u2009s.

\u00a0 The EM runtime turns on sysLed upon normal program termination.

\u00a0 The next capture zooms into the appOut signal.

Tour 01 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

\u00a0 The EM runtime outputs this sequence of (non-printable) bytes at startup, after blinking sysLed.

\u00a0 The EM runtime output this single byte upon normal program termination, before turning on sysLed.

"},{"location":"using/using-02/#tour-02-real-time-debug","title":"Tour 02 \u2013 real-time debug","text":"

This tour focuses upon the BlinkerDbgP program, which also toggles the appLed pin on your target board. This tour highlights a number of capabilities within EM for visualizing and troubleshooting program execution in real-time.

Tour 02 \u2013 Logic Capture

\u00a0 The busy-wait bracketed by %%[d+] and %%[d-] measures ~498 ms.

\u00a0 Executing a fail statement causes sysLed to blink rapidly.

Tour 02 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

\u00a0 The %%[>cnt] statement outputs the (non-printable) 0x82 control byte followed by 2 bytes of payload.

\u00a0 The %%[>bits11] statement outputs the (non-printable) 0x81 control byte followed by 1 byte of payload.

\u00a0 The %%[c:bits11] statement causes the dbgC pin to rapidly toggle 2 times \u2013 since (bits11\u2009==\u20090x1)

\u00a0 The ASCII character output of printf begins here \u2013 0x63('c'), 0x6E('n'), and so on.

"},{"location":"using/using-02/#tour-03-threading-with-fibers","title":"Tour 03 \u2013 threading with fibers","text":"

This tour centers around the FiberP program, which introduces a very lightweight threading construct termed a fiber. This tour also visits the EM runtime's (portable) implementation of fibers found in the FiberMgr module.

Tour 03 \u2013 Logic Capture

\u00a0 The %%[d] statement in blinkFB marks each point in time where the blinkF fiber begins execution.

\u00a0 The ~200 ms between blinkF cycles includes appLed on\u2009/\u2009off time plus FiberMgr dispatch overhead.

"},{"location":"using/using-02/#tour-04-button-handlers","title":"Tour 04 \u2013 button handlers","text":"

This tour centers around the Button1P program, which handles incoming events generated when pressing appBut on your board. This tour also visits the GpioEdgeDetectMinI interface that in turn extends the GpioI abstraction.

Tour 04 \u2013 Logic Capture

\u00a0 The EM runtime uses dbgB to mirror the MCU's execution mode [\u2009L \u2013 actively running, H \u2013 awaiting wakeup\u2009]

\u00a0 Pressing your board's button drives the appBut pin low; appLed then blinks shortly thereafter.

\u00a0 A 125\u2009ns \"glitch\" on the appBut signal fired another event at this time \u2013 causing an extra appLed blink.

Tour 04 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

\u00a0 You've pressed appBut at this time, which then begins awakening the MCU from its low-power sleep.

\u00a0 Requiring 34.2\u2009\u03bcs to fully power the MCU, dbgB's falling edge marks when Button1P starts actively running.

\u00a0 Control enters handler within 3.4\u2009\u03bcs, whose initial %%[c] statement toggles dbgC for 1.2\u2009\u03bcs

\u00a0 After some housekeeping, Button1P finally turns-on appLed \u2013 5.9\u2009\u03bcs since actively running.

"},{"location":"using/using-02/#tour-05-button-fibers","title":"Tour 05 \u2013 button fibers","text":"

This tour centers around the Button2P program, which uses a Fiber object to better handle incoming events. This tour also analyzes the performance impact of this approach compared with the earlier Button1P program.

Tour 05 \u2013 Logic Capture

dbgB shows that Button2P awoke exactly twice in response to pressing appBut \u2013 no glitches this time\u2009!!!

Tour 05 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

Button2P resumes execution in 35.2\u2009\u03bcs; keep in mind that low-power MCU wakeup times can vary slightly.

\u00a0 Control then enters handler 3.4\u2009\u03bcs later \u2013 consistent with the Button1P capture seen above.

\u00a0 Unlike Button1P, the Button2P handler readies the blinkF fiber which then gains control 5.3\u2009\u03bcs later.

\u00a0 Finally, the blinkFB function turns-on appLed \u2013 with only ~5\u2009\u03bcs of FiberMgr scheduling overhead.

"},{"location":"using/using-02/#tour-06-button-objects","title":"Tour 06 \u2013 button objects","text":"

This tour centers around the Button3P program, which debounces button input signals in a portable fashion. This tour also visits the ButtonI interface along with a module implementing this interface \u2013 the latter generated by the ButtonT template at build-time.

Tour 06 \u2013 Logic Capture

\u00a0 Once triggered by pressing your board's button, the EM runtime polls the state of appBut every 100\u2009ms.

\u00a0 If pressed for \u2265\u2009100\u2009ms but \u2264\u20094\u2009s, Button3P will blink appLed within 100\u2009ms of releasing the button.

\u00a0 Hitting the 4\u2009s mark, Button3P immediately blinks sysLed\u2013 regardless of how long appBut remains low.

Tour 06 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

\u00a0 After polling appBut for 4\u2009s, the EM runtime invokes Button3P.onPressedCB which leaves a %%[c] mark.

\u00a0 Discovering that appBut remains pressed [\u2009=\u2009L\u2009], onPressedCB then blinks sysLed for 40\u2009ms.

\u00a0 Only 7.5\u2009\u03bcs elapses from dbgB falling to sysLed rising, which includes scheduling fibers plus 1.2\u2009\u03bcs for %%[c].

"},{"location":"using/using-02/#tour-07-timer-handlers","title":"Tour 07 \u2013 timer handlers","text":"

This tour centers around the OneShot1P program, which handles timer events that awaken the MCU. This tour also visits the OneShotMilliI interface, which abstracts the functionality of a short-term timer with millisecond resolution.

Tour 07 \u2013 Logic Capture

\u00a0 The dbgB signal shows that OneShot1P awakens from low-power sleep every 500\u2009ms.

\u00a0 Once awake, OneShot1P toggles dbgC and dbgD before blinking appLed \u2013 like our earlier Button1P capture

\u00a0 The 7.5\u2009\u03bcs \"wakeup-to-blink\" latency seen here includes the overhead of servicing an on-chip MCU timer.

"},{"location":"using/using-02/#tour-08-timer-fibers","title":"Tour 08 \u2013 timer fibers","text":"

This tour centers around the OneShot2P program, which now uses Fiber objects to enhance robustness when handing timer events. This tour also invites performance comparision with the earlier OneShot1P program.

Tour 08 \u2013 Logic Capture

\u00a0 Fiber scheduling adds the extra 1.1\u2009\u03bcs of latency seen here, compared with our previous OneShot1P capture.

"},{"location":"using/using-02/#tour-09-timer-service","title":"Tour 09 \u2013 timer service","text":"

This tour centers around the PollerP program, which introduces a portable function for pausing execution at run-time. This tour also visits the top-level Poller module as well as the lower-level PollerAux module \u2013 both implementing the PollerI interface.

Tour 09 \u2013 Logic Capture

\u00a0 Without %%[c] and %%[d] marks, PollerP further reduces latency compared to OneShot1P and OneShot2P.

Tour 09 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

\u00a0 The [L] dbgB signal indicates that the PollerP program has awoken.

PollerP then calls AppLed.wink within 2.5\u2009\u03bcs, which then asserts the appLed pin

\u00a0 Calling AppLed.wink 2.5\u2009\u03bcs later asserts the appLed pin and then internally invokes Poller.pause.

Poller.pause proceeds to suspend program execution for 5\u2009ms \u2013 the duration of the wink.

\u00a0 The EM runtime toggles dbgB once before awaiting the next wakeup [H]\u2009; we'll explain more in a later tour.

\u00a0 An MCU timer event will eventually awaken the program 5\u2009ms later, with dbgB now signalling [L]\u2009.

\u00a0 Control unwinds from Poller.pause back to AppLed.wink, which will now lower the appLed pin.

em$run finally regains control, and then suspends execution for 500\u2009ms by calling Poller.pause directly.

"},{"location":"using/using-02/#tour-10-wakeup-alarms","title":"Tour 10 \u2013 wakeup alarms","text":"

This tour centers around the Alarm1P program, which uses Alarm objects to schedule longer-term wakeups with (sub-)second resolution. This tour also visits the AlarmMgr module, which internally uses a proxy implementing the WakeupTimerI interface.

Tour 10 \u2013 Logic Capture

\u00a0 The Alarm1P program alternately awakens from a low-power deep-sleep of 2\u2009s or else 750\u2009ms in duration.

\u00a0 The program's blinkFB function winks appLed for 100\u2009ms, with the MCU idling in the interim.

\u00a0 Once AppLed.wink returns, Alarm1P calls alarm.wakeup to re-enter an extended period of deep-sleep.

Tour 10 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

\u00a0 The single dbgB mark indicates the MCU has entered its \"lite-sleep\" mode, after Alarm1P calls AppLed.wink

\u00a0 The MCU awakens from its lite-sleep within 100\u2009ms, returning to wink which then turns-off appLed.

\u00a0 The double dbgB mark indicates the MCU has entered its \"deep-sleep\" mode, after calling alarm.wakeup

"},{"location":"using/using-02/#tour-11-aligned-wakeups","title":"Tour 11 \u2013 aligned wakeups","text":"

This tour centers around the Alarm2P program, which now aligns Alarm wakeups with a given time-window. This tour also re-visits the AlarmMgr implementation, seeing how it schedules the next wakeup event as well as the role played by the EpochTime module.

Tour 11 \u2013 Logic Capture

\u00a0 Note how the wakeups from deep-sleep align with a series of 1.5\u2009s windows along the time-line.

\u00a0 Due to startup overhead, the first alarm.wakeup call deep-sleeps the MCU for only 1.250\u2009s to stay aligned.

\u00a0 After a 5\u2009ms appLed wink, this alarm.wakeup call deep-sleeps the MCU for 1.495\u2009s to stay aligned.

\u00a0 But after a 100\u2009ms wink, this alarm.wakeup call deep-sleeps the MCU for just 1.400\u2009s to stay aligned.

"},{"location":"using/using-02/#tour-12-cyclic-tickers","title":"Tour 12 \u2013 cyclic tickers","text":"

This tour centers around the TickerP program, which takes duty-cycled functions to a higher level. This tour also visits the TickerMgr module, whose implementation of Ticker objects emulates as well as builds upon the AlarmMgr and FiberMgr studied earlier.

Tour 12 \u2013 Logic Capture

\u00a0 The appTicker.start call by the TickerP program initiates a train of 100\u2009ms appLed winks, spaced 1\u2009s apart.

\u00a0 The sysTicker.start call by TickerP then initiates a train of 100\u2009ms sydLed winks, but spaced 1.5\u2009s apart.

\u00a0 When appTicker and sysTicker wakeups coincide, their callbacks run on a first-come, first-served basis.

"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":""},{"location":"#the-em-programming-language","title":"The EM\u2122 Programming Language","text":"

Welcome to the world of EM \u2013 a novel programming language and runtime environment targeting resource-constrained embedded systems. To increase your understanding of the language and its runtime, this site documents all aspects of the EM software platform.

If you haven't already done so, we strongly suggest starting with Introducing EM which offers a 10,000' overview of the EM language and runtime \u2013 even if you just can't wait to install the EM software and start hacking some code\u2009!!!\u00a0\u00a0 Besides rationalizing the need for EM, this overview introduces concepts as well as defines terminology used throughout the site.

Building upon this introductory overview of EM, we've then organized the remaining documents found at this site as follows:

Installing EM software and hardware required to build and run EM programs Using EM language immersion through a graduated series of portable EM examples Porting EM steps required for (re-)targeting EM to a specific HW/SW environment Advancing EM deep-dives into specific facets of the EM platform Click here to see more (less) details

We'll often insert additional commentary on the material at hand in this collapsible format, providing deeper insights into some aspect of EM. While (hopefully) insightful, feel free to skip these comments at any time.

So follow me, and let the journey begin\u2009....

"},{"location":"discuss/","title":"General comments and specific issues","text":"

In my humble opinion\u2009...

Created for the benefit of the broader embedded software community, we value your general feedback \u2013 comments, questions, ideas \u2013 about The EM Programming Language as presented throughout these documents.

To add your thoughts about EM, use the discussion forum in our em-foundation/em-sdk GitHub repository.\u00a0 You can join here\u2009, if you don't already have a GitHub account.

Just keep in mind \u2013 nothing has been decided, and everything still matters.

If you've downloaded the EM SDK and have begun coding, you can report any specific issues with the software in the same em-foundation/em-sdk repository.

"},{"location":"edu/","title":"Academia \u2013 say \"hello world\" to EM","text":"

The EM software platform comprises a novel programming language and runtime which targets resource-constrained MCUs. Originally developed in 2010, EM has evolved over the past decade through a series of commercial deployments in low-power, low-cost wireless IoT applications. To encourage broader adoption of this technology, The EM Foundation (a non-profit formed in 2023) now makes the language and its runtime openly\u2009/\u2009freely available.

While EM leverages modern software constructs like interface inheritance and component composition, novel optimization techniques employed by the underlying language translator enable EM programs to invariably outperform their hand-crafted C counterparts in terms of time and (especially) space.

Often targeting MCUs with \u2264\u200932\u2009K of memory, real-world applications \u2013 including a BLE wireless stack \u2013 can comfortably fit within these constraints.\u00a0 A 5X\u2009-\u200910X size reduction in typical embedded applications can also drive comparable savings in energy consumption as well as overall system cost.

EM \u2013 a higher-level programming language AND a higher-level of program performance

"},{"location":"edu/#conceived-in-the-university","title":"Conceived in the university","text":"

Before addressing some opportunities for academic collaboration, you should make a quick pass through Introducing EM to understand a little more about the language and its run\u00adtime. The Tiny code \u2192 Tiny chips subsection already takes us to some fertile grounds for future investigation; EM's initial engagement with the RISC-V community should also spark interest within university environments.(1)

  1. This presentation from the RISC-V Europe Summit contains further details.

While you can certainly skip the technical overivew of the language and its runtime for now, we strongly encourage you to read The history of EM subsection \u2013 and do note the seminal role played by UC Santa Barbara in the birthing and early development of EM.\u2009 In retrospect, EM would not exist today without a nuturing university environment.

"},{"location":"edu/#managing-open-source-projects","title":"Managing open-source projects","text":"

With an abundance of open-source software ranging from host tooling to target drivers (plus open-source hardware ranging from Arduino boards to RISC-V MCUs), CS/CE university programs should (in our humble opinion) arm their students with knowledge of open-source best practices \u2013 enabling them to not only participate in established projects, but also to create their own open-source initiatives which they could lead and manage.

Given that the transition of the EM technology into the open-source domain has only just begun, \"ground-floor\" opportunities await enterprising CS/CE departments motivated to assume a leadership role in the process. Said another way, The EM Foundation seeks help from universities to support its mission \u2013 promoting, sustaining, and evolving the EM programming language and runtime for use by the broader embedded systems community.

"},{"location":"edu/#areas-for-technical-contribution","title":"Areas for technical contribution","text":"

From an academic perspective, the depth\u2009/\u2009duration of potential technical contributions to EM can range from (say) a single-semester undergraduate project to multi-year graduate-level research culminating in a thesis.\u2009 Some areas of mutual interest might include:

Overall management of EM repositories housed at GitHub \u2013 coordinate the transition of existing (private) sources to public repos; introduce processes defined by open-source maturity models.

Evolution of the (command-line) EM translator plus its companion VS Code extension \u2013 relatively stable, quite compact (~12\u2009K lines of TypeScript), but with many opportunities for adding new features.

Perpetual expansion of the EM language runtime \u2013 ports to different MCUs, device drivers for sensors\u2009/\u2009controllers, wired\u2009/\u2009wireless communication stacks, machine-learning algorithms, etc.

New MCU architectures tailored for EM \u2013 take on the Tiny code \u2192 Tiny chips challenge; leverage RISC-V IP targeting FPGAs for proof-of-concept; add application-specific CPU instructions, etc.

"},{"location":"edu/#call-to-action-contact-us","title":"Call to action \u2013 contact us","text":"

If EM appears to align with the interests of your department, don't hesitate to message The EM Foundation on Linkedin with any questions you may have.

In the interim, continue to explore the material at docs.openem.org as well as read our weekly posts at blog.openem.org.

And if you really feel motivated, consider visiting Installing EM and actually downloading the EM SDK \u2013 though perhaps you'll leave this task as an \"exercise for the student\"\u2009.

"},{"location":"install/","title":"Getting started with EM","text":"

Using the EM language and its runtime requires a cross-development environment, in which hosted tooling will build\u2009/\u2009load executable EM programs onto target hardware. For the host, you'll use a PC running Windows, Linux, or MacOS(1); for the target, you can choose any MCU board for which an em$distro package already exists.

  1. MacOS support coming in 1Q24

Before turning to the EM SDK (described next), you should first install\u2009/\u2009upgrade the following tooling environments on your host PC:

Node.js version 16.3.0 or later execute node --version to verify VS Code version 1.80.0 or later execute code --version to verify Windows

If you don't already have a recent version of the Git Bash shell, you should also install Git for Windows.\u00a0 To verify your setup, ensure that the node and code commands from the previous table operate correctly under Git Bash.

Do not proceed forward if these verification checks should fail\u2009!!!

"},{"location":"install/#software-development-kit","title":"Software development kit","text":"

The EM SDK comprises two distinct components:

\u2003a VS Code extension named EM Builder with which you'll interact directly; and

\u2003a special \u00abEM-SDK\u00bb folder automatically managed by , which you can largely ignore.

Under the \u00abEM-SDK\u00bb folder you'll find a sub-folder named tools, which will contain C/C++ compilers as well as emulation utilities \u2013 all used internally by EM to build\u2009/\u2009load executable target programs.\u00a0 Already found in a well-known place on your PC(1), EM requires no further action on your part to setup these tools.

  1. \u00abEM-SDK\u00bb\u00a0=\u2002~/em-sdk
Additional artifacts

Looking inside your \u00abEM-SDK\u00bb folder, you'll also find some package*.json files as well as a node_modules sub-folder \u2013 characteristic of an npm package.\u00a0 Unless instructed otherwise, please leave these (and any other\u2009!!\u2009) artifacts housed in \u00abEM-SDK\u00bb undisturbed.

Unless instructed otherwise, do NOT disturb the contents of your \u2009\u00abEM-SDK\u00bb\u2009 folder\u2009!!!

"},{"location":"install/#target-mcu-hardware","title":"Target MCU hardware","text":"

The EM SDK will contain all of the tools required to build\u2009/\u2009load EM programs targeting any of the following boards; you won't need to download any additional, vendor-specific software.\u00a0 While we encourage you to purchase one (or more) of these boards, you can still learn a great deal about EM without target hardware \u2013 by taking the **FAST-TRACK** option.

LP-EM-CC2340R5Board #2Board #3**\u2009FAST-TRACK\u2009**

The Texas Instruments CC2340R5 wireless MCU features an Arm Cortex-M0+ CPU together with a familiar suite of peripherals \u2013 including a generic 2.4\u2009GHz radio with BLE 5.x support. Texas Instruments also offers an inexpensive LP-EM-CC2340R5 evaluation board in their familiar LaunchPad format \u2013 available from TI as well as their distributors.

You should also purchase this emulator board from TI \u2013 unless you already own a \"classic\" TI LaunchPad with on-board XDS110 support. In that case, you can easily connect this legacy LP to your new LP-EM-CC2340R5 board using a cable supplied by TI. If you haven't used an XDS110 before, run the one_time_setup script found in \u00abEM-SDK\u00bb/tools/ti-uniflash.

The ti.cc23xx distro supports the following Setups for the EM-SDK tools:

ti.cc23xx/gcc GCC 10.3, optimized for space ti.cc23xx/gcc_sram GCC 10.3, optimized for space, code\u2009+\u2009consts in SRAM ti.cc23xx/segger CLANG\u2009/\u2009LLVM 14.0, optimized for space ti.cc23xx/segger_sram CLANG\u2009/\u2009LLVM 14.0, optimized for space, code\u2009+\u2009consts in SRAM ti.cc23xx/default == ti.cc23xx/segger

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

Nothing to buy, of course\u2009!!!\u00a0 You can still build executable programs using any em$distro package within the EM SDK; you just can't load these programs onto target hardware.

Familiarize yourself, however, with the Setups available for one (or more) of the other hardware tracks enumerated above.

As we pivot to installing EM Builder, we'll soon illustrate how to select one of the Setups associated with the distros supporting these hardware options.

Which MCU board(s) would you want to see EM support\u2009???

"},{"location":"install/#em-builder-extension","title":"EM Builder extension","text":"

At this stage, we can launch VS Code and install its EM Builder extension. To begin, first create an empty folder anywhere on your PC (outside of \u00abEM-SDK\u00bb); this folder will serve as your initial VS Code workspace.

Next, enter the command code workspace to launch VS Code (where workspace represents a path to the folder created above).\u00a0 Unless you've already installed EM Builder, you'll see something like the default Welcome layout shown within the following screen capture:

Importing EM Profile

Importing EM Profile

The installation process actually begins by importing a VS Code profile named EM, which will configure a variety of user-settings as well as download the latest (stable) version of the EM Builder extension and its dependencies. To illustrate the process, watch the Importing EM Profile animation above by clicking the button atop this screen capture.

As seen in the animation, you'll use a special URL generated by VS Code to fetch the EM profile from the cloud.\u00a0 When ready, copy this URL to your clipboard and follow the same steps [\u2009Profiles\u2009>\u2009Import Profiles...\u2009] within your own installation of VS Code \u2013 pasting this URL into the input box.

https://vscode.dev/profile/github/d42fc7e6ff05708f910babc909fce416\n

If necessary, you can rewind the animation by clicking the button whenever it appears atop the screen capture.\u00a0 Hint \u2013 once playing, you should click on the animation itself to enlarge the view.

With the EM profile in place, we'll now activate the EM Builder extension for the first time as illustrated in the following animation:

Activating EM Builder

Activating EM Builder

The [\u2009Command Palette\u2009>\u2009Reload Window\u2009] sequence effectively restarts VS Code which in turn will activate EM Builder.\u2009 Always checking the status of the \u00abEM-SDK\u00bb folder, the extension will prompt you to install the EM SDK components whenever absent or outdated.(1)

  1. Things will go faster the next time you'll launch VS Code.

The EM Builder extension also requires that you select one of the Setups supported by your target MCU hardware, as the following animation will illustrate:

Selecting EM Setups

Selecting EM Setups

You should select a \"default\" configuration when the EM Setup dropdown appears \u2013 even if you've chosen the **\u2009FAST-TRACK\u2009** option for your target MCU hardware. Note that this process implicitly binds a default target board associated with your selection.

If you do plan to connect a target board, you'll also need to assign an appropriate value to the ConsolePort parameter found in the workspace local.properties file as follows:

Setting ConsolePort

Finding the actual value for the ConsolePort parameter depends, of course, on utilities specific to your PC's operating system as well as some help from your board's documentation.

In summary:

\u2003enter code workspace from the shell to launch VS Code \u2003execute the \u2009Profiles\u2009>\u2009Import Profiles...\u2009 command sequence \u2003paste the special URL given above into the input box \u2003select Create Profile and then Create when prompted \u2003execute the Developer: Reload Window command \u2003select Install... if prompted to install EM SDK components \u2003select Select... if prompted to bind EM Setups \u2003choose a \"default\" configuration from the EM Setup dropdown \u2003update the ConsolePort parameter in local.properties as appropriate"},{"location":"install/#ready-set-go","title":"Ready, Set, Go\u00a0!!!","text":"

With everything in place, the time has come to start Using EM\u2009.Happy coding\u2009!!! \u2002

"},{"location":"advancing/","title":"Deep-dive into different facets of EM","text":"

This document comprises a collection of independent articles focusing on different facets of the EM language and runtime. So pick a topic of interest and then dive right in\u2009!!!

Command-line interface Managing EM from within the shell CoreMark Reimagined Transforming legacy C code into EM EM\u2022Mark Results Standard benchmarks for EM Energy Consumption Optimizing power over time Language Syntax Navigating EM syntax diagrams

What other aspects of EM should we tackle next\u2009???

"},{"location":"advancing/cli/","title":"Managing EM from within the shell","text":"

Under Construction \u2014 estimated completion in 1Q24 \u2009

"},{"location":"advancing/coremark/","title":"Transforming legacy C code into EM","text":"

CoreMark\u00ae has emerged as the premier industry benchmark for measuring CPU performance within embedded systems. Managed through EEMBC\u2009, virtually every MCU vendor has certified and published CoreMark scores for a broad portfolio of their processors. Running the benchmark code also serves as a \"typical workload\" used when characterizing active power consumption [\u2009\u03bcW\u2009/\u2009Mhz\u2009] of a particular MCU.

The workload introduced by CoreMark encompasses four algorithms reflecting the variety of software functions often implemented within embedded application programs:

list processing find and remove elements, generalized sorting matrix manipulation add and multiply by a scalar, vector, or matrix state machine scan a string for a variety of numeric formats cyclic redundancy check checksum over a sequence of 16\u2009/\u200932-bit values

Besides adding to the workload, CoreMark uses algorithm to validate the final results of running the benchmark program \u2013 comparing a checksum over the list elements used in algorithm against an expected value. CoreMark also checksums the matrix data produced by algorithm as well as the state machine transitions encountered by algorithm .

You'll find the CoreMark sources on GitHub, together with instructions for building\u2009/\u2009running the benchmark program. To ensure the integrity of the benchmark, you cannot modify any of its (portable) C source files \u2013 with the exception of core_portme.[ch], used to adapt CoreMark to a particular hardware platform.

Needless to say, your choice of C compiler along with specific options for controlling program optimization remain on the table. While primarily intended for comparing different MCUs, CoreMark also provides a known codebase useful for \"apples-to-apples\" comparisons between different compilers [GCC, IAR, Keil, LLVM] targeting the same MCU.

CoreMark \u2013 a \"typical\" C program in more ways than one

We sense that very few software practitioners have actually studied the CoreMark source files themselves. As long as \"someone else\" can actually port\u2009/\u2009build\u2009/\u2009run the benchmark on the MCU of interest, good enough\u2009!!

In our humble opinion, the CoreMark sources would not serve as the best textbook example of well-crafted C code:\u00a0 insufficent separation of concerns, excessive coupling among compilation units, plus other deficiencies.

Said another way, CoreMark typifies the design\u2009/\u2009implementation of much of the legacy embedded C code we've encountered for decades within industry and academia alike.\u00a0 But therein lies an opportunity to showcase EM.

"},{"location":"advancing/coremark/#coremark-emmark","title":"CoreMark \u21d2 EM\u2022Mark","text":"

In reality, none of the official CoreMark sources (written in C) will survive their transformation into EM\u2022Mark \u2013 a new codebase (re-)written entirely in EM.\u2009 At the same time, applying the same CoreMark algorithms to the same input data must yield the same results in EM.

The input data used by EM\u2022Mark (like CoreMark) ultimately derives from a handful of seed\u2009 variables, statically-initialized with prescribed values.\u2009 Declared volatile in EM as well as C, the integrity of the benchmark requires that the underlying compiler cannot know the initial values of these seed variables and potentially perform overly-aggressive code optimizations.

At the same time, the CoreMark sources do make use of C preprocessor #define directives to efficiently propogate constants and small (inline) functions during compilation.\u2009 EM\u2022Mark not only achieves the same effect automatically via whole-program optimization, but also leverages the full power of EM meta-programming to initialize internal data structures at build-time \u2013 resulting in a far-more compact program image at run-time.

If necessary, review the material on program configuration and compilation to fully appreciate the opportunities that EM affords for build-time optimization.

"},{"location":"advancing/coremark/#high-level-design","title":"High-level design","text":"

The EM\u2022Mark sources (found in the em.coremark package within the em.bench bundle) consist of ten EM modules and two EM interfaces, organized as follows:

EM\u2022Mark Design Hierarchy

The ActiveRunnerP and SleepyRunnerP programs on top of this hierarchy both execute the same core benchmark algorithms, albeit in two very different contexts:

ActiveRunnerP performs multiple\u2009 benchmark iterations, much like the legacy CoreMark program

SleepyRunnerP performs a single\u2009 benchmark iteration, awakening every second from deep-sleep

The CoreBench module (imported by both of these programs) coordinates both configuration as well as execution of the list processing, matrix manipulation, and state machine algorithms; we'll have more to say about its implementation in a little while.

To capture behavioral commonality between CoreBench and the algorithm modules it uses internally [\u2009ListBench, MatrixBench, StateBench\u2009], our EM\u2022Mark design introduces the abstract em.coremark/BenchAlgI interface:

em.coremark/BenchAlgI.em
package em.coremark\n\nimport Utils\n\ninterface BenchAlgI\n\n    config memSize: uint16\n\n    function dump()\n    function kind(): Utils.Kind\n    function print()\n    function run(arg: uarg_t = 0): Utils.sum_t\n    function setup()\n\nend\n

Of the handful of functions specified by this interface, two of these play a central role in the implementation of each benchmark algorithm:

BenchAlgI.setup, which initializes the algorithm's input data using volatile seed variables

BenchAlgI.run, which executes one pass of the benchmark algorithm and returns a CRC value

Taking a quick peek inside CoreBench, you'll notice how this module's implementation of the BenchI interface simply delegates to the other algorithm modules \u2013 which in turn implement the same interface:

em.coremark/CoreBench.em [exc]
def em$construct()\n    Utils.bindSeedH(1, 0x0)\n    Utils.bindSeedH(2, 0x0)\n    Utils.bindSeedH(3, 0x66)\nend\n\ndef dump()\n    ListBench.dump()\n    MatrixBench.dump()\n    StateBench.dump()\nend\n\ndef kind()\n    return Utils.Kind.FINAL\nend\n\ndef print()\n    ListBench.print()\n    MatrixBench.print()\n    StateBench.print()\nend\n\ndef run(arg)\n    auto crc = ListBench.run(1)\n    Utils.setCrc(Utils.Kind.FINAL, Crc.add16(<int16>crc, Utils.getCrc(Utils.Kind.FINAL)))\n    crc = ListBench.run(-1)\n    Utils.setCrc(Utils.Kind.FINAL, Crc.add16(<int16>crc, Utils.getCrc(Utils.Kind.FINAL)))\n    Utils.bindCrc(Utils.Kind.LIST, Utils.getCrc(Utils.Kind.FINAL))\n    return Utils.getCrc(Utils.Kind.FINAL)\nend\n\ndef setup()\n    ListBench.setup()\n    MatrixBench.setup()\n    StateBench.setup()\nend\n

CoreBench also uses public get\u2009/\u2009set functions provided by the Utils module to fetch\u2009/\u2009store designated CRC and seed values.

more code ahead \u2013 free free to scroll down to the Summary

Each of the benchmark algorithms will call the Crc.add16 or Crc.addU32 functions to fold a new data value into a particular checksum. Looking at the implementation of the Crc module, both of these function definitions ultimately call Crc.update \u2013 a private function that effectively mimics the crcu8 routine found in the legacy CoreMark source code:

core_util.c
ee_u16\ncrcu8(ee_u8 data, ee_u16 crc)\n{\n    ee_u8 i = 0, x16 = 0, carry = 0;\n\n    for (i = 0; i < 8; i++)\n    {\n        x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1));\n        data >>= 1;\n\n        if (x16 == 1)\n        {\n            crc ^= 0x4002;\n            carry = 1;\n        }\n        else\n            carry = 0;\n        crc >>= 1;\n        if (carry)\n            crc |= 0x8000;\n        else\n            crc &= 0x7fff;\n    }\n    return crc;\n}\n

Finally, CoreBench defines a pair of config params [\u2009TOTAL_DATA_SIZE, NUM_ALGS\u2009] used to bind the BenchAlgI.memSize parameter associated with the other algorithms; refer to CoreBench.em$configure defined here for further details.\u2009 Initialized to values tracking the legacy CoreMark code, CoreBench assigns \u230a2000/3\u230b\u2009\u2261\u2009666 bytes per algorithm.(1)

  1. We'll have more to say about CoreBench.em$configure after we explore the three benchmark algorithms in more detail.
"},{"location":"advancing/coremark/#matrix-manipulation","title":"Matrix manipulation","text":"

Pivoting to the simplest of the three benchmark algorithms administered by CoreBench, the MatrixBench module implements each (public) function specified by the BenchAlgI interface; and most of the MatrixBench private functions defined inside the module [\u2009addVal, mulVec, clip, etc\u2009] correspond to legacy C functions\u2009/\u2009macros found in core_matrix.c\u2009.

Internally, MatrixBench operates upon three matrices [\u2009matA, matB, matC\u2009] dimensioned at build-time by the module's em$construct function \u2013 which uses the BenchI.memSize parameter (bound previously in CoreBench.em$configure) when calculating a value for dimN:

em.coremark/MatrixBench.em [exc]
module MatrixBench: BenchAlgI\n\nprivate:\n\n    type matdat_t: int16\n    type matres_t: int32\n\n    config dimN: uint8\n\n    var matA: matdat_t[]\n    var matB: matdat_t[]\n    var matC: matres_t[]\n
em.coremark/MatrixBench.em [exc]
def em$construct()\n    auto i = 0\n    auto j = 0\n    while j < memSize\n        i += 1\n        j = i * i * 2 * 4\n    end\n    dimN = i - 1\n    matA.length = matB.length = matC.length = dimN * dimN\nend\n

The MatrixBench.setup function initializes \"input\" matrices [\u2009matA, matB\u2009] at run-time, using values derived from two of the volatile seed variables prescribed by legacy CoreMark:

em.coremark/MatrixBench.em [exc]
def setup()\n    auto s32 = <uint32>Utils.getSeed(1) | (<uint32>Utils.getSeed(2) << 16)\n    auto sd = <matdat_t>s32\n    sd = 1 if sd == 0\n    auto order = <matdat_t>1\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            sd = <int16>((order * sd) % 65536)\n            auto val = <matdat_t>(sd + order)\n            val = clip(val, false)\n            matB[i * dimN + j] = val\n            val += order\n            val = clip(val, true)\n            matA[i * dimN + j] = val\n            order += 1\n        end\n    end\nend\n

MatrixBench.run finally executes the benchmark algorithm itself \u2013 calling a sequence of private matrix manipulation functions and then returning a checksum that captures intermediate results of these operations:

em.coremark/MatrixBench.em [exc]
def run(arg)\n    auto crc = <Crc.sum_t>0\n    auto val = <matdat_t>arg\n    auto clipval = enlarge(val)\n    #\n    addVal(val)\n    mulVal(val)\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    mulVec()\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    mulMat()\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    mulMatBix()\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    addVal(-val)\n    return Crc.add16(<int16>crc, Utils.getCrc(Utils.Kind.FINAL))\nend\n

Once again, the [EM] implementations of private functions like addVal and mulMat track their [C] counterparts found in the CoreMark core_matrix.c source file.

"},{"location":"advancing/coremark/#state-machine","title":"State machine","text":"

The StateBench module \u2013 which also conforms to the BenchAlgI interface \u2013 scans an internal array [\u2009memBuf\u2009] for text matching a variety of numeric formats.\u2009 Similar to what we've seen in MatrixBench, the build-time em$construct function sizes memBuf as well as initializes some private config parameters used as run-time constants:

em.coremark/StateBench.em [exc]
    config intPat: string[4] = [\n        \"5012\", \"1234\", \"-874\", \"+122\"\n    ]\n    config fltPat: string[4] = [\n        \"35.54400\", \".1234500\", \"-110.700\", \"+0.64400\"\n    ]\n    config sciPat: string[4] = [\n        \"5.500e+3\", \"-.123e-2\", \"-87e+832\", \"+0.6e-12\"\n    ]\n    config errPat: string[4] = [\n        \"T0.3e-1F\", \"-T.T++Tq\", \"1T3.4e4z\", \"34.0e-T^\"\n    ]\n\n    config intPatLen: uint16\n    config fltPatLen: uint16\n    config sciPatLen: uint16\n    config errPatLen: uint16\n\n    var memBuf: char[]\n
em.coremark/StateBench.em [exc]
def em$construct()\n    memBuf.length = memSize\n    intPatLen = intPat[0].length\n    fltPatLen = fltPat[0].length\n    sciPatLen = sciPat[0].length\n    errPatLen = errPat[0].length\nend\n

The StateBench.setup function uses the xxxPat and xxxPatLen config parameters in combination with a local seed variable to initializing the memBuf characters at run-time:

em.coremark/StateBench.em [exc]
def setup()\n    auto seed = Utils.getSeed(1)\n    auto p = &memBuf[0]\n    auto total = 0\n    auto pat = \"\"\n    auto plen = 0\n    while (total + plen + 1) < (memSize - 1)\n        if plen\n            for auto i = 0; i < plen; i++\n                *p++ = pat[i]\n            end\n            *p++ = ','\n            total += plen + 1\n        end\n        switch ++seed & 0x7\n        case 0\n        case 1\n        case 2\n            pat  = intPat[(seed >> 3) & 0x3]\n            plen = intPatLen\n            break\n        case 3\n        case 4\n            pat  = fltPat[(seed >> 3) & 0x3]\n            plen = fltPatLen\n            break\n        case 5\n        case 6\n            pat  = sciPat[(seed >> 3) & 0x3]\n            plen = sciPatLen\n            break\n        case 7\n            pat  = errPat[(seed >> 3) & 0x3]\n            plen = errPatLen\n            break\n        end\n    end\nend\n

Details aside, StateBench.run calls a private scan function which in turn drives the algorithm's state machine; run also calls a private scramble function to \"corrupt\" memBuf contents ahead of the next scanning cycle:

em.coremark/StateBench.em [exc]
def run(arg)\n    arg = 0x22 if arg < 0x22\n    var finalCnt: uint32[NUM_STATES]\n    var transCnt: uint32[NUM_STATES]\n    for auto i = 0; i < NUM_STATES; i++\n        finalCnt[i] = transCnt[i] = 0\n    end\n    scan(finalCnt, transCnt)\n    scramble(Utils.getSeed(1), arg)\n    scan(finalCnt, transCnt)\n    scramble(Utils.getSeed(2), arg)\n    auto crc = Utils.getCrc(Utils.Kind.FINAL)\n    for auto i = 0; i < NUM_STATES; i++\n        crc = Crc.addU32(finalCnt[i], crc)\n        crc = Crc.addU32(transCnt[i], crc)\n    end\n    return crc\nend\n\ndef scan(finalCnt, transCnt)\n    for auto str = &memBuf[0]; *str;\n        auto state = nextState(&str, transCnt)\n        finalCnt[ord(state)] += 1\n    end\nend\n\ndef scramble(seed, step)\n    for auto str = &memBuf[0]; str < &memBuf[memSize]; str += <uint16>step\n        *str ^= <uint8>seed if *str != ','\n    end\nend\n

The crc returned by StateBench.run effectively summarizes the number of transitory and finals states encountered when scanning.

even more\u2009 code ahead \u2013 free free to scroll down to the Summary

"},{"location":"advancing/coremark/#list-processing","title":"List processing","text":"

Unlike its peer benchmark algorithms, the ListBench module introduces some new design elements into the EM\u2022Mark hierarchy depicted earlier:

the ComparatorI abstraction, used by ListBench to generalize its internal implementation of list sorting through a function-valued parameter that compares element values

the ValComparator module, an implementation of ComparatorI which invokes the other\u2009 benchmark algorithms (through a proxy) in a data-dependent fashion

The ComparatorI interface names just a single function [\u2009compare\u2009]\u2009; the ListBench module in turn specifies the signature of this function through a public type [\u2009Comparator\u2009]\u2009:\u2009(1)

  1. a design-pattern similar to a Java @FunctionalInterface annotation or a C# delegate object
em.coremark/ComparatorI.em
package em.coremark\n\nimport ListBench\n\ninterface ComparatorI\n\n    function compare: ListBench.Comparator\n\nend\n
em.coremark/ListBench.em [exc]
module ListBench: BenchAlgI\n\n    type Data: struct\n        val: int16\n        idx: int16\n    end\n\n    type Comparator: function(a: Data&, b: Data&): int32\n\n    config idxCompare: Comparator\n    config valCompare: Comparator\n

CoreBench.em$configure (which we'll examine shortly) performs build-time binding of conformant Comparator functions to the pair of ListBench config parameters declared above. But first, let's look at some private declarations within the ListBench module:

em.coremark/ListBench.em [exc]
private:\n\n    type Elem: struct\n        next: Elem&\n        data: Data&\n    end\n\n    function find(list: Elem&, data: Data&): Elem&\n    function pr(list: Elem&, name: string)\n    function remove(item: Elem&): Elem&\n    function reverse(list: Elem&): Elem&\n    function sort(list: Elem&, cmp: Comparator): Elem&\n    function unremove(removed: Elem&, modified: Elem&)\n\n    config maxElems: uint16\n\n    var curHead: Elem&\n\nend\n

The Elem struct supports the conventional representation of a singly-linked list, with the ListBench private functions manipulating references to objects of this type. The maxElems parameter effectively sizes the pool of Elem objects, while the curHead variable references a particular Elem object that presently anchors the list.

Similar to the other BenchAlgI modules we've seen, ListBench cannot fully initialize its internal data structures until setup fetches a volatile seed at run-time. Nevertheless, we still can perform a sizeable amount of build-time initialization within em$construct:

em.coremark/ListBench.em [exc]
def em$construct()\n    auto itemSize = 16 + sizeof<Data>\n    maxElems = Math.round(memSize / itemSize) - 3\n    curHead = new<Elem>\n    curHead.data = new<Data>\n    auto p = curHead\n    for auto i = 0; i < maxElems - 1; i++\n        auto q = p.next = new<Elem>\n        q.data = new<Data>\n        p = q\n    end\n    p.data = new<Data>\n    p.next = null\nend\n

Like all EM config params, maxElems behaves like a var at build-time but like a const at run-time; and the value assigned by em$construct will itself depend on other build-time parameters and variables [\u2009itemSize, memSize\u2009].\u2009 In theory, initialization of maxElem could have occurred at run-time \u2013 and with EM code that looks virtually identical to what we see here.

But by executing this EM code at build-time\u2009, we'll enjoy higher-levels of performance at run-time\u2009.

Taking this facet of EM one step further,(1)em$construct \"wires up\" a singly-linked chain of newly allocated\u2009/\u2009initialized Elem objects anchored by the curHead variable \u2013 a programming idiom you've learned in Data Structures 101\u2009.\u2009 Notice how each Elem.data field similarly references a newly-allocated (but uninitialized\u2009) Data object.

  1. that the EM language serves as its own meta-language

Turning now to ListBench.setup, the pseudo-random values assigned to each element's e.data.val and e.data.idx fields originate with one of the volatile seed variables prescribed by CoreMark.\u2009 Before returning, the private sort function (which we'll visit shortly) re-orders the list elements by comparing their e.data.idx fields:

em.coremark/ListBench.em [exc]
def setup()\n    auto seed = Utils.getSeed(1)\n    auto ki = 1\n    auto kd = maxElems - 3\n    auto e = curHead\n    e.data.idx = 0\n    e.data.val = 0x8080\n    for e = e.next; e.next; e = e.next\n        auto pat = <uint16>(seed ^ kd) & 0xf\n        auto dat = (pat << 3) | (kd & 0x7)\n        e.data.val = <int16>((dat << 8) | dat)\n        kd -= 1\n        if ki < (maxElems / 5)\n            e.data.idx = ki++\n        else\n            pat = <uint16>(seed ^ ki++)\n            e.data.idx = <int16>(0x3fff & (((ki & 0x7) << 8) | pat))\n        end\n    end\n    e.data.idx = 0x7fff\n    e.data.val = 0xffff\n    curHead = sort(curHead, idxCompare)\nend\n

Finally, the following implementation of ListBench.run calls many private functions [\u2009find, remove, reverse, \u2026\u2009] to continually rearrange the list elements; ListBench.run also uses another volatile seed as well as calls sort with two different Comparator functions:

em.coremark/ListBench.em [exc]
 def run(arg)\n    auto list = curHead\n    auto finderIdx = <int16>arg\n    auto findCnt = Utils.getSeed(3)\n    auto found = <uint16>0\n    auto missed = <uint16>0\n    auto retval = <Crc.sum_t>0\n    var data: Data\n    data.idx = finderIdx\n    for auto i = 0; i < findCnt; i++\n        data.val = <int16>(i & 0xff)\n        auto elem = find(list, data)\n        list = reverse(list)\n        if elem == null\n            missed += 1\n            retval += <uint16>(list.next.data.val >> 8) & 0x1\n        else\n            found += 1\n            if <uint16>elem.data.val & 0x1\n                retval += (<uint16>(elem.data.val >> 9)) & 0x1\n            end\n            if elem.next != null\n                auto tmp = elem.next\n                elem.next = tmp.next\n                tmp.next = list.next\n                list.next = tmp\n            end\n        end\n        data.idx += 1 if data.idx >= 0\n    end\n    retval += found * 4 - missed\n    list = sort(list, valCompare) if finderIdx > 0\n    auto remover = remove(list.next)\n    auto finder = find(list, &data)\n    finder = list.next if !finder\n    while finder\n        retval = Crc.add16(list.data.val, retval)\n        finder = finder.next\n    end\n    unremove(remover, list.next)\n    list = sort(list, idxCompare)\n    for auto e = list.next; e; e = e.next\n        retval = Crc.add16(list.data.val, retval)\n    end\n    return retval\nend\n

Refer to ListBench for the definitions of the internal functions called by ListBench.run\u2009.

"},{"location":"advancing/coremark/#generalized-sorting","title":"Generalized sorting","text":"

As already illustrated, the ListBench.sort accepts a cmp argument of type Comparator \u2013 invoked when merging Data objects from a pair of sorted sub-lists: (1)

  1. The implementation seen here (including the inline comments) mimics the core_list_mergesort function found in the legacy core_list_join.c source file.
em.coremark/ListBench.em [exc]
def sort(list, cmp)\n    auto insize = <int32>1\n    var q: Elem&\n    var e: Elem&\n    for ;;\n        auto p = list\n        auto tail = list = null\n        auto nmerges = <int32>0  # count number of merges we do in this pass\n        while p\n            nmerges++  # there exists a merge to be done\n            # step `insize' places along from p\n            q = p\n            auto psize = 0\n            for auto i = 0; i < insize; i++\n                psize++\n                q = q.next\n                break if !q\n            end\n            # if q hasn't fallen off end, we have two lists to merge\n            auto qsize = insize\n            # now we have two lists; merge them\n            while psize > 0 || (qsize > 0 && q)\n                # decide whether next element of merge comes from p or q\n                if psize == 0\n                    # p is empty; e must come from q\n                    e = q\n                    q = q.next\n                    qsize--\n                elif qsize == 0 || !q\n                    # q is empty; e must come from p.\n                    e = p\n                    p = p.next\n                    psize--\n                elif cmp(p.data, q.data) <= 0\n                    # First element of p is lower (or same); e must come from p.\n                    e = p\n                    p = p.next\n                    psize--\n                else\n                    # First element of q is lower; e must come from q.\n                    e = q\n                    q = q.next\n                    qsize--\n                end\n                # add the next element to the merged list\n                if tail\n                    tail.next = e\n                else\n                    list = e\n                end\n                tail = e\n            end\n            # now p has stepped `insize' places along, and q has too\n            p = q\n        end\n        tail.next = null\n        # If we have done only one merge, we're finished\n        break if nmerges <= 1  # allow for nmerges==0, the empty list case\n        # Otherwise repeat, merging lists twice the size\n        insize *= 2\n    end\n    return list\nend\n

Looking first at the IdxComparator module, you couldn't imagine a simpler implementation of its ComparatorI.compare function \u2013 which returns the signed difference of the idx fields after scrambling the val fields:

em.coremark/IdxComparator.em [exc]
module IdxComparator: ComparatorI\n\nend\n\ndef compare(a, b)\n    a.val = <int16>((<uint16>a.val & 0xff00) | (0x00ff & <uint16>(a.val >> 8)))\n    b.val = <int16>((<uint16>b.val & 0xff00) | (0x00ff & <uint16>(b.val >> 8)))\n    return a.idx - b.idx\nend\n

Turning now to the ValComparator module, you couldn't imagine a more convoluted\u2009 implementation of ComparatorI.compare \u2013 which returns the signed difference of values computed by the private calc function:\u2009(1)

  1. the twin of calc_func found in the legacy core_list_join.c source file
em.coremark/ValComparator.em [exc]
module ValComparator: ComparatorI\n\n    proxy Bench0: BenchAlgI\n    proxy Bench1: BenchAlgI\n\nprivate:\n\n    function calc(pval: int16*): int16\n\nend\n\ndef calc(pval)\n    auto val = <uint16>*pval\n    auto optype = <uint8>(val >> 7) & 1\n    return <int16>(val & 0x007f) if optype\n    auto flag = val & 0x7\n    auto vtype = (val >> 3) & 0xf\n    vtype |= vtype << 4\n    var ret: uint16\n    switch flag\n    case 0\n        ret = Bench0.run(<uarg_t>vtype)\n        Utils.bindCrc(Bench0.kind(), ret)\n        break\n    case 1\n        ret = Bench1.run(<uarg_t>vtype)\n        Utils.bindCrc(Bench1.kind(), ret)\n        break\n    default\n        ret = val\n        break\n    end\n    auto newcrc = Crc.add16(<int16>ret, Utils.getCrc(Utils.Kind.FINAL))\n    Utils.setCrc(Utils.Kind.FINAL, Crc.add16(<int16>ret, Utils.getCrc(Utils.Kind.FINAL)))\n    ret &= 0x007f\n    *pval = <int16>((val & 0xff00) | 0x0080 | ret)   ## cache the result\n    return <int16>ret\nend\n\ndef compare(a, b)\n    auto val1 = calc(&a.val)\n    auto val2 = calc(&b.val)\n    return val1 - val2\nend\n

Besides scrambling the contents of a val field reference passed as its argument, calc actually runs other benchmark algorithms via a pair of BenchAlgI proxies [\u2009Bench0, Bench1\u2009]\u2009.

"},{"location":"advancing/coremark/#benchmark-configuration","title":"Benchmark configuration","text":"

Having visited most of the individual modules found in the EM\u2022Mark design hierarchy, let's return to CoreBench and review its build-time configuration functions:

em.coremark/CoreBench.em [exc]
module CoreBench: BenchAlgI\n\n    config TOTAL_DATA_SIZE: uint16 = 2000\n    config NUM_ALGS: uint8 = 3\n\nend\n\ndef em$configure()\n    memSize = Math.floor(TOTAL_DATA_SIZE / NUM_ALGS)\n    ListBench.idxCompare ?= IdxComparator.compare\n    ListBench.valCompare ?= ValComparator.compare\n    ListBench.memSize ?= memSize\n    MatrixBench.memSize ?= memSize\n    StateBench.memSize ?= memSize\n    ValComparator.Bench0 ?= StateBench\n    ValComparator.Bench1 ?= MatrixBench\nend\n\ndef em$construct()\n    Utils.bindSeedH(1, 0x0)\n    Utils.bindSeedH(2, 0x0)\n    Utils.bindSeedH(3, 0x66)\nend\n

In addition to calculating and assigning the memSize config parameter for each of the benchmarks, CoreBench.em$configure binds a pair of Comparator functions to ListBench as well as binds the StateBench and MatrixBench modules to the ValComparator proxies.

CoreBench.em$construct completes build-time configuration by binding a prescribed set of values to the volatile seed variables accessed at run-time by the individual benchmarks.

"},{"location":"advancing/coremark/#summary-and-next-steps","title":"Summary and next steps","text":"

Whether you've arrived here by studying (or skipping\u2009!!) all of that EM code, let's summarize some key takeaways from the exercise of transforming CoreMark into EM\u2022Mark\u2009:

The CoreMark source code \u2013 written in C with \"plenty of room for improvement\" \u2013 typifies much of the legacy software targeting resource-constrained MCUs.

The high-level design of EM\u2022Mark (depicted here) showcases many aspects of the EM langage \u2013 separation of concerns, client-supplier decoupling, build-time configuration, etc.

The ActiveRunnerP and SleepyRunnerP programs can run on any\u2009 MCU for which an em$distro package exists \u2013 making EM\u2022Mark ideal for benchmarking MCU performance.

Besides embodying a higher-level of programming, EM\u2022Mark also outperforms\u2009 legacy CoreMark.

To prove our claim about programming in EM, let's move on to the EM\u2022Mark results and allow the numbers to speak for themselves.

"},{"location":"advancing/emmark/","title":"Standard benchmarks for EM","text":"

Armed with an understanding of the CoreMark \u21d2 EM\u2022Mark transformation, you'll further appreciate the significance of the EM benchmarks presented below. While CoreMark focuses heavily on measuring CPU performance, EM\u2022Mark takes a more balanced approach that also considers program image size, active power consumption, and overall energy efficiency.

With an emphasis on maximizing execution time, CoreMark programs overwhelmingly employ the most aggressive \"optimize-for-speed\" options when compiling the benchmark sources for a particular MCU \u2013 resulting in excessively large program images.

By way of contrast, EM\u2022Mark starts from the premise that minimizing program size when targeting resource-constrained MCUs trumps other performance factors.\u00a0 Said another way, most embedded firmware developers in practice will usually choose the most aggressive \"optimize-for-size\" option when compiling their code.

LP-EM-CC2340R5Board #2Board #3

Texas Instruments reports a score of 2.1 CoreMarks\u2009/\u2009MHz for their CC2340R5 wireless MCU, which features a 48\u2009MHz Cortex-M0+ CPU.\u00a0 TI used the IAR C/C++ compiler [\u2009v9.32.2\u2009] to generate an ~18\u2009K program image, optimized for high-speed with no size constraints.

The legacy CoreMark results we'll report below used TI's LLVM-based Arm compiler [\u2009v2.1.3\u2009] with its \"optimize-for-size\" [\u2009-Oz\u2009] option. To satisfy our curiousity, building the same Core\u00adMark program using the compiler's \"optimize-for-speed\" [\u2009-Os\u2009] option yielded comparable results to those reported with IAR.\u2009(1)

  1. We'll leave adding GCC into the mix as an exercise for the reader; suffice it to say the GCC does not\u2009 win the race\u2009!!

All of the EM\u2022Mark results reported below use the ti.cc23xx distro bundle delivered with the EM-SDK plus the following pair of Setups when building program images:\u2009(1)

  1. Here, too, we'll leave experimentation with GCC-based Setups available for this target hardware as an extra-credit project.
ti.cc23xx/segger CLANG\u2009/\u2009LLVM 14.0, optimized for space, code\u2009+\u2009consts in Flash ti.cc23xx/segger_sram CLANG\u2009/\u2009LLVM 14.0, optimized for space, code\u2009+\u2009consts in SRAM

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

"},{"location":"advancing/emmark/#program-size","title":"Program size","text":"

Much like the legacy CoreMark C code, the ActiveRunnerP EM program performs multiple iterations of the benchmark algorithms and displays results when finished:

em.coremark/ActiveRunnerP.em
package em.coremark\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.mcu import Common\n\nimport CoreBench\nimport Utils\n\nmodule ActiveRunnerP\n\n    config ITERATIONS: uint16 = 10\n\nend\n\ndef em$startup()\n    CoreBench.setup()\nend\n\ndef em$run()\n    AppLed.on()\n    Common.BusyWait.wait(250000)\n    AppLed.off()\n    Common.UsCounter.start()\n    %%[d+]\n    for auto i = 0; i < ITERATIONS; i++\n        CoreBench.run()\n    end\n    %%[d-]\n    auto usecs = Common.UsCounter.stop()\n    AppLed.on()\n    Common.BusyWait.wait(250000)\n    AppLed.off()\n    printf \"usecs = %d\\n\", usecs\n    printf \"list crc = %04x\\n\", Utils.getCrc(Utils.Kind.LIST)\n    printf \"matrix crc = %04x\\n\", Utils.getCrc(Utils.Kind.MATRIX)\n    printf \"state crc = %04x\\n\", Utils.getCrc(Utils.Kind.STATE)\n    printf \"final crc = %04x\\n\", Utils.getCrc(Utils.Kind.FINAL)\nend\n

Recalling the central role played by the CoreBench module in the EM\u2022Mark high-level design, the implementation of its setup and run functions dominate the code\u2009/\u2009data sizes of the ActiveRunnerP program image:

LP-EM-CC2340R5Board #2Board #3

EM\u2022Mark Image Size

By way of comparison, the legacy CoreMark program built with TI's compiler weighs in with the following image size:

text (8798) const (3777) data (286) bss (2372)

CoreMark Image Size

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

"},{"location":"advancing/emmark/#execution-time","title":"Execution time","text":"

We've used a Saleae Logic Analyzer to capture logic traces of the legacy CoreMark and ActiveRunnerP programs executing ten iterations of the benchmark. To help measure execution time, both programs blink appLed for 250\u2009ms before\u2009/\u2009after the main benchmark loop:

LP-EM-CC2340R5Board #2Board #3

Legacy Logic Capture \u2013 Flash

ActiveRunnerP Logic Capture \u2013 Flash

ActiveRunnerP Logic Capture \u2013 SRAM

CoreMark text\u2009+\u2009const [\u2009Flash\u2009] 176\u2009ms EM\u2022Mark text\u2009+\u2009const [\u2009Flash\u2009] 151\u2009ms EM\u2022Mark text\u2009+\u2009const [\u2009SRAM\u2009] 124\u2009ms

Execution Times \u2013 Summary

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

"},{"location":"advancing/emmark/#active-power","title":"Active power","text":"

We've used a Joulescope JS220 to capture power profiles of legacy CoreMark and ActiveRunnerP executing ten iterations of the benchmark. To help measure power consumption, both programs blink appLed for 250\u2009ms before\u2009/\u2009after the main benchmark loop:

LP-EM-CC2340R5Board #2Board #3

Legacy Power Capture \u2013 Flash

ActiveRunnerP Power Capture \u2013 Flash

ActiveRunnerP Power Capture \u2013 SRAM

CoreMark text\u2009+\u2009const [\u2009Flash\u2009] 1.368\u2009mJ EM\u2022Mark text\u2009+\u2009const [\u2009Flash\u2009] 1.034\u2009mJ EM\u2022Mark text\u2009+\u2009const [\u2009SRAM\u2009] 0.634\u2009mJ

Execution Times \u2013 Summary

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

"},{"location":"advancing/emmark/#energy-efficiency","title":"Energy efficiency","text":"

Applications targeting resource-constrained (ultra-low-power) MCUs often spend most of their time in deep-sleep \u2013 awakening at rates from once-per-second down to once-per-day, and actively executing for time windows measured in just milliseconds.

The CPU-centric nature of legacy CoreMark (and hence ActiveRunnerP) doesn't necessarily reflect \"real-world\" duty-cycled applications targeting ULP MCUs, where maximizing energy efficiency becomes paramount.

ULPMark\u00ae benchmark suite

In addition to legacy CoreMark, the EEMBC organization offers ULPMark \u2013 a benchmark suite that quantifies many aspects of ultra-low-power MCUs. One of the profiles in the suite in fact measures active power consumption, using CoreMark as the workload; other profiles quantify the true energy cost of deep-sleep.

Unlike CoreMark, however, ULPMark requires a paid license to access its source code \u2014 an obstacle for purely inquisitive engineers working with ULP MCUs.\u2009 EM\u2022Mark attempts to fill this niche with a complementary pair of portable programs for benchmarking code size and execution time, as well as power consumption.

To that end, EM\u2022Mark also incorporates the SleepyRunnerP program \u2013 which executes the same underlying benchmark algorithms as ActiveRunnerP, but in a very different setting:

em.coremark/SleepyRunnerP.em
package em.coremark\n\nfrom em$distro import BoardC\n\nfrom em.utils import FiberMgr\nfrom em.utils import TickerMgr\n\nimport CoreBench\n\nmodule SleepyRunnerP\n\nprivate:\n\n    var ticker: TickerMgr.Ticker&\n\n    var count: uint8 = 10\n\n    function tickCb: TickerMgr.TickCallback\n\nend\n\ndef em$construct()\n    ticker = TickerMgr.createH()\nend\n\ndef em$startup()\n    CoreBench.setup()\nend\n\ndef em$run()\n    ticker.start(256, tickCb)\n    FiberMgr.run()\nend\n\ndef tickCb()\n    %%[d+]\n    auto crc = CoreBench.run()\n    %%[d-]\n    printf \"crc = %04x\\n\", crc\n    return if --count\n    ticker.stop()\n    halt\nend\n

Here too, SleepyRunnerP calls CoreBench.setup at startup; but instead of the \"main loop\" seen earlier in ActiveRunnerP, we now make a single\u2009 call to CoreBench.run just once-per-second. Relying only on modules found in the em.core bundle [\u2009FiberMgr, TickerMgr\u2009], SleepyRunnerP can execute on any target MCU for which an em$distro package exists.\u2009(1)

  1. Review the material in Tour 12 \u2013 cyclic tickers if necessary

The following sets of Saleae logic-captures first show SleepyRunner awakening once-per-second, and then zoom-in to view the execution time of a single active cycle:

LP-EM-CC2340R5Board #2Board #3

SleepRunnerP Logic Capture \u2013 SRAM

SleepRunnerP Logic Capture \u2013 SRAM\u2002[\u2009zoom\u2009]

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

Note that measurement M0 reflects the total active time as framed by dbgB (managed automatically by EM), whereas measurement M1 reflects the actual benchmark interval between the dbgD toggles seen earlier in SleepyRunnerP.\u2009 Also note that the latter measurement does not\u2009 include the time to format\u2009/\u2009output the \"crc = 72be\\n\" character string.

The following sets of Joulescope power-captures report the total amount of energy consumed over a one-second interval, as well as the amount of energy consumed when the SleepyRunnerP program awakens and executes a single iteration of the benchmark:

LP-EM-CC2340R5Board #2Board #3

SleepRunnerP Power Capture \u2013 SRAM

SleepRunnerP Power Capture \u2013 SRAM\u2002[\u2009zoom\u2009]

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

As expected, a single call to the CoreBench.run function takes only milliseconds to execute and yet consumes most of the energy over the one-second cycle.

"},{"location":"advancing/emmark/#general-observations","title":"General observations","text":"

Improvements in EM\u2022Mark program size and execution time compared with legacy CoreMark hopefully supports EM's claim of higher-level programming and higher-levels of performance\u2009.

Building EM\u2022Mark with the most aggressive \"optimize-for-size\" options passed to the underlying C/C++ compiler reflects the reality of targeting resource-constrained MCUs.

Placing runtime code and constants into SRAM (versus Flash) not only improves execution time but also reduces active power consumption \u2014 a corrolary of optimizing for program size.

While ActiveRunnerP maintains the same focus as legacy CoreMark (inviting side-by-side comparison), the SleepyRunnerP benchmark more accurately quantifies the energy efficiency of ULP MCUs.

"},{"location":"advancing/energy/","title":"Optimizing power over time","text":"

We put forth a rather bold proposition in Using EM:\u2003 If you can't see the problem, you can't fix it\u2009!!!\u00a0 As we toured the EM runtime, logic captures for each example program gave you an important perspective \u2013 that of program state over the course of time. Informally termed \"real-time debug\", this kind of logic trace proves invaluable to both quantify program execution time at sub-\u03bcs resolution, as well as to verify proper sequencing of program execution.

This article expands this proposition into the domain of energy consumption \u2013 by now tracing MCU power over the course of time. With many resource-constrained MCUs targeting always-on applications that run using batteries and\u2009/\u2009or harvested energy, power profiles captured by a precision energy analyzer nicely complement the \"real-time debug\" traces captured by a logic-state analyzer.

Until recently, the cost of a high-quality energy analyzer would often exceed $10,000 \u2013 far beyond most of our budgets. The recent arrival of the Joulescope JS220 precision analyzer does, however, afford order-of-magnitude relief on pricing. And the STM32 Power Shield offers an even more affordable option at <\u2009$100.

Help wanted \u2013 someone familiar with the STM32 Power Shield

For now, though, we'll stick with the Joulescope JS220 as our energy analyzer. And even if you don't own a JS220, we recommend downloading the (free) Joulescope UI software as well as the original power capture files presented throughout this article.

"},{"location":"advancing/energy/#mcu-power-modes","title":"Mcu power modes","text":"

The Tour 10 \u2013 Logic Capture seen here in Using EM introduced the terms \"lite-sleep\" and \"deep-sleep\" corresponding to distinct marks on dbgB. Recalling the Alarm1P example, this program enters the MCU's deep-sleep mode %%[b:2] after calling alarm.wakeup. But after calling AppLed.wink \u2013 which internally pauses execution for a much shorter period of time \u2013 the program instead enters the MCU's lite-sleep mode %%[b:1].

While each vendor often has their own jargon for these power modes (IDLE, PAUSE, SLEEP, STOP, SUSPEND, \u2026\u2009), we'll uniformally use the following terminology when measuring power across different MCUs supported by EM:

ACTIVE CPU core running \u2013 MCU peripherals powered on when needed by CPU PAUSE CPU core idling \u2013 MCU peripherals powered on when needed for CPU wakeup SLEEP CPU + most peripherals powered off \u2013 wakeup via special \"always-on\" peripherals HIBERNATE entire MCU powered off \u2013 CPU \"reset\" interrupt triggered by external HW devices only

As application software transitions amongst these modes, the power required to operate the MCU can range from milliwatts [ACTIVE] to microwatts [SLEEP] \u2013 and even down to nanowatts [HIBERNATE] if the application wishes to suspend execution indefintely.

To quantify these MCU power modes on your target board, we'll use the Button3P program highlighted in Tour\u200906 to obtain these readings. The Button3P Power Capture image below marks four distinct points during program execution, where we'll use the JS220 to measure the amperage instanteneously drawn by the MCU.

\u00a0 We've pressed appBut for almost 4\u2009s, with the program testing appBut every 100\u2009ms. [PAUSE]

\u00a0 Crossing the 4\u2009s threshold, the program now blinks sysLed for 40\u2009ms using a busy-wait loop. [ACTIVE]

\u00a0 The program sleeps until the next button event, even though appBut itself remains pressed. [SLEEP]

\u00a0 With the button now released, the program remains asleep while drawing even less current. [SLEEP]

LP-EM-CC2340R5Board #2Board #3

Button3P Power Capture

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

Because the JS200 samples at a relatively slow 1\u2009MHz rate (compared with the CPU clock), the capture around marker shows a series of ripples spaced 100\u2009ms apart which in fact correspond to very brief CPU wakeups from PAUSE to sample appBut; a similar train of blips occurs around markers and , which here represent an internal duty-cycled recharge of the MCU's DC/DC converter or LDO regulator.

By in large, these current measurements align with specifications found in the MCU vendor's datasheet. Do note, however, that the ACTIVE reading recorded at marker includes current drawn by the board's LED as well as the CPU itself.

"},{"location":"advancing/energy/#measuring-energy","title":"Measuring energy","text":"

While important, MCU power specifications such as [SLEEP = 1.5 \u03bcA] or even more generalized forms such as [ACTIVE = 53 \u03bcA / MHz] say absolutely nothing about the overall energy efficiency of an ultra-low-power embedded system built around this particular MCU. To gain this perspective, we must simultaneously consider the software running on the MCU and answer critical questions such as:

Once awakened, how quickly can our application software go back to sleep\u2009?!?!

By knowing the amount of time a program spends in the various MCU power modes, we can begin to quantify the overall energy efficiency of an embedded system. To illustrate the methodology we'll apply to measure energy consumption, consider the following JS220 capture of the Alarm1P example, which complements the logic capture found here:

LP-EM-CC2340R5Board #2Board #3

Alarm1P Power Capture \u2013 Flash

EM Setup:\u00a0ti.cc23xx/segger_default

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

Alarm1P spends the majority of its time in SLEEP, typical of many embedded applications.

\u00a0 Once ACTIVE, the program calls AppLed.wink and then enters PAUSE mode for 100\u2009ms;

\u00a0 awoken from PAUSE, the program calls alarm.wakeup and moves from ACTIVE to SLEEP mode.

\u00a0 The energy (in millijoules) consumed during this 100+\u2009ms SLEEP\u2009-\u2009ACTIVE\u2009-\u2009PAUSE\u2009-\u2009ACTIVE\u2009-\u2009SLEEP interval.

\u00a0 The energy (in millijoules) consumed over an arbitrary 10\u2009s interval encompassing six wakeups from SLEEP.

While time intervals and differ by a factor of 100, the total energy [\u2009mJ\u2009] consumed over these intervals differ by only a factor of \u2248\u20096. Needless to say, decreasing the number of wakeups over a given timeframe will always improve overall energy efficiency. Often, though, application requirements will dictate the frequency of these wakeup intervals \u2013 as high as once per second in many embedded systems.

"},{"location":"advancing/energy/#less-code-less-energy","title":"Less code, less energy","text":"

Introducing EM hypothesized that reducing code size could have a potentially dramatic impact on the size, power, and cost of future MCU silicon. Focusing on the dimension of power for now \u2013 and targeting legacy MCUs \u2013 we can already quantify the relationship between \"less code\" and \"less energy\".

Needless to say, minimizing the number of CPU instructions executed while ACTIVE will only reduce overall energy consumption \u2013 assuming our software still meets a given set of application requirements. With its uncanny ability to reduce code size, the EM language and runtime should benchmark quite favorably against more conventional C/C++ RTOS platforms such as Zephyr.

Help wanted \u2013 embedded programmer familiar with Zephyr

Setting aside the larger \"EM vs C/C++\" discussion for now, we'll focus instead on a very effective technique for reducing energy consumption using the same Alarm1P program executing on the same target MCU board.\u00a0 Quite simply, the EM runtime will automatically copy the\u2009.text and\u2009.const program sections into fast, on-chip SRAM at startup \u2013 rather than leaving this readonly code\u2009+\u2009data in Flash memory, where they conventionally reside.

To quantify the impact of this change, compare the following Alarm1P Power Capture with our earlier baseline \u2013 paying close attention to the total energy [\u2009mJ\u2009] consumed at intervals and in each capture.

LP-EM-CC2340R5Board #2Board #3

Alarm1P Power Capture \u2013 SRAM

EM Setup:\u00a0ti.cc23xx/segger_sram

TBD \u2013 open for suggestions

TBD \u2013 open for suggestions

While we do see a modest 10% gain in energy efficiency here, don't forget that the Alarm1P program actually fetches very few instructions \u2013 with the MCU remaining in a (lower-power) PAUSE mode for most of interval .\u00a0 Imagine, though, a duty-cycled \"sleepy\" application that executes a non-trivial mix of math functions and control code when ACTIVE:\u00a0 significant improvements during interval would also lower overall energy consumption reported at .

With modern MCUs clocked at \u2248\u200950\u2009-\u2009150\u2009MHz\u2009, these architectures invariably employ a HW cache to mitigate wait-states which would otherwise stall the CPU when fetching instructions or constants directly from slower flash memory. But SRAM has no such limitations, as this class of memory can easily sustain read rates in excess of 500\u2009MHz\u2009. The CPU hence runs at maximum efficiency, allowing the application to re-enter SLEEP that much sooner.

Assuming the program image can actually fit within SRAM \u2013 a far more scarce resource than flash \u2013 the EM distro for your target MCU board can actually disable the flash memory and its HW cache during em$startup to further reduce ambient power. Paradoxically, running the CPU at its highest possible clock rate will often decrease overall energy consumption when executing \u2013 again, by minimizing the amount of time spent in the ACTIVE mode.

In the future, we'll have additional articles under Advancing EM that benchmark more sophisticated EM applications that nevertheless can execute entirely from on-chip SRAM.\u00a0 In the meanwhile, ponder the following question:

Knowing EM applications need only a small SRAM to run, how might we architect future MCUs\u2009???

"},{"location":"advancing/syntax/","title":"Navigating EM syntax diagrams","text":"

The following \"railroad track\" diagram captures the complete syntax of EM. Automatically generated from the actual grammar used by the language translator, you can click on any of the blue rectangles (such as Unit or Decl) and navigate to the definition of these non-terminal elements; the cyan ovals represent terminal tokens scanned by an underlying lexer.

Hint

To quickly jump to the major sections of the grammar, click through the blue non-terminals within the special definitions at the top of the diagram [\u2009$start, Decl_$, Expr_$, Stmt_$, Type_$\u2009]\u2009.

Your browser will not maintain history as you navigate through this diagram. To save time scrolling back to the top of diagram, simply click on the Language Syntax link to reload the entire window.

"},{"location":"cargo/","title":"Index","text":""},{"location":"cargo/#em-bundles","title":"EM bundles","text":""},{"location":"cargo/em.bench/","title":"Index","text":""},{"location":"cargo/em.bench/#bundle-embench","title":"bundle em.bench","text":""},{"location":"cargo/em.bench/em.coremark/","title":"Index","text":""},{"location":"cargo/em.bench/em.coremark/#package-emcoremark","title":"package em.coremark","text":""},{"location":"cargo/em.bench/em.coremark/ActiveRunnerP/","title":"ActiveRunnerP","text":""},{"location":"cargo/em.bench/em.coremark/ActiveRunnerP/#unit-activerunnerp","title":"unit ActiveRunnerP","text":"em.coremark/ActiveRunnerP.em
package em.coremark\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.mcu import Common\n\nimport CoreBench\nimport Utils\n\nmodule ActiveRunnerP\n\n    config ITERATIONS: uint16 = 10\n\nend\n\ndef em$startup()\n    CoreBench.setup()\nend\n\ndef em$run()\n    AppLed.on()\n    Common.BusyWait.wait(250000)\n    AppLed.off()\n    Common.UsCounter.start()\n    %%[d+]\n    for auto i = 0; i < ITERATIONS; i++\n        CoreBench.run()\n    end\n    %%[d-]\n    auto usecs = Common.UsCounter.stop()\n    AppLed.on()\n    Common.BusyWait.wait(250000)\n    AppLed.off()\n    printf \"usecs = %d\\n\", usecs\n    printf \"list crc = %04x\\n\", Utils.getCrc(Utils.Kind.LIST)\n    printf \"matrix crc = %04x\\n\", Utils.getCrc(Utils.Kind.MATRIX)\n    printf \"state crc = %04x\\n\", Utils.getCrc(Utils.Kind.STATE)\n    printf \"final crc = %04x\\n\", Utils.getCrc(Utils.Kind.FINAL)\nend\n
"},{"location":"cargo/em.bench/em.coremark/BenchAlgI/","title":"BenchAlgI","text":""},{"location":"cargo/em.bench/em.coremark/BenchAlgI/#unit-benchalgi","title":"unit BenchAlgI","text":"em.coremark/BenchAlgI.em
package em.coremark\n\nimport Utils\n\ninterface BenchAlgI\n\n    config memSize: uint16\n\n    function dump()\n    function kind(): Utils.Kind\n    function print()\n    function run(arg: uarg_t = 0): Utils.sum_t\n    function setup()\n\nend\n
"},{"location":"cargo/em.bench/em.coremark/ComparatorI/","title":"ComparatorI","text":""},{"location":"cargo/em.bench/em.coremark/ComparatorI/#unit-comparatori","title":"unit ComparatorI","text":"em.coremark/ComparatorI.em
package em.coremark\n\nimport ListBench\n\ninterface ComparatorI\n\n    function compare: ListBench.Comparator\n\nend\n
"},{"location":"cargo/em.bench/em.coremark/CoreBench/","title":"CoreBench","text":""},{"location":"cargo/em.bench/em.coremark/CoreBench/#unit-corebench","title":"unit CoreBench","text":"em.coremark/CoreBench.em
package em.coremark\n\nfrom em.lang import Math\n\nimport BenchAlgI\nimport Crc\nimport ListBench\nimport IdxComparator\nimport MatrixBench\nimport StateBench\nimport Utils\nimport ValComparator\n\nmodule CoreBench: BenchAlgI\n\n    config TOTAL_DATA_SIZE: uint16 = 2000\n    config NUM_ALGS: uint8 = 3\n\nend\n\ndef em$configure()\n    memSize = Math.floor(TOTAL_DATA_SIZE / NUM_ALGS)\n    ListBench.idxCompare ?= IdxComparator.compare\n    ListBench.valCompare ?= ValComparator.compare\n    ListBench.memSize ?= memSize\n    MatrixBench.memSize ?= memSize\n    StateBench.memSize ?= memSize\n    ValComparator.Bench0 ?= StateBench\n    ValComparator.Bench1 ?= MatrixBench\nend\n\ndef em$construct()\n    Utils.bindSeedH(1, 0x0)\n    Utils.bindSeedH(2, 0x0)\n    Utils.bindSeedH(3, 0x66)\nend\n\ndef dump()\n    ListBench.dump()\n    MatrixBench.dump()\n    StateBench.dump()\nend\n\ndef kind()\n    return Utils.Kind.FINAL\nend\n\ndef print()\n    ListBench.print()\n    MatrixBench.print()\n    StateBench.print()\nend\n\ndef run(arg)\n    auto crc = ListBench.run(1)\n    Utils.setCrc(Utils.Kind.FINAL, Crc.add16(<int16>crc, Utils.getCrc(Utils.Kind.FINAL)))\n    crc = ListBench.run(-1)\n    Utils.setCrc(Utils.Kind.FINAL, Crc.add16(<int16>crc, Utils.getCrc(Utils.Kind.FINAL)))\n    Utils.bindCrc(Utils.Kind.LIST, Utils.getCrc(Utils.Kind.FINAL))\n    return Utils.getCrc(Utils.Kind.FINAL)\nend\n\ndef setup()\n    ListBench.setup()\n    MatrixBench.setup()\n    StateBench.setup()\nend\n
"},{"location":"cargo/em.bench/em.coremark/Crc/","title":"Crc","text":""},{"location":"cargo/em.bench/em.coremark/Crc/#unit-crc","title":"unit Crc","text":"em.coremark/Crc.em
package em.coremark\n\nimport Utils\n\nmodule Crc\n\n    type sum_t: Utils.sum_t\n\n    function add16(val: int16, crc: sum_t): sum_t\n    function addU32(val: uint32, crc: sum_t): sum_t\n\nprivate:\n\n    function update(data: uint8, crc: sum_t): sum_t\n\nend\n\ndef add16(val, crc)\n    auto v = <uint16>val\n    crc = update(<uint8>v, crc)\n    crc = update(<uint8>(v >> 8), crc)\n    return crc\nend\n\ndef addU32(val, crc)\n    crc = add16(<int16>val, crc)\n    crc = add16(<int16>(val >> 16), crc)\n    return crc\nend\n\ndef update(data, crc)\n    auto i = <uint8>0\n    auto x16 = <uint8>0\n    auto carry = <uint8>0\n    for auto i = 0; i < 8; i++\n        x16 = <uint8>((data & 1) ^ (<uint8>crc & 1))\n        data >>= 1\n        if x16 == 1\n            crc ^= 0x4002\n            carry = 1\n        else\n            carry = 0\n        end\n        crc >>= 1\n        if carry\n            crc |= 0x8000\n        else\n            crc &= 0x7fff\n        end\n    end\n    return crc\nend\n
"},{"location":"cargo/em.bench/em.coremark/IdxComparator/","title":"IdxComparator","text":""},{"location":"cargo/em.bench/em.coremark/IdxComparator/#unit-idxcomparator","title":"unit IdxComparator","text":"em.coremark/IdxComparator.em
package em.coremark\n\nimport ComparatorI\n\nmodule IdxComparator: ComparatorI\n\nend\n\ndef compare(a, b)\n    a.val = <int16>((<uint16>a.val & 0xff00) | (0x00ff & <uint16>(a.val >> 8)))\n    b.val = <int16>((<uint16>b.val & 0xff00) | (0x00ff & <uint16>(b.val >> 8)))\n    return a.idx - b.idx\nend\n
"},{"location":"cargo/em.bench/em.coremark/ListBench/","title":"ListBench","text":""},{"location":"cargo/em.bench/em.coremark/ListBench/#unit-listbench","title":"unit ListBench","text":"em.coremark/ListBench.em
package em.coremark\n\nfrom em.lang import Math\n\nimport BenchAlgI\nimport Crc\nimport Utils\n\n# patterned after core_list_join.c\n\nmodule ListBench: BenchAlgI\n\n    type Data: struct\n        val: int16\n        idx: int16\n    end\n\n    type Comparator: function(a: Data&, b: Data&): int32\n\n    config idxCompare: Comparator\n    config valCompare: Comparator\n\nprivate:\n\n    type Elem: struct\n        next: Elem&\n        data: Data&\n    end\n\n    function find(list: Elem&, data: Data&): Elem&\n    function pr(list: Elem&, name: string)\n    function remove(item: Elem&): Elem&\n    function reverse(list: Elem&): Elem&\n    function sort(list: Elem&, cmp: Comparator): Elem&\n    function unremove(removed: Elem&, modified: Elem&)\n\n    config maxElems: uint16\n\n    var curHead: Elem&\n\nend\n\ndef em$construct()\n    auto itemSize = 16 + sizeof<Data>\n    maxElems = Math.round(memSize / itemSize) - 3\n    curHead = new<Elem>\n    curHead.data = new<Data>\n    auto p = curHead\n    for auto i = 0; i < maxElems - 1; i++\n        auto q = p.next = new<Elem>\n        q.data = new<Data>\n        p = q\n    end\n    p.data = new<Data>\n    p.next = null\nend\n\ndef dump()\n    for auto e = curHead; e; e = e.next\n        %%[a+]\n        %%[>e.data.idx]\n        %%[>e.data.val]\n        %%[a-]\n    end\nend\n\ndef find(list, data)\n    auto elem = list\n    if data.idx >= 0\n        while elem && elem.data.idx != data.idx\n            elem = elem.next\n        end\n    else\n        while elem && <int16>(<uint16>elem.data.val & 0xff) != data.val\n            elem = elem.next\n        end\n    end\n    return elem\nend\n\ndef kind()\n    return Utils.Kind.LIST\nend\n\ndef pr(list, name)\n    auto sz = 0\n    printf \"%s\\n[\", name\n    for auto e = list; e; e = e.next\n        auto pre = (sz++ % 8) == 0 ? \"\\n    \" : \"\"\n        printf \"%s(%04x,%04x)\", <iarg_t>pre, e.data.idx, e.data.val\n    end\n    printf \"\\n], size = %d\\n\", sz\nend\n\ndef print()\n    pr(curHead, \"current\")\nend\n\ndef remove(item)\n    auto ret = item.next\n    auto tmp = item.data\n    item.data = ret.data\n    ret.data = tmp\n    item.next = item.next.next\n    ret.next = null\n    return ret\nend\n\ndef reverse(list)\n    auto next = <Elem&>null\n    while list\n        auto tmp = list.next\n        list.next = next\n        next = list\n        list = tmp\n    end\n    return next\nend\n\n def run(arg)\n    auto list = curHead\n    auto finderIdx = <int16>arg\n    auto findCnt = Utils.getSeed(3)\n    auto found = <uint16>0\n    auto missed = <uint16>0\n    auto retval = <Crc.sum_t>0\n    var data: Data\n    data.idx = finderIdx\n    for auto i = 0; i < findCnt; i++\n        data.val = <int16>(i & 0xff)\n        auto elem = find(list, data)\n        list = reverse(list)\n        if elem == null\n            missed += 1\n            retval += <uint16>(list.next.data.val >> 8) & 0x1\n        else\n            found += 1\n            if <uint16>elem.data.val & 0x1\n                retval += (<uint16>(elem.data.val >> 9)) & 0x1\n            end\n            if elem.next != null\n                auto tmp = elem.next\n                elem.next = tmp.next\n                tmp.next = list.next\n                list.next = tmp\n            end\n        end\n        data.idx += 1 if data.idx >= 0\n    end\n    retval += found * 4 - missed\n    list = sort(list, valCompare) if finderIdx > 0\n    auto remover = remove(list.next)\n    auto finder = find(list, &data)\n    finder = list.next if !finder\n    while finder\n        retval = Crc.add16(list.data.val, retval)\n        finder = finder.next\n    end\n    unremove(remover, list.next)\n    list = sort(list, idxCompare)\n    for auto e = list.next; e; e = e.next\n        retval = Crc.add16(list.data.val, retval)\n    end\n    return retval\nend\n\ndef setup()\n    auto seed = Utils.getSeed(1)\n    auto ki = 1\n    auto kd = maxElems - 3\n    auto e = curHead\n    e.data.idx = 0\n    e.data.val = 0x8080\n    for e = e.next; e.next; e = e.next\n        auto pat = <uint16>(seed ^ kd) & 0xf\n        auto dat = (pat << 3) | (kd & 0x7)\n        e.data.val = <int16>((dat << 8) | dat)\n        kd -= 1\n        if ki < (maxElems / 5)\n            e.data.idx = ki++\n        else\n            pat = <uint16>(seed ^ ki++)\n            e.data.idx = <int16>(0x3fff & (((ki & 0x7) << 8) | pat))\n        end\n    end\n    e.data.idx = 0x7fff\n    e.data.val = 0xffff\n    curHead = sort(curHead, idxCompare)\nend\n\ndef sort(list, cmp)\n    auto insize = <int32>1\n    var q: Elem&\n    var e: Elem&\n    for ;;\n        auto p = list\n        auto tail = list = null\n        auto nmerges = <int32>0  # count number of merges we do in this pass\n        while p\n            nmerges++  # there exists a merge to be done\n            # step `insize' places along from p\n            q = p\n            auto psize = 0\n            for auto i = 0; i < insize; i++\n                psize++\n                q = q.next\n                break if !q\n            end\n            # if q hasn't fallen off end, we have two lists to merge\n            auto qsize = insize\n            # now we have two lists; merge them\n            while psize > 0 || (qsize > 0 && q)\n                # decide whether next element of merge comes from p or q\n                if psize == 0\n                    # p is empty; e must come from q\n                    e = q\n                    q = q.next\n                    qsize--\n                elif qsize == 0 || !q\n                    # q is empty; e must come from p.\n                    e = p\n                    p = p.next\n                    psize--\n                elif cmp(p.data, q.data) <= 0\n                    # First element of p is lower (or same); e must come from p.\n                    e = p\n                    p = p.next\n                    psize--\n                else\n                    # First element of q is lower; e must come from q.\n                    e = q\n                    q = q.next\n                    qsize--\n                end\n                # add the next element to the merged list\n                if tail\n                    tail.next = e\n                else\n                    list = e\n                end\n                tail = e\n            end\n            # now p has stepped `insize' places along, and q has too\n            p = q\n        end\n        tail.next = null\n        # If we have done only one merge, we're finished\n        break if nmerges <= 1  # allow for nmerges==0, the empty list case\n        # Otherwise repeat, merging lists twice the size\n        insize *= 2\n    end\n    return list\nend\n\ndef unremove(removed, modified)\n    auto tmp = removed.data\n    removed.data = modified.data\n    modified.data = tmp\n    removed.next = modified.next\n    modified.next = removed\nend\n
"},{"location":"cargo/em.bench/em.coremark/MatrixBench/","title":"MatrixBench","text":""},{"location":"cargo/em.bench/em.coremark/MatrixBench/#unit-matrixbench","title":"unit MatrixBench","text":"em.coremark/MatrixBench.em
package em.coremark\n\nimport BenchAlgI\nimport Crc\nimport Utils\n\n# patterned after core_matrix.c\n\nmodule MatrixBench: BenchAlgI\n\nprivate:\n\n    type matdat_t: int16\n    type matres_t: int32\n\n    config dimN: uint8\n\n    var matA: matdat_t[]\n    var matB: matdat_t[]\n    var matC: matres_t[]\n\n    function addVal(val: matdat_t)\n    function mulVal(val: matdat_t)\n    function mulMat()\n    function mulMatBix()\n    function mulVec()\n    function sumDat(clipval: matdat_t): matdat_t\n\n    function bix(res: matres_t, lower: uint8, upper: uint8): matres_t\n    function clip(d: matdat_t, b: bool): matdat_t\n    function enlarge(val: matdat_t): matdat_t\n\n    function prDat(lab: string, mat: matdat_t[])\n    function prRes(lab: string)\n\nend\n\ndef em$construct()\n    auto i = 0\n    auto j = 0\n    while j < memSize\n        i += 1\n        j = i * i * 2 * 4\n    end\n    dimN = i - 1\n    matA.length = matB.length = matC.length = dimN * dimN\nend\n\ndef addVal(val)\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            matA[i * dimN + j] += val\n        end\n    end\nend\n\ndef bix(res, lower, upper)\n    auto r = <uint32>res\n    auto l = <uint32>lower\n    auto u = <uint32>upper\n    return <matres_t>((r >> l) & (~(0xffffffff << u)))\nend\n\ndef clip(d, b)\n    auto x = <uint16>d\n    return <matdat_t>(x & (b ? 0x0ff : 0x0ffff))\nend\n\ndef dump()\n    ## TODO -- implement\nend\n\ndef enlarge(val)\n    auto v = <uint16>val\n    return <matdat_t>(0xf000 | v)\nend\n\ndef kind()\n    return Utils.Kind.MATRIX\nend\n\ndef mulVal(val)\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            matC[i * dimN + j] = <matres_t>matA[i * dimN + j] * <matres_t>val\n        end\n    end\nend\n\ndef mulMat()\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            matC[i * dimN + j] = 0\n            for auto k = 0; k < dimN; k++\n                matC[i * dimN + j] += <matres_t>matA[i * dimN + k] * <matres_t>matB[k * dimN + j]\n            end\n        end\n    end\nend\n\ndef mulMatBix()\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            matC[i * dimN + j] = 0\n            for auto k = 0; k < dimN; k++\n                auto tmp = <matres_t>matA[i * dimN + k] * <matres_t>matB[k * dimN + j]\n                matC[i * dimN + j] += bix(tmp, 2, 4) * bix(tmp, 5, 7)\n            end\n        end\n    end\nend\n\ndef mulVec()\n    for auto i = 0; i < dimN; i++\n        matC[i] = 0\n        for auto j = 0; j < dimN; j++\n            matC[i] += <matres_t>matA[i * dimN + j] * <matres_t>matB[j]\n        end\n    end\nend\n\ndef print()\n    prDat(\"A\", matA)\n    prDat(\"B\", matB)\nend\n\ndef prDat(lab, mat)\n    printf \"\\n%s:\\n    \", lab\n    for auto i = 0; i < dimN; i++\n        auto sep = \"\"\n        for auto j = 0; j < dimN; j++\n            printf \"%s%d\", sep, mat[i * dimN + j]\n            sep = \",\"\n        end\n        printf \"\\n    \"\n    end\nend\n\ndef prRes(lab)\n    printf \"\\n%s:\\n    \", lab\n    for auto i = 0; i < dimN; i++\n        auto sep = \"\"\n        for auto j = 0; j < dimN; j++\n            printf \"%s%d\", sep, matC[i * dimN + j]\n            sep = \",\"\n        end\n        printf \"\\n    \"\n    end\nend\n\ndef run(arg)\n    auto crc = <Crc.sum_t>0\n    auto val = <matdat_t>arg\n    auto clipval = enlarge(val)\n    #\n    addVal(val)\n    mulVal(val)\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    mulVec()\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    mulMat()\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    mulMatBix()\n    crc = Crc.add16(sumDat(clipval), crc)\n    #\n    addVal(-val)\n    return Crc.add16(<int16>crc, Utils.getCrc(Utils.Kind.FINAL))\nend\n\ndef setup()\n    auto s32 = <uint32>Utils.getSeed(1) | (<uint32>Utils.getSeed(2) << 16)\n    auto sd = <matdat_t>s32\n    sd = 1 if sd == 0\n    auto order = <matdat_t>1\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            sd = <int16>((order * sd) % 65536)\n            auto val = <matdat_t>(sd + order)\n            val = clip(val, false)\n            matB[i * dimN + j] = val\n            val += order\n            val = clip(val, true)\n            matA[i * dimN + j] = val\n            order += 1\n        end\n    end\nend\n\ndef sumDat(clipval)\n    auto cur = <matres_t>0\n    auto prev = <matres_t>0\n    auto tmp = <matres_t>0\n    auto ret = <matdat_t>0\n    for auto i = 0; i < dimN; i++\n        for auto j = 0; j < dimN; j++\n            cur = matC[i * dimN + j]\n            tmp += cur\n            if tmp > clipval\n                ret += 10\n                tmp = 0\n            else\n                ret += (cur > prev) ? 1 : 0\n            end\n            prev = cur\n        end\n    end\n    return ret\nend\n
"},{"location":"cargo/em.bench/em.coremark/SleepyRunnerP/","title":"SleepyRunnerP","text":""},{"location":"cargo/em.bench/em.coremark/SleepyRunnerP/#unit-sleepyrunnerp","title":"unit SleepyRunnerP","text":"em.coremark/SleepyRunnerP.em
package em.coremark\n\nfrom em$distro import BoardC\n\nfrom em.utils import FiberMgr\nfrom em.utils import TickerMgr\n\nimport CoreBench\n\nmodule SleepyRunnerP\n\nprivate:\n\n    var ticker: TickerMgr.Ticker&\n\n    var count: uint8 = 10\n\n    function tickCb: TickerMgr.TickCallback\n\nend\n\ndef em$construct()\n    ticker = TickerMgr.createH()\nend\n\ndef em$startup()\n    CoreBench.setup()\nend\n\ndef em$run()\n    ticker.start(256, tickCb)\n    FiberMgr.run()\nend\n\ndef tickCb()\n    %%[d+]\n    auto crc = CoreBench.run()\n    %%[d-]\n    printf \"crc = %04x\\n\", crc\n    return if --count\n    ticker.stop()\n    halt\nend\n
"},{"location":"cargo/em.bench/em.coremark/StateBench/","title":"StateBench","text":""},{"location":"cargo/em.bench/em.coremark/StateBench/#unit-statebench","title":"unit StateBench","text":"em.coremark/StateBench.em
package em.coremark\n\nimport BenchAlgI\nimport Crc\nimport Utils\n\n# patterned after core_state.c\n\nmodule StateBench: BenchAlgI\n\nprivate:\n\n    const NUM_STATES: uint8 = 8\n\n    type StringBuf: char*\n\n    type State: enum\n        START,\n        INVALID,\n        S1,\n        S2,\n        INT,\n        FLOAT,\n        EXPONENT,\n        SCIENTIFIC,\n    end\n\n    config intPat: string[4] = [\n        \"5012\", \"1234\", \"-874\", \"+122\"\n    ]\n    config fltPat: string[4] = [\n        \"35.54400\", \".1234500\", \"-110.700\", \"+0.64400\"\n    ]\n    config sciPat: string[4] = [\n        \"5.500e+3\", \"-.123e-2\", \"-87e+832\", \"+0.6e-12\"\n    ]\n    config errPat: string[4] = [\n        \"T0.3e-1F\", \"-T.T++Tq\", \"1T3.4e4z\", \"34.0e-T^\"\n    ]\n\n    config intPatLen: uint16\n    config fltPatLen: uint16\n    config sciPatLen: uint16\n    config errPatLen: uint16\n\n    var memBuf: char[]\n\n    function isDigit(ch: char): bool\n    function nextState(pStr: StringBuf*, transCnt: uint32[]): State\n    function ord(state: State): uint8\n    function scan(finalCnt: uint32[], transCnt: uint32[])\n    function scramble(seed: Utils.seed_t, step: uarg_t)\n\nend\n\ndef em$construct()\n    memBuf.length = memSize\n    intPatLen = intPat[0].length\n    fltPatLen = fltPat[0].length\n    sciPatLen = sciPat[0].length\n    errPatLen = errPat[0].length\nend\n\ndef dump()\n    ## TODO -- implement\nend\n\ndef isDigit(ch)\n    return ch >= '0' && ch <= '9'\nend\n\ndef kind()\n    return Utils.Kind.STATE\nend\n\ndef nextState(pStr, transCnt)\n    auto str = *pStr\n    auto state = State.START\n    for ; *str && state != State.INVALID; str++\n        auto ch = *str\n        if ch == ','\n            str++\n            break\n        end\n        switch state\n        case State.START\n            if isDigit(ch)\n                state = State.INT\n            elif ch == '+' || ch == '-'\n                state = State.S1\n            elif ch == '.'\n                state = State.FLOAT\n            else\n                state = State.INVALID\n                transCnt[ord(State.INVALID)] += 1\n            end\n            transCnt[ord(State.START)] += 1\n            break\n        case State.S1\n            if isDigit(ch)\n                state = State.INT\n                transCnt[ord(State.S1)] += 1\n            elif ch == '.'\n                state = State.FLOAT\n                transCnt[ord(State.S1)] += 1\n            else\n                state = State.INVALID\n                transCnt[ord(State.S1)] += 1\n            end\n            break\n        case State.INT\n            if ch == '.'\n                state = State.FLOAT\n                transCnt[ord(State.INT)] += 1\n            elif !isDigit(ch)\n                state = State.INVALID\n                transCnt[ord(State.INT)] += 1\n            end\n            break\n        case State.FLOAT\n            if ch == 'E' || ch == 'e'\n                state = State.S2\n                transCnt[ord(State.FLOAT)] += 1\n            elif !isDigit(ch)\n                state = State.INVALID\n                transCnt[ord(State.FLOAT)] += 1\n            end\n            break\n        case State.S2\n            if ch == '+' || ch == '-'\n                state = State.EXPONENT\n                transCnt[ord(State.S2)] += 1\n            else\n                state = State.INVALID\n                transCnt[ord(State.S2)] += 1\n            end\n            break\n        case State.EXPONENT\n            if isDigit(ch)\n                state = State.SCIENTIFIC\n                transCnt[ord(State.EXPONENT)] += 1\n            else\n                state = State.INVALID\n                transCnt[ord(State.EXPONENT)] += 1\n            end\n            break\n        case State.SCIENTIFIC\n            if !isDigit(ch)\n                state = State.INVALID\n                transCnt[ord(State.INVALID)] += 1\n            end\n            break\n        end\n    end\n    *pStr = str\n    return state\nend\n\ndef ord(state)\n    return <uint8>state\nend\n\ndef print()\n    auto p = &memBuf[0]\n    auto cnt = 0\n    printf \"\\n%c\", '\"'\n    while *p\n        if (cnt++ % 8) == 0\n            printf \"\\n    \"\n        end\n        var c: char\n        while (c = *p++) != ','\n            printf \"%c\", c\n        end\n        printf \", \"\n    end\n    printf \"\\n%c, count = %d\\n\", '\"', cnt\nend\n\ndef run(arg)\n    arg = 0x22 if arg < 0x22\n    var finalCnt: uint32[NUM_STATES]\n    var transCnt: uint32[NUM_STATES]\n    for auto i = 0; i < NUM_STATES; i++\n        finalCnt[i] = transCnt[i] = 0\n    end\n    scan(finalCnt, transCnt)\n    scramble(Utils.getSeed(1), arg)\n    scan(finalCnt, transCnt)\n    scramble(Utils.getSeed(2), arg)\n    auto crc = Utils.getCrc(Utils.Kind.FINAL)\n    for auto i = 0; i < NUM_STATES; i++\n        crc = Crc.addU32(finalCnt[i], crc)\n        crc = Crc.addU32(transCnt[i], crc)\n    end\n    return crc\nend\n\ndef scan(finalCnt, transCnt)\n    for auto str = &memBuf[0]; *str;\n        auto state = nextState(&str, transCnt)\n        finalCnt[ord(state)] += 1\n    end\nend\n\ndef scramble(seed, step)\n    for auto str = &memBuf[0]; str < &memBuf[memSize]; str += <uint16>step\n        *str ^= <uint8>seed if *str != ','\n    end\nend\n\ndef setup()\n    auto seed = Utils.getSeed(1)\n    auto p = &memBuf[0]\n    auto total = 0\n    auto pat = \"\"\n    auto plen = 0\n    while (total + plen + 1) < (memSize - 1)\n        if plen\n            for auto i = 0; i < plen; i++\n                *p++ = pat[i]\n            end\n            *p++ = ','\n            total += plen + 1\n        end\n        switch ++seed & 0x7\n        case 0\n        case 1\n        case 2\n            pat  = intPat[(seed >> 3) & 0x3]\n            plen = intPatLen\n            break\n        case 3\n        case 4\n            pat  = fltPat[(seed >> 3) & 0x3]\n            plen = fltPatLen\n            break\n        case 5\n        case 6\n            pat  = sciPat[(seed >> 3) & 0x3]\n            plen = sciPatLen\n            break\n        case 7\n            pat  = errPat[(seed >> 3) & 0x3]\n            plen = errPatLen\n            break\n        end\n    end\nend\n
"},{"location":"cargo/em.bench/em.coremark/Utils/","title":"Utils","text":""},{"location":"cargo/em.bench/em.coremark/Utils/#unit-utils","title":"unit Utils","text":"em.coremark/Utils.em
package em.coremark\n\nmodule Utils\n\n    const NUM_SEEDS: uint8 = 5\n\n    type Kind: enum\n        FINAL, LIST, MATRIX, STATE, ZZZ_\n    end\n\n    type seed_t: uint16 volatile\n    type sum_t: uint16\n\n    function bindCrc(kind: Kind, crc: sum_t)\n    function getCrc(kind: Kind): sum_t\n    function setCrc(kind: Kind, crc: sum_t)\n\n    host function bindSeedH(idx: uint8, val: seed_t)\n    function getSeed(idx: uint8): seed_t\n\nprivate:\n\n    var crcTab: sum_t[]\n    var seedTab: seed_t[NUM_SEEDS]\n\nend\n\ndef em$construct()\n    crcTab.length = <uint16>Kind.ZZZ_\nend\n\ndef bindCrc(kind, crc)\n    auto p = &crcTab[<uint16>kind]\n    *p = crc if *p == 0\nend\n\ndef bindSeedH(idx, val)\n    seedTab[idx - 1] = val\nend\n\ndef getCrc(kind)\n    return crcTab[<uint16>kind]\nend\n\ndef getSeed(idx)\n    return seedTab[idx - 1]\nend\n\ndef setCrc(kind, crc)\n    crcTab[<uint16>kind] = crc\nend\n
"},{"location":"cargo/em.bench/em.coremark/ValComparator/","title":"ValComparator","text":""},{"location":"cargo/em.bench/em.coremark/ValComparator/#unit-valcomparator","title":"unit ValComparator","text":"em.coremark/ValComparator.em
package em.coremark\n\nimport BenchAlgI\nimport ComparatorI\nimport Crc\nimport Utils\n\nmodule ValComparator: ComparatorI\n\n    proxy Bench0: BenchAlgI\n    proxy Bench1: BenchAlgI\n\nprivate:\n\n    function calc(pval: int16*): int16\n\nend\n\ndef calc(pval)\n    auto val = <uint16>*pval\n    auto optype = <uint8>(val >> 7) & 1\n    return <int16>(val & 0x007f) if optype\n    auto flag = val & 0x7\n    auto vtype = (val >> 3) & 0xf\n    vtype |= vtype << 4\n    var ret: uint16\n    switch flag\n    case 0\n        ret = Bench0.run(<uarg_t>vtype)\n        Utils.bindCrc(Bench0.kind(), ret)\n        break\n    case 1\n        ret = Bench1.run(<uarg_t>vtype)\n        Utils.bindCrc(Bench1.kind(), ret)\n        break\n    default\n        ret = val\n        break\n    end\n    auto newcrc = Crc.add16(<int16>ret, Utils.getCrc(Utils.Kind.FINAL))\n    Utils.setCrc(Utils.Kind.FINAL, Crc.add16(<int16>ret, Utils.getCrc(Utils.Kind.FINAL)))\n    ret &= 0x007f\n    *pval = <int16>((val & 0xff00) | 0x0080 | ret)   ## cache the result\n    return <int16>ret\nend\n\ndef compare(a, b)\n    auto val1 = calc(&a.val)\n    auto val2 = calc(&b.val)\n    return val1 - val2\nend\n
"},{"location":"cargo/em.core/","title":"Index","text":""},{"location":"cargo/em.core/#bundle-emcore","title":"bundle em.core","text":""},{"location":"cargo/em.core/em.hal/","title":"Index","text":""},{"location":"cargo/em.core/em.hal/#package-emhal","title":"package em.hal","text":""},{"location":"cargo/em.core/em.hal/BusyWaitI/","title":"BusyWaitI","text":""},{"location":"cargo/em.core/em.hal/BusyWaitI/#unit-busywaiti","title":"unit BusyWaitI","text":"em.hal/BusyWaitI.em
package em.hal\n\ninterface BusyWaitI\n        #   ^| abstraction of a spin-loop\n    function wait(usecs: uint32)\n        #   ^| enter a spin-loop\n        #   ^| @usecs - duration in microseconds\nend\n
"},{"location":"cargo/em.core/em.hal/BusyWaitN/","title":"BusyWaitN","text":""},{"location":"cargo/em.core/em.hal/BusyWaitN/#unit-busywaitn","title":"unit BusyWaitN","text":"em.hal/BusyWaitN.em
package em.hal\n\nimport BusyWaitI\n\nmodule BusyWaitN: BusyWaitI\n    #   ^| Nil implementation of the BusyWaitI interface\nend\n\ndef wait(usecs)\nend\n
"},{"location":"cargo/em.core/em.hal/ButtonI/","title":"ButtonI","text":""},{"location":"cargo/em.core/em.hal/ButtonI/#unit-buttoni","title":"unit ButtonI","text":"em.hal/ButtonI.em
package em.hal\n\ninterface ButtonI\n        #   ^| abstraction of a pressable button\n    type OnPressedCB: function()\n        #   ^| signature of a button's callback function\n    function isPressed(): bool\n        #   ^| test whether this button is currently pressed\n    function onPressed(cb: OnPressedCB, minDurationMs: uint16 = 100, maxDurationMs: uint16 = 4000)\n        #   ^| bind a callback to this button\n        #   ^| @cb - callback function, executed when this button is pressed\n        #   ^| @minDurationMs - minimum time in millisecs before executing this button's callback\n        #   ^| @maxDurationMs - maximum time in millisecs, after which this button's callback is executed\n\nend\n
"},{"location":"cargo/em.core/em.hal/ButtonN/","title":"ButtonN","text":""},{"location":"cargo/em.core/em.hal/ButtonN/#unit-buttonn","title":"unit ButtonN","text":"em.hal/ButtonN.em
package em.hal\n\nimport ButtonI\n\nmodule ButtonN: ButtonI\n    #   ^| Nil implementation of the ButtonI interface\nend\n\ndef isPressed()\n    return false\nend\n\ndef onPressed(cb, minDurationMs, maxDurationMs)\nend\n
"},{"location":"cargo/em.core/em.hal/ConsoleUartI/","title":"ConsoleUartI","text":""},{"location":"cargo/em.core/em.hal/ConsoleUartI/#unit-consoleuarti","title":"unit ConsoleUartI","text":"em.hal/ConsoleUartI.em
package em.hal\n\ninterface ConsoleUartI \n\n    host function setBaudH(rate: uint32)\n\n    function flush()\n    function put(data: uint8)\n\nend\n
"},{"location":"cargo/em.core/em.hal/ConsoleUartN/","title":"ConsoleUartN","text":""},{"location":"cargo/em.core/em.hal/ConsoleUartN/#unit-consoleuartn","title":"unit ConsoleUartN","text":"em.hal/ConsoleUartN.em
package em.hal\n\nimport ConsoleUartI\n\nmodule ConsoleUartN: ConsoleUartI\n    #   ^| Nil implementation of the ConsoleUartI interface\nend\n\ndef setBaudH(rate)\nend\n\ndef flush()\nend\n\ndef put(data)\nend\n
"},{"location":"cargo/em.core/em.hal/CopierI/","title":"CopierI","text":""},{"location":"cargo/em.core/em.hal/CopierI/#unit-copieri","title":"unit CopierI","text":"em.hal/CopierI.em
package em.hal\n\ninterface CopierI\n\n    function exec(dst: ptr_t, src: ptr_t, cnt: uint16)\n\nend\n
"},{"location":"cargo/em.core/em.hal/FlashI/","title":"FlashI","text":""},{"location":"cargo/em.core/em.hal/FlashI/#unit-flashi","title":"unit FlashI","text":"em.hal/FlashI.em
package em.hal\n\ninterface FlashI\n\n    host function getSectorSizeH(): uint32\n    host function getWriteChunkH(): uint32\n\n    function erase(addr: addr_t, upto: addr_t = 0)\n    function write(addr: addr_t, data: ptr_t, len: uint32): addr_t\n\nend\n
"},{"location":"cargo/em.core/em.hal/FlashN/","title":"FlashN","text":""},{"location":"cargo/em.core/em.hal/FlashN/#unit-flashn","title":"unit FlashN","text":"em.hal/FlashN.em
package em.hal\n\nimport FlashI\n\nmodule FlashN: FlashI\n    #   ^| Nil implementation of the FlashI interface\nend\n\ndef getSectorSizeH()\n    return 0\nend\n\ndef getWriteChunkH()\n    return 0\nend\n\ndef erase(addr, upto)\nend\n\ndef write(addr, data, len)\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/GlobalInterruptsI/","title":"GlobalInterruptsI","text":""},{"location":"cargo/em.core/em.hal/GlobalInterruptsI/#unit-globalinterruptsi","title":"unit GlobalInterruptsI","text":"em.hal/GlobalInterruptsI.em
package em.hal\n\n#! Interface implemented by a GlobalInterrupts module for a device.\n\ninterface GlobalInterruptsI \n\n    type Key: uarg_t\n\n    #! Disables interrupts and saves state\n    function disable(): Key\n\n    #! Enables interrupts\n    function enable()\n\n    #! Restores interrupts to previous state\n    function restore(key: Key)\nend\n
"},{"location":"cargo/em.core/em.hal/GlobalInterruptsN/","title":"GlobalInterruptsN","text":""},{"location":"cargo/em.core/em.hal/GlobalInterruptsN/#unit-globalinterruptsn","title":"unit GlobalInterruptsN","text":"em.hal/GlobalInterruptsN.em
package em.hal\n\nimport GlobalInterruptsI\n\nmodule GlobalInterruptsN: GlobalInterruptsI\n    #   ^| Nil implementation of the GlobalInterruptsI interface\nend\n\ndef disable()\n    return 0\nend\n\ndef enable()\nend\n\ndef restore(key)\nend\n
"},{"location":"cargo/em.core/em.hal/GpioEdgeDetectMinI/","title":"GpioEdgeDetectMinI","text":""},{"location":"cargo/em.core/em.hal/GpioEdgeDetectMinI/#unit-gpioedgedetectmini","title":"unit GpioEdgeDetectMinI","text":"em.hal/GpioEdgeDetectMinI.em
package em.hal\n\nimport GpioI\n\ninterface GpioEdgeDetectMinI: GpioI \n        #   ^| extends the GpioI abstraction with edge-detection features\n    type Handler: function ()\n        #   ^| signature of an edge-detection function\n    host function setDetectHandlerH(h: Handler)\n        #   ^| bind a handler to this GPIO at build-time\n    function clearDetect()\n        #   ^| clear (acknowledge) any edge-detection by this GPIO\n    function disableDetect()   \n        #   ^| disable edge-detection by this GPIO\n    function enableDetect()\n        #   ^| enable edge-detection by this GPIO\n    function setDetectFallingEdge()\n        #   ^| detect high-to-low transitions by this GPIO\n    function setDetectRisingEdge()\n        #   ^| detect low-to-high transitions by this GPIO\nend\n
"},{"location":"cargo/em.core/em.hal/GpioEdgeDetectMinN/","title":"GpioEdgeDetectMinN","text":""},{"location":"cargo/em.core/em.hal/GpioEdgeDetectMinN/#unit-gpioedgedetectminn","title":"unit GpioEdgeDetectMinN","text":"em.hal/GpioEdgeDetectMinN.em
package em.hal\n\nimport GpioEdgeDetectMinI\n\nmodule GpioEdgeDetectMinN: GpioEdgeDetectMinI\n    #   ^| Nil implementation of the GpioEdgeDetectMinI interface\nend\n\ndef set()\nend\n\ndef clear()\nend\n\ndef toggle()\nend\n\ndef get()\n    return false\nend\n\ndef makeInput()\nend\n\ndef isInput()\n    return false\nend\n\ndef makeOutput()\nend\n\ndef isOutput()\n    return false\nend\n\ndef functionSelect(select)\nend\n\ndef setInternalPullup(state)\nend\n\ndef pinId()\n    return 0\nend\n\ndef reset()\nend\n\ndef enableDetect()\nend\n\ndef disableDetect()\nend\n\ndef clearDetect()\nend\n\ndef setDetectRisingEdge()\nend\n\ndef setDetectFallingEdge()\nend\n\ndef setDetectHandlerH(h)\nend\n
"},{"location":"cargo/em.core/em.hal/GpioI/","title":"GpioI","text":""},{"location":"cargo/em.core/em.hal/GpioI/#unit-gpioi","title":"unit GpioI","text":"em.hal/GpioI.em
package em.hal\n\ninterface GpioI\n        #   ^| abstraction of a GPIO pin\n    function clear()\n        #   ^| clear the value of this GPIO (low)\n    function functionSelect (select: uint8)\n        #   ^| select an alternative function of this GPIO\n    function get(): bool\n        #   ^| get the value of this GPIO\n    function isInput(): bool\n        #   ^| test if this GPIO is an input pin\n    function isOutput(): bool\n        #   ^| test if this GPIO is an output pin\n    function makeInput()\n        #   ^| make this GPIO an input pin\n    function makeOutput()\n        #   ^| make this GPIO an output pin\n    function pinId(): int16\n        #   ^| Return the pin ID of this GPIO\n    function reset()\n        #   ^| Reset this GPIO\n    function set()\n        #   ^| set the value of this GPIO (high)\n    function setInternalPullup (state: bool)\n        #   ^| enable/disable the internalpullup for this GPIO\n    function toggle()\n        #   ^| toggle the value of this GPIO\n\nend\n
"},{"location":"cargo/em.core/em.hal/GpioN/","title":"GpioN","text":""},{"location":"cargo/em.core/em.hal/GpioN/#unit-gpion","title":"unit GpioN","text":"em.hal/GpioN.em
package em.hal\n\nimport GpioI\n\nmodule GpioN: GpioI\n    #   ^| Nil implementation of the GpioI interface\nend\n\ndef set()\nend\n\ndef clear()\nend\n\ndef toggle()\nend\n\ndef get()\n    return false\nend\n\ndef makeInput()\nend\n\ndef isInput()\n    return false\nend\n\ndef makeOutput()\nend\n\ndef isOutput()\n    return false\nend\n\ndef functionSelect(select)\nend\n\ndef setInternalPullup(state)\nend\n\ndef pinId()\n    return 0\nend\n\ndef reset()\nend\n
"},{"location":"cargo/em.core/em.hal/HostUartI/","title":"HostUartI","text":""},{"location":"cargo/em.core/em.hal/HostUartI/#unit-hostuarti","title":"unit HostUartI","text":"em.hal/HostUartI.em
package em.hal\n\nimport ConsoleUartI\n\ninterface HostUartI: ConsoleUartI\n\n    type RxHandler: function(b: uint8)\n\n    function disable()\n    function enable()\n    function get(): uint8\n\n    host function setRxHandlerH(handler: RxHandler)\n\nend\n
"},{"location":"cargo/em.core/em.hal/HostUartN/","title":"HostUartN","text":""},{"location":"cargo/em.core/em.hal/HostUartN/#unit-hostuartn","title":"unit HostUartN","text":"em.hal/HostUartN.em
package em.hal\n\nimport HostUartI\n\nmodule HostUartN: HostUartI\n    #   ^| Nil implementation of the HostUartI interface\nend\n\ndef setBaudH(rate)\n    ## TODO -- implement\nend\n\ndef flush()\n    ## TODO -- implement\nend\n\ndef put(data)\n    ## TODO -- implement\nend\n\ndef disable()\n    ## TODO -- implement\nend\n\ndef enable()\n    ## TODO -- implement\nend\n\ndef get()\n    ## TODO -- implement\n    return 0\nend\n\ndef setRxHandlerH(handler)\n    ## TODO -- implement\nend\n
"},{"location":"cargo/em.core/em.hal/IdleI/","title":"IdleI","text":""},{"location":"cargo/em.core/em.hal/IdleI/#unit-idlei","title":"unit IdleI","text":"em.hal/IdleI.em
package em.hal\n\n#! Should be implemented by an Idle module\n\ninterface IdleI  \n\n    #! This function defines how the system idles\n    function exec()\n\n    #! This function is called during \"warm\" wakeups\n    function wakeup()\nend\n
"},{"location":"cargo/em.core/em.hal/IdleN/","title":"IdleN","text":""},{"location":"cargo/em.core/em.hal/IdleN/#unit-idlen","title":"unit IdleN","text":"em.hal/IdleN.em
package em.hal\n\nimport IdleI\n\nmodule IdleN: IdleI\n    #   ^| Nil implementation of the IdleI interface\nend\n\ndef exec()\nend\n\ndef wakeup()\nend\n
"},{"location":"cargo/em.core/em.hal/InterruptSourceI/","title":"InterruptSourceI","text":""},{"location":"cargo/em.core/em.hal/InterruptSourceI/#unit-interruptsourcei","title":"unit InterruptSourceI","text":"em.hal/InterruptSourceI.em
package em.hal\n\n#! Generally implemented by an Interrupt Template used to \"create\" interrupts\n\ninterface InterruptSourceI \n\n    type Handler: function()\n\n    #! Sets the handler function for a particular interrupt\n    host function setHandlerH(h: Handler)\n\n    #! Enables a particular interrupt\n    function enable()\n\n    #! Disables a particular interrupt\n    function disable()\n\n    #! Clears the interrupt flag   \n    function clear()\n\n    #! True if the interrupt is enabled\n    function isEnabled(): bool\nend\n
"},{"location":"cargo/em.core/em.hal/IntrVecI/","title":"IntrVecI","text":""},{"location":"cargo/em.core/em.hal/IntrVecI/#unit-intrveci","title":"unit IntrVecI","text":"em.hal/IntrVecI.em
package em.hal\n\ninterface IntrVecI\n\n    type ExceptionHandler: function(vecNum: uint32, retAddr: addr_t)\n\n    host function bindExceptionHandlerH(handler: ExceptionHandler)\n\nend\n
"},{"location":"cargo/em.core/em.hal/LedI/","title":"LedI","text":""},{"location":"cargo/em.core/em.hal/LedI/#unit-ledi","title":"unit LedI","text":"em.hal/LedI.em
package em.hal\n\ninterface LedI\n        #   ^| abstraction of an LED\n    function isOn(): bool\n        #   ^| test if the LED is on\n    function off()\n        #   ^| turn the LED off\n    function on()\n        #   ^| turn the LED on\n    function toggle()\n        #   ^| toggle the LED\n    function wink(msecs: uint16)\n        #   ^| turn the LED on/off\n        #   ^| @msecs duration in milliseconds\n    end\n
"},{"location":"cargo/em.core/em.hal/LedN/","title":"LedN","text":""},{"location":"cargo/em.core/em.hal/LedN/#unit-ledn","title":"unit LedN","text":"em.hal/LedN.em
package em.hal\n\nimport LedI\n\nmodule LedN: LedI\n    #   ^| Nil implementation of the LedI interface\nend\n\ndef isOn()\n    return false\nend\n\ndef on()\nend\n\ndef off()\nend\n\ndef toggle()\nend\n\ndef wink(usecs)\nend\n
"},{"location":"cargo/em.core/em.hal/McuI/","title":"McuI","text":""},{"location":"cargo/em.core/em.hal/McuI/#unit-mcui","title":"unit McuI","text":"em.hal/McuI.em
package em.hal\n\n#! Implemented by an Mcu module\n\ninterface McuI \n\n    const ADMIN_RESET: int8 = -1\n    const HOST_RESET:  int8 = -2\n    const COLD_RESET:  int8 = -3\n    const FIRST_RESET: int8 = -4\n\n    config mclkFrequency: uint32\n\n    function getResetCode(): int8\n    function getStashAddr(): ptr_t\n    function isWarm(): bool\n    function readEui48(dst: uint8*)\n\n    #! Perform startup and shutdown operations specific for a particular Mcu\n    function reset(code: int8 = 0)\n    function startup()\n    function shutdown()\nend\n
"},{"location":"cargo/em.core/em.hal/McuInfoI/","title":"McuInfoI","text":""},{"location":"cargo/em.core/em.hal/McuInfoI/#unit-mcuinfoi","title":"unit McuInfoI","text":"em.hal/McuInfoI.em
package em.hal\n\ninterface McuInfoI\n\n    function readBatMv(): uint16\n    function readTempC(): int8\n\nend\n
"},{"location":"cargo/em.core/em.hal/McuInfoN/","title":"McuInfoN","text":""},{"location":"cargo/em.core/em.hal/McuInfoN/#unit-mcuinfon","title":"unit McuInfoN","text":"em.hal/McuInfoN.em
package em.hal\n\nimport McuInfoI\n\nmodule McuInfoN: McuInfoI\n    #   ^| Nil implementation of the McuInfoI interface\nend\n\ndef readBatMv()\n    return 0\nend\n\ndef readTempC()\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/McuN/","title":"McuN","text":""},{"location":"cargo/em.core/em.hal/McuN/#unit-mcun","title":"unit McuN","text":"em.hal/McuN.em
package em.hal\n\nimport McuI\n\nmodule McuN: McuI\n\nend\n\ndef getResetCode()\n    return 0\nend\n\ndef getStashAddr()\n    return null\nend\n\ndef isWarm()\n    return false\nend\n\ndef readEui48(dst)\nend\n\ndef reset(code)\nend\n\ndef startup()\nend\n\ndef shutdown()\nend\n
"},{"location":"cargo/em.core/em.hal/MsCounterI/","title":"MsCounterI","text":""},{"location":"cargo/em.core/em.hal/MsCounterI/#unit-mscounteri","title":"unit MsCounterI","text":"em.hal/MsCounterI.em
package em.hal\n\ninterface MsCounterI\n\n    function start()\n    function stop(): uint32\n\nend\n
"},{"location":"cargo/em.core/em.hal/MsCounterN/","title":"MsCounterN","text":""},{"location":"cargo/em.core/em.hal/MsCounterN/#unit-mscountern","title":"unit MsCounterN","text":"em.hal/MsCounterN.em
package em.hal\n\nimport MsCounterI\n\nmodule MsCounterN: MsCounterI\n    #   ^| Nil implementation of the MsCounterI interface\nend\n\ndef start()\nend\n\ndef stop()\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/OneShotMilliI/","title":"OneShotMilliI","text":""},{"location":"cargo/em.core/em.hal/OneShotMilliI/#unit-oneshotmillii","title":"unit OneShotMilliI","text":"em.hal/OneShotMilliI.em
 package em.hal\n\ninterface OneShotMilliI\n        #   ^| abstraction of a one-shot timer with millisecond resolution\n    type Handler: function(arg: ptr_t)\n        #   ^| handler function signature\n    function disable()\n        #   ^| disables the timer\n    function enable(msecs: uint32, handler: Handler, arg: ptr_t = null) \n        #   ^| enables the timer to expire in msecs milliseconds\n        #   ^| @msecs - duration in millisecs before expiration\n        #   ^| @handler - handler function called upon expiration \n        #   ^| @arg - optional value passed to the handler\nend\n
"},{"location":"cargo/em.core/em.hal/OneShotMilliN/","title":"OneShotMilliN","text":""},{"location":"cargo/em.core/em.hal/OneShotMilliN/#unit-oneshotmillin","title":"unit OneShotMilliN","text":"em.hal/OneShotMilliN.em
package em.hal\n\nimport OneShotMilliI\n\nmodule OneShotMilliN: OneShotMilliI\n    #   ^| Nil implementation of the OneShotMilliI interface\nend\n\ndef disable()\nend\n\ndef enable(msecs, handler, arg)\nend\n
"},{"location":"cargo/em.core/em.hal/PollerI/","title":"PollerI","text":""},{"location":"cargo/em.core/em.hal/PollerI/#unit-polleri","title":"unit PollerI","text":"em.hal/PollerI.em
package em.hal\n\ninterface PollerI\n        #       ^| abstration of periodic polling\n    type PollFxn: function(): bool\n        #       ^| signature of a boolean-valued polling function\n    function poll(rateMs: uint16, count: uint16, fxn: PollFxn): uint16 \n        #       ^| initiates a polling sequence\n        #       ^| @rateMs - idle time in milliseconds between pollings\n        #       ^| @count - maximum number of polling attempts\n        #       ^| @fxn - the polling function itself\n        #       ^| @return - the number of polling attempts remaining (success if >0)\nend\n
"},{"location":"cargo/em.core/em.hal/PollerN/","title":"PollerN","text":""},{"location":"cargo/em.core/em.hal/PollerN/#unit-pollern","title":"unit PollerN","text":"em.hal/PollerN.em
package em.hal\n\nimport PollerI\n\nmodule PollerN: PollerI\n    #   ^| Nil implementation of the PollerI interface\nend\n\ndef poll(rateMs, count, fxn)\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/RandI/","title":"RandI","text":""},{"location":"cargo/em.core/em.hal/RandI/#unit-randi","title":"unit RandI","text":"em.hal/RandI.em
package em.hal\n\ninterface RandI\n\n    function gen(): uint32\n\nend\n
"},{"location":"cargo/em.core/em.hal/RandN/","title":"RandN","text":""},{"location":"cargo/em.core/em.hal/RandN/#unit-randn","title":"unit RandN","text":"em.hal/RandN.em
package em.hal\n\nimport RandI\n\nmodule RandN: RandI\n    #   ^| Nil implementation of the RandI interface\nend\n\ndef gen()\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/SpiMasterI/","title":"SpiMasterI","text":""},{"location":"cargo/em.core/em.hal/SpiMasterI/#unit-spimasteri","title":"unit SpiMasterI","text":"em.hal/SpiMasterI.em
package em.hal\n\ninterface SpiMasterI\n\n    function activate()\n    function deactivate()\n    function flush()\n    function get(): uint8\n    function put(data: uint8)\n\nend\n
"},{"location":"cargo/em.core/em.hal/TimeoutI/","title":"TimeoutI","text":""},{"location":"cargo/em.core/em.hal/TimeoutI/#unit-timeouti","title":"unit TimeoutI","text":"em.hal/TimeoutI.em
package em.hal\n\ninterface TimeoutI\n\n    function active(): bool\n    function cancel()\n    function set(msecs: uint32)\n\nend\n
"},{"location":"cargo/em.core/em.hal/TimeoutN/","title":"TimeoutN","text":""},{"location":"cargo/em.core/em.hal/TimeoutN/#unit-timeoutn","title":"unit TimeoutN","text":"em.hal/TimeoutN.em
package em.hal\n\nimport TimeoutI\n\nmodule TimeoutN: TimeoutI\n    #   ^| Nil implementation of the TimeoutI interface\nend\n\ndef active()\n    return false\nend\n\ndef cancel()\nend\n\ndef set(msecs)\nend\n
"},{"location":"cargo/em.core/em.hal/UptimerI/","title":"UptimerI","text":""},{"location":"cargo/em.core/em.hal/UptimerI/#unit-uptimeri","title":"unit UptimerI","text":"em.hal/UptimerI.em
package em.hal\n\ninterface UptimerI\n\n    type Time: struct\n        secs: uint32\n        subs: uint32\n        ticks: uint32\n    end\n\n    function calibrate(secs256: uint32, ticks: uint32): uint16\n    function read(): Time&\n    function resetSync()\n    function trim(): uint16\n\nend\n
"},{"location":"cargo/em.core/em.hal/UptimerN/","title":"UptimerN","text":""},{"location":"cargo/em.core/em.hal/UptimerN/#unit-uptimern","title":"unit UptimerN","text":"em.hal/UptimerN.em
package em.hal\n\nimport UptimerI\n\nmodule UptimerN: UptimerI\n    #   ^| Nil implementation of the UptimerI interface\nend\n\ndef calibrate(secs256, ticks)\n    return 0\nend\n\ndef read()\n    return null\nend\n\ndef resetSync()\nend\n\ndef trim()\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/UsCounterI/","title":"UsCounterI","text":""},{"location":"cargo/em.core/em.hal/UsCounterI/#unit-uscounteri","title":"unit UsCounterI","text":"em.hal/UsCounterI.em
package em.hal\n\ninterface UsCounterI\n\n    function start()\n    function stop(): uint32\n\nend\n
"},{"location":"cargo/em.core/em.hal/UsCounterN/","title":"UsCounterN","text":""},{"location":"cargo/em.core/em.hal/UsCounterN/#unit-uscountern","title":"unit UsCounterN","text":"em.hal/UsCounterN.em
package em.hal\n\nimport UsCounterI\n\nmodule UsCounterN: UsCounterI\n\nend\n\ndef start()\nend\n\ndef stop()\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/UsThreshI/","title":"UsThreshI","text":""},{"location":"cargo/em.core/em.hal/UsThreshI/#unit-usthreshi","title":"unit UsThreshI","text":"em.hal/UsThreshI.em
package em.hal\n\ninterface UsThreshI\n\n    function pause()\n    function set(usecs: uint16)\n\nend\n
"},{"location":"cargo/em.core/em.hal/WakeupTimerI/","title":"WakeupTimerI","text":""},{"location":"cargo/em.core/em.hal/WakeupTimerI/#unit-wakeuptimeri","title":"unit WakeupTimerI","text":"em.hal/WakeupTimerI.em
package em.hal\n\ninterface WakeupTimerI\n        #   ^| abstraction of a free-running wakeup-timer (RTC)\n    type Handler: function()\n        #   ^| handler function signature\n    function disable()\n        #   ^| disables any pending wakeup from the timer\n    function enable(thresh: uint32, handler: Handler)\n        #   ^| enables a future wakeup from the timer\n        #   ^| @thresh - an internal timer threshold value\n        #   ^| @handler - the function called when reaching the threshold\n    function secs256ToTicks(secs256: uint32): uint32\n        #   ^| converts secs256 to logical timer ticks\n    function ticksToThresh(ticks: uint32): uint32\n        #   ^| converts timer ticks to an internal timer threshold value\n    function timeToTicks(secs: uint32, subs: uint32): uint32\n        #   ^| converts secs+subs time value to logical timer ticks\n        #   ^| @secs - the seconds component of the time value\n        #   ^| @subs - the sub-seconds component of the time value\n        #   ^| @return - time value represented as logic timer ticks\nend\n
"},{"location":"cargo/em.core/em.hal/WakeupTimerN/","title":"WakeupTimerN","text":""},{"location":"cargo/em.core/em.hal/WakeupTimerN/#unit-wakeuptimern","title":"unit WakeupTimerN","text":"em.hal/WakeupTimerN.em
package em.hal\n\nimport WakeupTimerI\n\nmodule WakeupTimerN: WakeupTimerI\n    #   ^| Nil implementation of the WakeupTimerI interface\nend\n\ndef disable()\nend\n\ndef enable(thresh, handler)\nend\n\ndef secs256ToTicks(secs256)\n    return 0\nend\n\ndef ticksToThresh(ticks)\n    return 0\nend\n\ndef timeToTicks(secs, subs)\n    return 0\nend\n
"},{"location":"cargo/em.core/em.hal/WatchdogI/","title":"WatchdogI","text":""},{"location":"cargo/em.core/em.hal/WatchdogI/#unit-watchdogi","title":"unit WatchdogI","text":"em.hal/WatchdogI.em
package em.hal\n\ninterface WatchdogI\n\n    type Handler: function()\n\n    function didBite(): bool\n    function disable()\n    function enable(secs: uint16, handler: Handler)\n    function pet()\n\nend\n
"},{"location":"cargo/em.core/em.hal/WatchdogN/","title":"WatchdogN","text":""},{"location":"cargo/em.core/em.hal/WatchdogN/#unit-watchdogn","title":"unit WatchdogN","text":"em.hal/WatchdogN.em
package em.hal\n\nimport WatchdogI\n\nmodule WatchdogN: WatchdogI\n    #   ^| Nil implementation of the WatchdogI interface\nend\n\ndef didBite()\n    return false\nend\n\ndef disable()\nend\n\ndef enable(secs, handler)\nend\n\ndef pet()\nend\n
"},{"location":"cargo/em.core/em.lang/","title":"Index","text":""},{"location":"cargo/em.core/em.lang/#package-emlang","title":"package em.lang","text":""},{"location":"cargo/em.core/em.lang/Assert/","title":"Assert","text":""},{"location":"cargo/em.core/em.lang/Assert/#unit-assert","title":"unit Assert","text":"em.lang/Assert.em
package em.lang\n\nimport AssertProviderI\nimport AssertProviderN\n\nmodule Assert\n\n    proxy Provider: AssertProviderI\n\n    function enabled(): bool\n    function trigger(upath: atom_t, line: uint16, msg: atom_t = 0, arg1: iarg_t = 0, arg2: iarg_t = 0)\n\nend\n\ndef em$configure()\n    Provider ?= AssertProviderN\nend\n\ndef enabled()\n    return Provider.enabled()\nend\n\ndef trigger(upath, line, msg, arg1, arg2)\n    Provider.trigger(upath, line, msg, arg1, arg2) if enabled()\nend\n
"},{"location":"cargo/em.core/em.lang/AssertProviderI/","title":"AssertProviderI","text":""},{"location":"cargo/em.core/em.lang/AssertProviderI/#unit-assertprovideri","title":"unit AssertProviderI","text":"em.lang/AssertProviderI.em
package em.lang\n\ninterface AssertProviderI\n\n    function enabled(): bool\n    function trigger(upath: atom_t, line: uint16, msg: atom_t, arg1: iarg_t, arg2: iarg_t)\n\nend\n
"},{"location":"cargo/em.core/em.lang/AssertProviderN/","title":"AssertProviderN","text":""},{"location":"cargo/em.core/em.lang/AssertProviderN/#unit-assertprovidern","title":"unit AssertProviderN","text":"em.lang/AssertProviderN.em
package em.lang\n\nimport AssertProviderI\n\nmodule AssertProviderN: AssertProviderI\n\nend\n\ndef enabled()\n    return false\nend\n\ndef trigger(upath, line, msg, arg1, arg2)\nend\n
"},{"location":"cargo/em.core/em.lang/Atom/","title":"Atom","text":""},{"location":"cargo/em.core/em.lang/Atom/#unit-atom","title":"unit Atom","text":"em.lang/Atom.em
package em.lang\n\nmodule Atom\n\n    config NULL_A: atom_t = @\"<<null>>\"\n    config UNDEFINED_A: atom_t = @\"<<undefined>>\"\n\n    function fromString(str: string, oatom: atom_t*): bool\n    function hasTable(): bool\n    function toString(atom: atom_t): string\n\nprivate:\n\n    const MASK: addr_t = 0x80000000\n\n    config tableFlag: bool\n\nend\n\ndef em$construct()\n    tableFlag = ^^!!em$props.get(em$session.PROP_ATOM_TABLE)^^\nend\n\ndef fromString(str, oatom)\n    auto saddr = <addr_t>str\n    return false if tableFlag || (saddr & MASK) == 0\n    *oatom = <atom_t>saddr\n    return true\nend\n\ndef hasTable()\n    return tableFlag\nend\n\ndef toString(atom)\n    return tableFlag ? ^^em$atoms[atom]^^ : <string>((<addr_t>atom) | MASK)\nend\n
"},{"location":"cargo/em.core/em.lang/BuildC/","title":"BuildC","text":""},{"location":"cargo/em.core/em.lang/BuildC/#unit-buildc","title":"unit BuildC","text":"em.lang/BuildC.em
package em.lang\n\ncomposite BuildC\n\n    config arch: string\n    config bootFlash: bool\n    config bootLoader: bool\n    config compiler: string\n    config cpu: string\n    config jlinkDev: string\n    config mcu: string\n    config optimize: string\n\nprivate:\n\n    var curPval: string\n\n    function getProp(pname: string): string\n\nend\n\ndef em$preconfigure()\n    arch ?= curPval if getProp(\"em.build.Arch\")\n    bootFlash ?= true if getProp(\"em.build.BootFlash\")\n    bootLoader ?= true if getProp(\"em.lang.BootLoader\")\n    compiler ?= curPval if getProp(\"em.build.Compiler\")\n    cpu ?= curPval if getProp(\"em.build.Cpu\")\n    jlinkDev ?= curPval if getProp(\"em.build.JlinkDev\")\n    mcu ?= curPval if getProp(\"em.build.Mcu\")\n    optimize ?= curPval if getProp(\"em.build.Optimize\")\nend\n\ndef getProp(pname)\n    return curPval = ^^em$props.get^^(pname, null)\nend\n
"},{"location":"cargo/em.core/em.lang/BuilderI/","title":"BuilderI","text":""},{"location":"cargo/em.core/em.lang/BuilderI/#unit-builderi","title":"unit BuilderI","text":"em.lang/BuilderI.em
package em.lang\n\nhost interface BuilderI\n\n    type CompileInfo: struct\n        errMsgs: string[]\n        imageSizes: string\n        procStat: int8\n    end\n\n    type TypeInfoDesc: uint8[2]\n\n    type TypeInfo: struct\n        ARG:    TypeInfoDesc\n        CHAR:   TypeInfoDesc\n        INT:    TypeInfoDesc\n        INT8:   TypeInfoDesc\n        INT16:  TypeInfoDesc\n        INT32:  TypeInfoDesc\n        LONG:   TypeInfoDesc\n        PTR:    TypeInfoDesc\n        SHORT:  TypeInfoDesc\n        SIZE:   TypeInfoDesc\n    end\n\n    function compile(buildDir: string): CompileInfo&\n    function getTypeInfo(): TypeInfo&\n    function populate(buildDir: string, sysFlag: bool)\n\nend\n
"},{"location":"cargo/em.core/em.lang/CompositeI/","title":"CompositeI","text":""},{"location":"cargo/em.core/em.lang/CompositeI/#unit-compositei","title":"unit CompositeI","text":"em.lang/CompositeI.em
package em.lang\n\ninterface CompositeI\n\n    host function em$configure()\n    host function em$preconfigure()\n\nend\n
"},{"location":"cargo/em.core/em.lang/Console/","title":"Console","text":""},{"location":"cargo/em.core/em.lang/Console/#unit-console","title":"unit Console","text":"em.lang/Console.em
package em.lang\n\nimport ConsoleProviderI\n\nmodule Console\n\n    proxy Provider: ConsoleProviderI\n\n    config noPrint: bool\n\n    function print(fmt: string, a1: iarg_t = 0, a2: iarg_t = 0, a3: iarg_t = 0, a4: iarg_t = 0, a5: iarg_t = 0, a6: iarg_t = 0)\n\n    function wrC(data: char)\n    function wrN(data: num_t)\n    function wrP(data: ptr_t)\n\n    function wrT(data: string)\n\n    function wrIA(data: iarg_t)\n    function wrUA(data: uarg_t)\n\n    function wrI8(data: int8)\n    function wrI16(data: int16)\n    function wrI32(data: int32)\n\n    function wrU8(data: uint8)\n    function wrU16(data: uint16)\n    function wrU32(data: uint32)\n\nend\n\ndef em$generateCode(prefix)\n    |-> #define em$print em_lang_Console::print\nend\n\ndef print(fmt, a1, a2, a3, a4, a5, a6)\n    if !noPrint\n        Provider.print(fmt, a1, a2, a3, a4, a5, a6)\n    end\nend\n\ndef wrC(data)\n    Provider.put(data)\nend\n\ndef wrN(data)\n    Provider.put(0x8F)\n    auto ba = <uint8[]>(&data)\n    for auto i = 0; i < sizeof<num_t>; i++\n        Provider.put(ba[i])\n    end\n    Provider.flush()\nend\n\ndef wrP(data)\n    wrU32(<uint32>data)\nend\n\ndef wrT(data)\n    Provider.put(0x80)\n    auto cp = <char*>data\n    for ;;\n        auto ch = *cp++\n        wrC(ch)\n        return if ch == 0      \n    end\nend\n\ndef wrIA(data)\n    wrU16(<uint16>data)\nend\n\ndef wrUA(data)\n    wrU16(<uint16>data)\nend\n\ndef wrI8(data)\n    wrU8(<uint8>data)\nend\n\ndef wrI16(data)\n    wrU16(<uint16>data)\nend\n\ndef wrI32(data)\n    wrU32(<uint32>data)\nend\n\ndef wrU8(data)\n    Provider.put(0x81)\n    Provider.put(data)\n    Provider.flush()\nend\n\ndef wrU16(data)\n    Provider.put(0x82)\n    auto b = <uint8> ((data >> 8) & 0xFF)\n    Provider.put(b)\n    b = <uint8> ((data >> 0) & 0xFF)\n    Provider.put(b)\n    Provider.flush()\nend\n\ndef wrU32(data)\n    Provider.put(0x84)\n    auto b = <uint8> ((data >> 24) & 0xFF)\n    Provider.put(b)\n    b = <uint8> ((data >> 16) & 0xFF)\n    Provider.put(b)\n    b = <uint8> ((data >> 8) & 0xFF)\n    Provider.put(b)\n    b = <uint8> ((data >> 0) & 0xFF)\n    Provider.put(b)\n    Provider.flush()\nend\n
"},{"location":"cargo/em.core/em.lang/ConsoleProviderI/","title":"ConsoleProviderI","text":""},{"location":"cargo/em.core/em.lang/ConsoleProviderI/#unit-consoleprovideri","title":"unit ConsoleProviderI","text":"em.lang/ConsoleProviderI.em
package em.lang\n\ninterface ConsoleProviderI\n\n    function flush()\n    function print(fmt: string, a1: iarg_t = 0, a2: iarg_t = 0, a3: iarg_t = 0, a4: iarg_t = 0, a5: iarg_t = 0, a6: iarg_t = 0)\n    function put(data: uint8)\n\nend\n
"},{"location":"cargo/em.core/em.lang/ConsoleProviderN/","title":"ConsoleProviderN","text":""},{"location":"cargo/em.core/em.lang/ConsoleProviderN/#unit-consoleprovidern","title":"unit ConsoleProviderN","text":"em.lang/ConsoleProviderN.em
package em.lang\n\nimport ConsoleProviderI\n\nmodule ConsoleProviderN: ConsoleProviderI\n\nend\n\ndef flush()\nend\n\ndef print(fmt, a1, a2, a3, a4, a5, a6)\nend\n\ndef put(data)\nend\n
"},{"location":"cargo/em.core/em.lang/Debug/","title":"Debug","text":""},{"location":"cargo/em.core/em.lang/Debug/#unit-debug","title":"unit Debug","text":"em.lang/Debug.em
package em.lang\n\nimport DebugPinI\n\nmodule Debug\n\n    proxy Pin_a: DebugPinI\n    proxy Pin_b: DebugPinI\n    proxy Pin_c: DebugPinI\n    proxy Pin_d: DebugPinI\n\n    function getNumPins(): uint8\n    function sleepEnter()\n    function sleepLeave()\n    function startup()\n\nprivate:\n\nend\n\ndef em$configure()\n    em$used ?= true\nend\n\ndef getNumPins()\n    return 4\nend\n\ndef sleepEnter()\n    Pin_a.reset()\n    Pin_b.reset()\n    Pin_c.reset()\n    Pin_d.reset()\nend\n\ndef sleepLeave()\n    startup()\nend\n\ndef startup()\n    Pin_a.startup()\n    Pin_b.startup()\n    Pin_c.startup()\n    Pin_d.startup()\nend\n
"},{"location":"cargo/em.core/em.lang/DebugPinI/","title":"DebugPinI","text":""},{"location":"cargo/em.core/em.lang/DebugPinI/#unit-debugpini","title":"unit DebugPinI","text":"em.lang/DebugPinI.em
package em.lang\n\ninterface DebugPinI\n\n    function clear()\n    function get(): bool\n    function set()\n    function toggle()\n    function pulse()\n    function mark(k: uint8 = 0)\n    function reset()\n    function startup()\n\nend\n
"},{"location":"cargo/em.core/em.lang/DebugPinN/","title":"DebugPinN","text":""},{"location":"cargo/em.core/em.lang/DebugPinN/#unit-debugpinn","title":"unit DebugPinN","text":"em.lang/DebugPinN.em
package em.lang\n\nimport DebugPinI\n\nmodule DebugPinN: DebugPinI\n\nend\n\ndef clear()\nend\n\ndef get()\n    return false\nend\n\ndef set()\nend\n\ndef toggle()\nend\n\ndef pulse()\nend\n\ndef mark(k)\nend\n\ndef reset()\nend\n\ndef startup()\nend\n
"},{"location":"cargo/em.core/em.lang/Math/","title":"Math","text":""},{"location":"cargo/em.core/em.lang/Math/#unit-math","title":"unit Math","text":"em.lang/Math.em
package em.lang\n\n#! This module is only available for use on the host.\n#! It contains some standard math functions.\n\nhost module Math\n\n    config PI: num_t\n\n    #! Returns the absolute value of x\n    function abs(x: num_t): num_t\n\n    #! Returns the smallest integer greater than or equal to x\n    function ceil(x: num_t): num_t\n\n    #! Returns the cos of x\n    function cos(x: num_t): num_t\n\n    #! Returns the largest integer less than or equal to x\n    function floor(x: num_t): num_t\n\n    #! Returns the logarithm (base 10) of x\n    function log2(x: num_t): num_t\n\n    #! Returns the logarithm (base 10) of x\n    function log10(x: num_t): num_t\n\n    #! Returns the value of x to the y power\n    function pow(x: num_t, y: num_t): num_t\n\n    #! Returns the rounded value of x\n    function round(x: num_t): num_t\n\n    #! Returns the sin of x\n    function sin(x: num_t): num_t\n\nend\n\ndef em$configure()\n    PI ?= ^^global.Math.PI^^\nend\n\ndef abs(x)\n    return ^^global.Math.abs(x)^^\nend\n\n# If x = 19.1 this function will return 20\ndef ceil(x)\n    return ^^global.Math.ceil(x)^^\nend\n\ndef cos(x)\n    return ^^global.Math.cos(x)^^\nend\n\n# If x = 19.6 this function will return 19\ndef floor(x)\n    return ^^global.Math.floor(x)^^\nend\n\ndef log2(x)\n    return ^^global.Math.log2(x)^^\nend\n\ndef log10(x)\n    return ^^global.Math.LOG10E * global.Math.log(x)^^\nend\n\ndef pow(x, y)\n    return ^^global.Math.pow(x, y)^^\nend\n\ndef round(x)\n    return ^^global.Math.round(x)^^\nend\n\ndef sin(x)\n    return ^^global.Math.sin(x)^^\nend\n
"},{"location":"cargo/em.core/em.lang/ModuleI/","title":"ModuleI","text":""},{"location":"cargo/em.core/em.lang/ModuleI/#unit-modulei","title":"unit ModuleI","text":"em.lang/ModuleI.em
package em.lang\n\ninterface ModuleI\n\n    type io32_t: uint32 volatile*\n\n    host config em$exclude: bool\n    host config em$export: bool\n    host config em$traceGrp: string\n    host config em$used: bool\n\n    config em$tracePri: uint8\n\n    host function em$configure()\n    host function em$construct()\n    template em$generateCode(prefix: string)\n\n    function em$fail()\n    function em$halt()\n    function em$reset()\n    function em$run()\n    function em$shutdown()\n    function em$startup()\n    function em$startupDone()\n\n    host function em$uses__()\n\nend\n
"},{"location":"cargo/em.core/em.lang/RunC/","title":"RunC","text":""},{"location":"cargo/em.core/em.lang/RunC/#unit-runc","title":"unit RunC","text":"em.lang/RunC.em
package em.lang\n\nimport Console\nimport ConsoleProviderN\n\nimport Debug\nimport DebugPinN\n\ncomposite RunC\n\nend\n\ndef em$configure()\n    Console.em$used ?= true\n    Console.Provider ?= ConsoleProviderN\n    Debug.em$used ?= true\n    Debug.Pin_a ?= DebugPinN\n    Debug.Pin_b ?= DebugPinN\n    Debug.Pin_c ?= DebugPinN\n    Debug.Pin_d ?= DebugPinN\nend\n
"},{"location":"cargo/em.core/em.lang/TemplateI/","title":"TemplateI","text":""},{"location":"cargo/em.core/em.lang/TemplateI/#unit-templatei","title":"unit TemplateI","text":"em.lang/TemplateI.em
package em.lang\n\nhost interface TemplateI \n\n    function em$cacheDirty(ctimeMs: num_t): bool\n    template em$generateUnit(pkgName: string, unitName: string)\n\nend\n
"},{"location":"cargo/em.core/em.mcu/","title":"Index","text":""},{"location":"cargo/em.core/em.mcu/#package-emmcu","title":"package em.mcu","text":""},{"location":"cargo/em.core/em.mcu/Common/","title":"Common","text":""},{"location":"cargo/em.core/em.mcu/Common/#unit-common","title":"unit Common","text":"em.mcu/Common.em
package em.mcu\n\nfrom em.hal import BusyWaitI\nfrom em.hal import GlobalInterruptsI\nfrom em.hal import IdleI\nfrom em.hal import McuI\nfrom em.hal import MsCounterI\nfrom em.hal import RandI\nfrom em.hal import UsCounterI\nfrom em.hal import WatchdogI\n\nmodule Common\n        #   ^| collection of proxies implementing MCU abstractions\n    proxy BusyWait: BusyWaitI\n    proxy GlobalInterrupts: GlobalInterruptsI\n    proxy Idle: IdleI \n    proxy Mcu: McuI    \n    proxy MsCounter: MsCounterI    \n    proxy Rand: RandI\n    proxy UsCounter: UsCounterI    \n    proxy Watchdog: WatchdogI\n\nend\n
"},{"location":"cargo/em.core/em.mcu/CommonC/","title":"CommonC","text":""},{"location":"cargo/em.core/em.mcu/CommonC/#unit-commonc","title":"unit CommonC","text":"em.mcu/CommonC.em
package em.mcu\n\nfrom em.hal import BusyWaitN\nfrom em.hal import GlobalInterruptsN\nfrom em.hal import IdleN\nfrom em.hal import McuN\nfrom em.hal import MsCounterN\nfrom em.hal import RandN\nfrom em.hal import UsCounterN\nfrom em.hal import WatchdogN\n\nfrom em.mcu import Common\n\ncomposite CommonC\n\nend\n\ndef em$configure()\n    Common.BusyWait ?= BusyWaitN\n    Common.GlobalInterrupts ?= GlobalInterruptsN\n    Common.Idle ?= IdleN\n    Common.Mcu ?= McuN\n    Common.MsCounter ?= MsCounterN\n    Common.Rand ?= RandN\n    Common.UsCounter ?= UsCounterN\n    Common.Watchdog ?= WatchdogN\nend\n
"},{"location":"cargo/em.core/em.mcu/ConsoleUart/","title":"ConsoleUart","text":""},{"location":"cargo/em.core/em.mcu/ConsoleUart/#unit-consoleuart","title":"unit ConsoleUart","text":"em.mcu/ConsoleUart.em
package em.mcu\n\nfrom em.hal import ConsoleUartI\nfrom em.hal import ConsoleUartN\n\nmodule ConsoleUart: ConsoleUartI\n\n    proxy Impl: ConsoleUartI\n\nend\n\ndef em$configure()\n    Impl ?= ConsoleUartN\nend\n\ndef setBaudH(rate)\n    Impl.setBaudH(rate)\nend\n\ndef flush()\n    Impl.flush()\nend\n\ndef put(data)\n    Impl.put(data)\nend\n
"},{"location":"cargo/em.core/em.mcu/Copier/","title":"Copier","text":""},{"location":"cargo/em.core/em.mcu/Copier/#unit-copier","title":"unit Copier","text":"em.mcu/Copier.em
package em.mcu\n\nfrom em.hal import CopierI\n\nmodule Copier: CopierI\n\n    proxy Impl: CopierI\n\nend\n\ndef exec(dst, src, cnt)\n    Impl.exec(dst, src, cnt)\nend\n
"},{"location":"cargo/em.core/em.mcu/Info/","title":"Info","text":""},{"location":"cargo/em.core/em.mcu/Info/#unit-info","title":"unit Info","text":"em.mcu/Info.em
package em.mcu\n\nfrom em.hal import McuInfoI\n\nmodule Info: McuInfoI\n\n    proxy Impl: McuInfoI\n\nend\n\ndef readBatMv()\n    return Impl.readBatMv()\nend\n\ndef readTempC()\n    return Impl.readTempC()\nend\n
"},{"location":"cargo/em.core/em.mcu/Poller/","title":"Poller","text":""},{"location":"cargo/em.core/em.mcu/Poller/#unit-poller","title":"unit Poller","text":"em.mcu/Poller.em
package em.mcu\n\nfrom em.hal import PollerN\n\nfrom em.hal import PollerI\n\nmodule Poller: PollerI\n\n    proxy Impl: PollerI\n\n    function pause(timeMs: uint16)\n\nend\n\ndef em$configure()\n    Impl ?= PollerN\nend\n\ndef pause(timeMs)\n    Impl.poll(timeMs, 1, null)\nend\n\ndef poll(rateMs, count, fxn)\n    return Impl.poll(rateMs, count, fxn)\nend\n
"},{"location":"cargo/em.core/em.mcu/Timeout/","title":"Timeout","text":""},{"location":"cargo/em.core/em.mcu/Timeout/#unit-timeout","title":"unit Timeout","text":"em.mcu/Timeout.em
package em.mcu\n\nfrom em.hal import TimeoutI\n\nmodule Timeout: TimeoutI\n\n    proxy Impl: TimeoutI\n\nend\n\ndef active()\n    return Impl.active()\nend\n\ndef cancel()\n    Impl.cancel()\nend\n\ndef set(msecs)\n    Impl.set(msecs)\nend\n
"},{"location":"cargo/em.core/em.utils/","title":"Index","text":""},{"location":"cargo/em.core/em.utils/#package-emutils","title":"package em.utils","text":""},{"location":"cargo/em.core/em.utils/AlarmMgr/","title":"AlarmMgr","text":""},{"location":"cargo/em.core/em.utils/AlarmMgr/#unit-alarmmgr","title":"unit AlarmMgr","text":"em.utils/AlarmMgr.em
package em.utils\n\nfrom em.hal import WakeupTimerI\n\nimport EpochTime\nimport FiberMgr\n\nmodule AlarmMgr\n            #   ^|\n    proxy WakeupTimer: WakeupTimerI\n            #   ^|\n    type Alarm: opaque\n            #   ^|        \n        host function initH(fiber: FiberMgr.Fiber&)\n            #   ^|        \n        function active(): bool\n            #   ^|        \n        function cancel()\n            #   ^|        \n        function wakeup(secs256: uint32)\n            #   ^|        \n        function wakeupAt(secs256: uint32)\n            #   ^|        \n    end\n\n    host function createH(fiber: FiberMgr.Fiber&): Alarm&\n            #   ^|\nprivate:\n\n    def opaque Alarm\n        fiber: FiberMgr.Fiber&\n        thresh: uint32\n        ticks: uint32\n        function setup(ticks: uint32)\n    end\n\n    function update(deltaTicks: uint32)\n    function wakeupHandler: WakeupTimer.Handler\n\n    var alarmTab: Alarm[..]\n    var curAlarm: Alarm&\n\nend\n\ndef createH(fiber)\n    var alarm: Alarm& = alarmTab[alarmTab.length++]\n    alarm.initH(fiber)\n    return alarm\nend\n\ndef update(deltaTicks)\n    WakeupTimer.disable()\n    auto nxtAlarm = <Alarm&>null\n    var maxTicks: uint32 = ~0       # largest uint32\n    for a in alarmTab\n        continue if a.ticks == 0    # inactive alarm\n        a.ticks -= deltaTicks\n        if a.ticks == 0             # expired alarm\n            a.fiber.post()\n        elif a.ticks < maxTicks\n            nxtAlarm = a\n            maxTicks = a.ticks         \n        end\n    end\n    return if nxtAlarm == null      # no active alarms\n    curAlarm = nxtAlarm\n    WakeupTimer.enable(curAlarm.thresh, wakeupHandler)\nend\n\ndef wakeupHandler()\n    update(curAlarm.ticks)\nend\n\ndef Alarm.initH(fiber)\n    this.fiber = fiber\n    this.ticks = 0\nend\n\ndef Alarm.active()\n    return this.ticks != 0\nend\n\ndef Alarm.cancel()\n    this.ticks = 0\n    update(0)\nend\n\ndef Alarm.setup(ticks)\n    this.thresh = WakeupTimer.ticksToThresh(ticks)\n    this.ticks = ticks\n    update(0)\nend\n\ndef Alarm.wakeup(secs256)\n    auto ticks = WakeupTimer.secs256ToTicks(secs256)\n    this.setup(ticks)\nend\n\ndef Alarm.wakeupAt(secs256)\n    var etSubs: uint32\n    auto etSecs = EpochTime.getCurrent(&etSubs)\n    auto etTicks = WakeupTimer.timeToTicks(etSecs, etSubs)\n    auto ticks = WakeupTimer.secs256ToTicks(secs256)\n    this.setup(ticks - (etTicks % ticks))\nend\n
"},{"location":"cargo/em.core/em.utils/AppControl/","title":"AppControl","text":""},{"location":"cargo/em.core/em.utils/AppControl/#unit-appcontrol","title":"unit AppControl","text":"em.utils/AppControl.em
package em.utils\n\nfrom em.mcu import Common\n\nimport BoardController\nimport EpochTime\n\nmodule AppControl\n\n    function restart(status: int8)\n\nprivate:\n\n    type Stash: struct\n        secs: uint32\n        subs: uint32\n    end\n\n    function getStash(): Stash&\n    function doReset(code: int8)\n\nend\n\ndef em$startup()\n    return if Common.Mcu.isWarm() || Common.Mcu.getResetCode() < 0\n    auto stash = getStash()\n    EpochTime.setCurrent(stash.secs, stash.subs, false)\nend\n\ndef em$fail()\n    BoardController.em$fail()\nend\n\ndef em$halt()\n    BoardController.em$halt()\nend\n\ndef doReset(code)\n    auto stash = getStash()\n    stash.secs = EpochTime.getCurrent(&stash.subs)\n    Common.Mcu.reset(code) \nend\n\ndef getStash()\n    return Common.Mcu.getStashAddr()\nend\n\ndef restart(status)\n    doReset(status)\nend\n
"},{"location":"cargo/em.core/em.utils/AssertProvider/","title":"AssertProvider","text":""},{"location":"cargo/em.core/em.utils/AssertProvider/#unit-assertprovider","title":"unit AssertProvider","text":"em.utils/AssertProvider.em
package em.utils\n\nfrom em.lang import AssertProviderI\n\nimport Error\nimport Logger\n\nmodule AssertProvider: AssertProviderI\n\nprivate:\n\n    config assertMsgE: Logger.EventKind&\n    config assertSiteE: Logger.EventKind&\n\nend\n\ndef em$construct()\n    assertMsgE = Logger.declareEventH(\"ASSERT: $F\", \"*--*\")\n    assertSiteE = Logger.declareEventH(\"ASSERT: $a, line %d\", \"*--*\")\nend\n\ndef enabled()\n    return Logger.POLICY != Logger.Policy.NIL\nend\n\ndef trigger(upath, line, msg, arg1, arg2)\n    assertSiteE.log(<addr_t>upath, line)\n    assertMsgE.log(<addr_t>msg, <addr_t>arg1, <addr_t>arg2) if msg\n    Error.raise(Error.Kind.ASSERTION, 0, 0)\nend\n
"},{"location":"cargo/em.core/em.utils/BasicListManager/","title":"BasicListManager","text":""},{"location":"cargo/em.core/em.utils/BasicListManager/#unit-basiclistmanager","title":"unit BasicListManager","text":"em.utils/BasicListManager.em
package em.utils\n\nimport ListManagerI\n\n#! This module implements ListManagerI.\n#! It contains all the functions necessary to maintain a list of objects.\n\nmodule BasicListManager: ListManagerI\n\nprivate:\n\n    # Representation of Element\n    def opaque Element \n        next: Element& volatile\n    end\n\n    # Representation of List\n    def opaque List \n        first: Element& volatile\n        last: Element& volatile\n    end\nend\n\n# Initially an Element is not a member of a List\ndef Element.init() \n    this.next = null\nend\n\n# Initially an Element is not a member of a List\ndef Element.initH() \n    this.next = null\nend\n\ndef Element.isActive() \n    return <uarg_t> this.next\nend\n\n# Creates a head and tail pointer\ndef List.init() \n    this.first = this.last = <Element&> &this.first\nend\n\n# Creates a head and tail pointer\ndef List.initH() \n    this.first = this.last = <Element&> &this.first;\nend\n\n# The very first Element is pointed to by this.first and this.last.\n# Subsequent Elements are added to the end of the list by setting the\n# next pointer of the current last Element to the added Element then moving\n# the last pointer.    \ndef List.add(elem)\n    this.last.next = elem\n    this.last = elem\n    elem.next = <Element&> this\nend\n\n# Elements are removed from the front of the list by\n# setting a pointer equal to the this.first pointer,\n# then moving the this.first pointer to the next Element.\n# If the pointer then points to the List then that was the last\n# Element and reinitialize the list for adding Elements.\n# Otherwise just remove the Element.    \ndef List.get() \n    auto elem = this.first\n    this.last = <Element&>this if (this.first = elem.next) == <Element&>this\n    elem.next = null\n    return elem\nend\n\ndef List.getAt(index)\n    auto elem = this.first\n    auto i = 0\n    if this.hasElements()\n        for ;;\n            break if i++ == index                \n            elem = elem.next                \n            break if elem == <Element&> this\n        end\n        elem = null if elem == <Element&> this\n    else \n        elem = null\n    end\n    return elem\nend\n\n# This function returns the Element after the given Element\n# in the List, but does not remove it from the List.\ndef List.getNext(elem) \n    return elem == this.last ? null : elem.next\nend\n\ndef List.hasElements() \n    return (<uarg_t> this.first) ^ <uarg_t> this\nend\n\n# This function prints the index and address of each Element in the List\ndef List.print() \n    auto elem = this.first\n    auto i = 0\n    if this.hasElements()\n        for ;;\n            printf \"elem%d %p\\n\", i++, elem\n            elem = elem.next\n            break if elem == <Element&> this\n        end\n    else \n        printf \"list empty\\n\"\n    end\n    printf \"\\n\" \nend\n\n# Performs a linear search through the list to find the Element\n# then removes it, updating the appropriate pointers.\ndef List.remove(elem)\n    auto e = this.first\n    if this.hasElements()\n        if elem == this.first\n            this.first = this.first.next\n        else \n            for ;; \n                if e.next == elem\n                    e.next = elem.next                    \n                    break    \n                end \n                break if e == <Element&> this\n            end\n        end\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/BoardController/","title":"BoardController","text":""},{"location":"cargo/em.core/em.utils/BoardController/#unit-boardcontroller","title":"unit BoardController","text":"em.utils/BoardController.em
package em.utils\n\nfrom em.hal import ConsoleUartI\nfrom em.hal import LedI\n\nfrom em.mcu import Common\nfrom em.mcu import ConsoleUart\n\nimport ConsoleProtocol\n\nmodule BoardController\n\n    proxy Led: LedI\n    proxy Uart: ConsoleUartI\n\n    config blinkRate: uint32 = 50000\n\nprivate:    \n\n    function blink(times: uint8, usecs: uint32)\n\nend\n\ndef em$configure()\n    Uart ?= ConsoleUart\nend\n\ndef em$reset()\n    Common.Mcu.startup() \nend\n\ndef em$startupDone()\n    return if Common.Mcu.isWarm()\n    Led.off()\n    blink(2, blinkRate)\n    Uart.flush()\n    Uart.put(0)\n    Uart.put(0)\n    for auto i = 0; i < ConsoleProtocol.SOT_COUNT; i++\n        Uart.put(ConsoleProtocol.SOT_BYTE)\n    end\n    Uart.flush()\nend\n\ndef em$halt()\n    Uart.put(ConsoleProtocol.EOT_BYTE)\n    Common.GlobalInterrupts.disable()\n    Led.on()\n    Common.Mcu.shutdown()\nend\n\ndef em$fail()\n    Common.Mcu.shutdown()\n    Common.GlobalInterrupts.disable()\n    while true\n        blink(2, blinkRate)\n        for auto i = 0; i < 800; i++\n            Common.BusyWait.wait(100)\n        end\n    end\nend\n\ndef blink(times, usecs)\n    auto k = (times * 2)\n    while --k\n        Led.toggle()\n        Common.BusyWait.wait(usecs)    \n    end\n    Led.toggle()\nend\n
"},{"location":"cargo/em.core/em.utils/BoardDriverI/","title":"BoardDriverI","text":""},{"location":"cargo/em.core/em.utils/BoardDriverI/#unit-boarddriveri","title":"unit BoardDriverI","text":"em.utils/BoardDriverI.em
package em.utils\n\ninterface BoardDriverI\n\n    host function bindParamsH(p: ptr_t)\n\n    template genImpl(dn: string)\n    template genSpec(dn: string)\n\nend\n
"},{"location":"cargo/em.core/em.utils/BoardDriversGenT/","title":"BoardDriversGenT","text":""},{"location":"cargo/em.core/em.utils/BoardDriversGenT/#unit-boarddriversgent","title":"unit BoardDriversGenT","text":"em.utils/BoardDriversGenT.em
package em.utils\n\nimport BoardInfo\n\ntemplate BoardDriversGenT\n\n    config driversPkg: string\n\nend\n\ndef em$generateUnit(pn, un)\n    auto brdRec = BoardInfo.readRecordH()\n    auto drvPkg = driversPkg\n            |->package `pn`\n            |-> \n    for dd in brdRec.drvDescs\n            |->from `drvPkg` import `dd.driver` as `dd.name`\n    end\n            |->\n            |->module `un`\n            |-> \n            |->end\nend\n
"},{"location":"cargo/em.core/em.utils/BoardInfo/","title":"BoardInfo","text":""},{"location":"cargo/em.core/em.utils/BoardInfo/#unit-boardinfo","title":"unit BoardInfo","text":"em.utils/BoardInfo.em
package em.utils\n\nfrom em$distro import BoardMeta as Meta\n\nhost module BoardInfo\n\n    const PROP_BOARD_CHAIN: string = \"em.lang.BoardChain_\"\n    const PROP_BOARD_KIND: string = \"em.lang.BoardKind\"\n\n    type PinMap: Meta.PinMap\n    type DrvDesc: Meta.DrvDesc\n    type Record: Meta.Record\n\n    function getKind(): string\n    function readRecordH(): Record&\n\nprivate:\n\n    function cacheGet(kind: string): Record&\n    function cacheSet(kind: string, rec: Record&)\n\n    function collapse(kind: string, db: ptr_t, set: ptr_t): ptr_t\n\n    function init()\n\n    function mergeBrd(baseBrd: ptr_t, extBrd: ptr_t)\n    function mergeDb(baseDb: ptr_t, extDb: ptr_t)\n\n    config baseFileLoc: string\n    config localFileLoc: string\n\n    config attrs: string[]\n    config pins: string[]\n\n    config boardKind: string\n\n    var initFlg: bool\n    var recCache: ptr_t\n\nend\n\ndef em$configure()\n    readRecordH()\nend\n\ndef cacheGet(kind)\n    ^^if (!BoardInfo.recCache) BoardInfo.recCache = {}^^\n    return ^^BoardInfo.recCache[kind]^^\nend\n\ndef cacheSet(kind, rec)\n    ^^BoardInfo.recCache[kind] = rec^^\nend\n\ndef collapse(kind, db, set)\n    return ^^db.$DEFAULTS^^ if ^^!kind || kind == '$DEFAULTS'^^\n    var ext: ptr_t = ^^db[kind]^^\n    if !ext\n        printf \"*** unknown board kind: '%s'\\n\", kind\n        fail\n    end\n    if ^^set.has(kind)^^\n        printf \"*** circular inheritance chain: '%s'\\n\", kind\n        fail\n    end\n    ^^set.add(kind)^^\n    var base: ptr_t = collapse(^^ext.$inherits^^, db, set)\n    mergeBrd(base, ext)\n    return base\nend\n\ndef getKind()\n    init()\n    return boardKind\nend\n\ndef init()\n    return if initFlg\n    initFlg = true\n    attrs = Meta.attrNames\n    pins = Meta.pinNames\n    baseFileLoc = Meta.baseFileLoc\n    auto path = ^^$Path.join(em$session.getRootDir(), 'em-boards-local')^^\n    localFileLoc = ^^$Fs.existsSync(path) ? path : null^^\n    boardKind = ^^em$props.get^^(PROP_BOARD_KIND)\nend\n\ndef mergeBrd(baseBrd, extBrd)\n    ^^var aTab = []^^\n    ^^for (a in extBrd) { aTab[a] = true; aTab.push(a) }^^\n    for a in attrs\n        ^^baseBrd[a] = extBrd[a]^^ if ^^a in extBrd^^\n        ^^aTab[a] = false^^\n    end\n    for i: uint8 = 0; i < ^^aTab.length^^; i++\n        var an: string = ^^aTab[i]^^\n        if an != \"pins\" && an != \"drvDescs\" && an != \"nvsFiles\" && ^^aTab[an]^^\n            printf \"*** unknown attribute name: %s\\n\", an\n            fail\n        end\n    end\n    #\n    ^^var pTab = []^^\n    ^^for (p in extBrd.pins) { pTab[p] = true; pTab.push(p) }^^\n    ^^baseBrd.pins = {}^^ if ^^!baseBrd.pins^^\n    for p in pins\n        ^^baseBrd.pins[p] = extBrd.pins[p]^^ if ^^extBrd.pins && p in extBrd.pins^^\n        ^^pTab[p] = false^^\n    end\n    for i: uint8 = 0; i < ^^pTab.length^^; i++\n        var pn: string = ^^pTab[i]^^\n        continue if ^^pn[0] == '$'^^\n        if ^^pTab[pn]^^\n            printf \"*** unknown pin name: %s\\n\", pn\n            fail\n        end\n    end\n    #\n    ^^baseBrd.drvDescs = extBrd.drvDescs^^ if ^^extBrd.drvDescs^^\n    ^^baseBrd.nvsFiles = extBrd.nvsFiles^^ if ^^extBrd.nvsFiles^^\nend\n\ndef mergeDb(baseDb, extDb)\n    ^^var brdSet = {}^^\n    ^^var brdArr = []^^\n    ^^for (b in baseDb) brdSet[b] = true^^\n    ^^for (b in extDb) brdSet[b] = true^^\n    ^^for (b in brdSet) brdArr.push(b)^^\n    for i: uint8 = 0; i < ^^brdArr.length^^; i++\n        ^^var brdKind = brdArr[i]^^\n        ^^var baseBrd = baseDb[brdKind]^^\n        ^^var extBrd = extDb[brdKind]^^\n        if ^baseBrd && ^extBrd\n            if ^^extBrd.$overrides^^\n                mergeBrd(^baseBrd, ^extBrd)\n            else\n                printf \"*** missing '$overrides' for %s\\n\", ^brdKind\n                fail\n            end\n        elif ^extBrd\n            if ^^extBrd.$overrides^^\n                printf \"*** no platform definition for '$overrides' for %s\\n\", ^brdKind\n                fail\n            else\n                ^^baseDb[brdKind] = extDb[brdKind]^^\n            end\n        end\n    end\nend\n\ndef readRecordH()\n    init()\n    if boardKind == null\n        printf \"*** null board kind\\n\"\n        fail\n    end\n    var rec: Record& = cacheGet(boardKind)\n    return rec if rec\n    var baseLoc: string = ^em$find(baseFileLoc)\n    var baseDb: ptr_t = ^^$Yaml.load($Fs.readFileSync(baseLoc), 'utf-8')^^\n    if localFileLoc != null\n        var localDb: ptr_t = ^^$Yaml.load($Fs.readFileSync(localFileLoc), 'utf-8')^^\n        mergeDb(baseDb, localDb)                    \n    end\n    var set: ptr_t = ^^new Set^^\n    var base: ptr_t = collapse(boardKind, baseDb, set)\n    var chain: ptr_t = ^^Array.from(set.values()).join('--')^^\n    ^^em$props.set^^(PROP_BOARD_CHAIN, chain)\n    rec = new <Record>\n    rec.pinMap = new <PinMap>\n    for a in attrs\n        ^^rec[a] = base[a]^^\n    end\n    for p in pins\n        ^^rec.pinMap[p] = base.pins[p]^^\n    end\n    ^^for (n in base.drvDescs) {^^\n        ^^var o = base.drvDescs[n]^^\n        rec.drvDescs[rec.drvDescs.length++] = new <DrvDesc> {\n            name: ^n, driver: ^^o.driver^^, params: ^^o.params^^\n        }\n    ^^}^^\n    cacheSet(boardKind, rec)\n    return rec\nend\n
"},{"location":"cargo/em.core/em.utils/BoardMeta/","title":"BoardMeta","text":""},{"location":"cargo/em.core/em.utils/BoardMeta/#unit-boardmeta","title":"unit BoardMeta","text":"em.utils/BoardMeta.em
package em.utils\n\nhost module BoardMeta\n\n    type PinMap: struct\n        pin: int8\n    end\n\n    type DrvDesc: struct\n        name: string\n        driver: string\n        params: ptr_t\n    end        \n\n    type Record: struct\n        attr: bool\n        pinMap: PinMap&\n        drvDescs: DrvDesc&[]\n    end\n\n    config baseFileLoc: string = \"biz.biosbob.distro.axm0f343/em-boards\"\n\n    config attrNames: string[] = [\n        \"$inherits\",\n        \"$overrides\",\n        \"attr\",\n    ]\n\n    config pinNames: string[] = [\n        \"pin\",\n    ] \n\nend\n
"},{"location":"cargo/em.core/em.utils/Bootup/","title":"Bootup","text":""},{"location":"cargo/em.core/em.utils/Bootup/#unit-bootup","title":"unit Bootup","text":"em.utils/Bootup.em
package em.utils\n\nmodule Bootup\n\n    type Fxn: function()\n\n    host function addFxnH(fxn: Fxn)\n\n    function exec()\n\nprivate:\n\n    config FXNTAB: Fxn volatile[]\n    config fxnCnt: uint8\n\nend\n\ndef em$construct()\n    FXNTABootMemory = true\nend\n\ndef addFxnH(fxn)\n    FXNTAB[fxnCnt++] = fxn\nend\n\ndef exec()\n    for auto i = 0; i < fxnCnt; i++\n        FXNTAB[i]()\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/BufPrint/","title":"BufPrint","text":""},{"location":"cargo/em.core/em.utils/BufPrint/#unit-bufprint","title":"unit BufPrint","text":"em.utils/BufPrint.em
package em.utils\n\nmodule BufPrint\n\n    config enabled: bool\n\n    function bswap(ptr: ptr_t, cnt: uint16, lab: string = null)\n    function bytes(ptr: ptr_t, cnt: uint16, lab: string = null)\n    function words(ptr: ptr_t, cnt: uint16, lab: string = null)\n\nprivate:\n\n    function label(lab: string)\n\nend\n\ndef bswap(ptr, cnt, lab)\n    if enabled\n        label(lab) if lab\n        printf \"[\"\n        auto pb = <uint8*>ptr\n        auto wc = ((cnt + 0x3) & ~0x3) / 4\n        auto sep = \"\"\n        while wc--\n            printf \"%s\", sep\n            sep = \", \"\n            var buf: uint8[4]\n            buf[0] = *pb++\n            buf[1] = *pb++\n            buf[2] = *pb++\n            buf[3] = *pb++\n            auto nb = cnt >= 4 ? 4 : cnt\n            cnt -= nb\n            auto idx = 3\n            while nb--\n                printf \"%02x\", buf[idx--]\n            end\n        end\n        printf \"]\\n\"\n    end\nend\n\ndef bytes(ptr, cnt, lab)\n    if enabled\n        label(lab) if lab\n        auto pb = <uint8*>ptr\n        while cnt--\n            printf \"%02x\", *pb++\n        end\n        printf \"\\n\"\n    end\nend\n\ndef label(lab)\n    printf \"%s = \", lab\nend\n\ndef words(ptr, cnt, lab)\n    if enabled\n        label(lab) if lab\n        printf \"[\"\n        auto pw = <uint32*>ptr\n        auto sep = \"\"\n        while cnt--\n            printf \"%s%08x\", sep, *pw++\n            sep = \", \"\n        end\n        printf \"]\\n\"\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/ButtonT/","title":"ButtonT","text":""},{"location":"cargo/em.core/em.utils/ButtonT/#unit-buttont","title":"unit ButtonT","text":"em.utils/ButtonT.em
package em.utils\n\ntemplate ButtonT\n\nend\n\ndef em$generateUnit(pn, un)\n|->>>\n    ## ---- generated by em.utils/ButtonT ---- ##\n    package `pn`\n\n    from em.hal import ButtonI\n    from em.hal import GpioEdgeDetectMinI\n\n    from em.mcu import Poller\n\n    from em.utils import FiberMgr\n\n    module `un`: ButtonI\n        #   ^| implements the ButtonI interface\n        proxy Edge: GpioEdgeDetectMinI\n        #   ^| a GPIO with edge-detection capabilities\n    private:\n\n        function buttonHandler: Edge.Handler\n        function debounceFB: FiberMgr.FiberBodyFxn\n\n        config debounceF: FiberMgr.Fiber&\n\n        var curDuration: uint16\n        var curCb: OnPressedCB\n        var maxDur: uint16\n        var minDur: uint16\n\n    end\n\n    def em$construct()\n        Edge.setDetectHandlerH(buttonHandler)\n        debounceF = FiberMgr.createH(debounceFB)\n    end \n\n    def em$startup()\n        Edge.makeInput()\n        Edge.setInternalPullup(true)\n        Edge.setDetectFallingEdge()\n    end\n\n    def buttonHandler()\n        Edge.clearDetect()\n        debounceF.post() if curCb\n    end\n\n    def debounceFB(arg)\n        curDuration = 0\n        for ;;\n            Poller.pause(minDur)\n            return if curDuration == 0 && !isPressed()\n            curDuration += minDur\n            break if !isPressed() || curDuration >= maxDur\n        end\n        curCb()\n    end\n\n    def isPressed()\n        return !Edge.get()\n    end\n\n    def onPressed(cb, minDurationMs, maxDurationMs)\n        curCb = cb\n        maxDur = maxDurationMs\n        minDur = minDurationMs\n        if cb == null\n            Edge.disableDetect()\n        else\n            Edge.enableDetect()\n        end\n    end\n|-<<<\nend\n
"},{"location":"cargo/em.core/em.utils/Checksum/","title":"Checksum","text":""},{"location":"cargo/em.core/em.utils/Checksum/#unit-checksum","title":"unit Checksum","text":"em.utils/Checksum.em
package em.utils\n\n# Fletcher-16 checksum\n\nmodule Checksum\n\n    type Obj: opaque\n        function addData(buf: uint8*, len: uint16)\n        function clear()\n        function getSum8(): uint8\n        function getSum16(): uint16\n    end\n\nprivate:\n\n    def opaque Obj\n        sum1: uint16\n        sum2: uint16\n    end\n\nend\n\ndef Obj.addData(ptr, len)\n    auto tl = <uint8>0\n    while len\n        tl = len >= 20 ? 20 : len\n        len -= tl\n        for ;;\n            this.sum2 += this.sum1 += *ptr++\n            tl -= 1\n            break if tl == 0\n        end\n        this.sum1 = (this.sum1 & 0xFF) + (this.sum1 >> 8)\n        this.sum2 = (this.sum2 & 0xFF) + (this.sum2 >> 8)\n    end\n    this.sum1 = (this.sum1 & 0xFF) + (this.sum1 >> 8)\n    this.sum2 = (this.sum2 & 0xFF) + (this.sum2 >> 8)\n#/*\n    for i: uint16 = 0; i < len; i++\n        this.sum1 += *ptr++\n        this.sum1 -= 255 if this.sum1 >= 255;\n        this.sum2 += this.sum1;\n        this.sum2 -= 255 if this.sum2 >= 255;\n    end\n#*/    \nend\n\ndef Obj.clear()\n    this.sum1 = this.sum2 = 0xFF\nend\n\ndef Obj.getSum8()\n    return <uint8>(this.sum1 ^ this.sum2)\nend\n\ndef Obj.getSum16()\n    return this.sum2 << 8 | this.sum1\nend\n
"},{"location":"cargo/em.core/em.utils/ConsoleProtocol/","title":"ConsoleProtocol","text":""},{"location":"cargo/em.core/em.utils/ConsoleProtocol/#unit-consoleprotocol","title":"unit ConsoleProtocol","text":"em.utils/ConsoleProtocol.em
package em.utils\n\nmodule ConsoleProtocol\n\n    const SOT_BYTE: uint8 = 0x3\n    const SOT_COUNT: uint8 = 13\n\n    const EOT_BYTE: uint8 = 0x4\n\nend\n
"},{"location":"cargo/em.core/em.utils/Copier/","title":"Copier","text":""},{"location":"cargo/em.core/em.utils/Copier/#unit-copier","title":"unit Copier","text":"em.utils/Copier.em
package em.utils\n\nfrom em.hal import CopierI\n\nmodule Copier: CopierI\n\nend\n\ndef exec(dst, src, cnt)\n    ^memcpy(dst, src, cnt)\nend\n
"},{"location":"cargo/em.core/em.utils/Crc16/","title":"Crc16","text":""},{"location":"cargo/em.core/em.utils/Crc16/#unit-crc16","title":"unit Crc16","text":"em.utils/Crc16.em
package em.utils\n\nmodule Crc16\n\n    type Obj: opaque\n        function addByte(b: uint8): uint8\n        function addData(src: uint8*, len: uint8)\n        function getSum(): uint16\n        function getSumLsb(): uint8\n        function getSumMsb(): uint8\n        function init()\n    end\n\n    host function createH(): Obj&\n\nprivate:\n\n    const POLY: uint16 = 0x8005\n\n    def opaque Obj\n        sum: uint16\n        function update(b: uint8)\n    end\n\nend\n\ndef createH()\n    return new<Obj>\nend\n\ndef Obj.addByte(b)\n    this.update(b)\n    return b\nend\n\ndef Obj.addData(src, len)\n    while len--\n        this.update(*src++)\n    end\nend\n\ndef Obj.getSum()\n    return this.sum\nend\n\ndef Obj.getSumLsb()\n    return <uint8>(this.sum & 0xFF)\nend\n\ndef Obj.getSumMsb()\n    return <uint8>(this.sum >> 8)\nend\n\ndef Obj.init()\n    this.sum = 0xFFFF\nend\n\ndef Obj.update(b)\n    auto tot = this.sum\n    for auto i = 0; i < 8; i++\n        if ((tot & 0x8000) >> 8) ^ (b & 0x80)\n            tot = (tot << 1) ^ POLY\n        else\n            tot = (tot << 1)\n        end\n        b <<= 1\n    end\n    this.sum = tot\nend\n
"},{"location":"cargo/em.core/em.utils/DebugPinAux/","title":"DebugPinAux","text":""},{"location":"cargo/em.core/em.utils/DebugPinAux/#unit-debugpinaux","title":"unit DebugPinAux","text":"em.utils/DebugPinAux.em
package em.utils\n\nfrom em.mcu import Common\n\nmodule DebugPinAux\n\n    type ToggleFxn: function()\n\n    config pulseDelay: int32 = -1\n\n    function pulse(toggleFxn: ToggleFxn)\n    function mark(toggleFxn: ToggleFxn, k: uint8)\n\nprivate:\n\n    function delay()\n\nend\n\ndef delay()\n    ## TODO -- finer granularity\n    Common.BusyWait.wait(<uint32>(-pulseDelay))\nend\n\ndef pulse(toggleFxn)\n    toggleFxn()\n    delay()\n    toggleFxn()\n    delay()\n\nend\n\ndef mark(toggleFxn, k)\n    while k--\n        pulse(toggleFxn)\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/DebugPinT/","title":"DebugPinT","text":""},{"location":"cargo/em.core/em.utils/DebugPinT/#unit-debugpint","title":"unit DebugPinT","text":"em.utils/DebugPinT.em
package em.utils\n\ntemplate DebugPinT\n\nend\n\ndef em$generateUnit(pn, un)\n|->>>\npackage `pn`\n\nfrom em.utils import DebugPinAux as Aux\nfrom em.lang import DebugPinI\nfrom em.hal import GpioI\n\nmodule `un`: DebugPinI\n\n    proxy Pin: GpioI\n\nend\n\ndef clear()\n    Pin.set()\nend\n\ndef get()\n    return Pin.get() != 0\nend\n\ndef set()\n    Pin.clear()\nend\n\ndef toggle()\n    Pin.toggle()\nend\n\ndef pulse()\n    Aux.pulse(<Aux.ToggleFxn>toggle)\nend\n\ndef mark(k)\n    Aux.mark(<Aux.ToggleFxn>toggle, k)\nend\n\ndef reset()\n    Pin.reset()\nend\n\ndef startup()\n    Pin.makeOutput()\n    Pin.set()\nend\n|-<<<\nend\n
"},{"location":"cargo/em.core/em.utils/EpochTime/","title":"EpochTime","text":""},{"location":"cargo/em.core/em.utils/EpochTime/#unit-epochtime","title":"unit EpochTime","text":"em.utils/EpochTime.em
package em.utils\n\nfrom em.hal import UptimerI\n\nmodule EpochTime\n\n    proxy Uptimer: UptimerI\n\n    type UpdateFxn: function(esecs: uint32, esubs: uint32)\n\n    host function bindUpdateFxnH(fxn: UpdateFxn)\n\n    function getCurrent(oSubs: uint32* = null): uint32\n    function getRaw(oSubs: uint32* = null): uint32\n    function mkSecs256(secs: uint32, subs: uint32): uint32\n    function setCurrent(eSecs: uint32, eSubs: uint32 = 0, syncFlag: bool = false)\n\nprivate:\n\n    config updateFxn: UpdateFxn\n\n    var deltaSecs: uint32\n    var deltaSubs: uint32\n\n    var lastSecs256: uint32\n    var lastTicks: uint32\n\n    function compute(time: Uptimer.Time&, oSubs: uint32*): uint32\n\nend\n\ndef bindUpdateFxnH(fxn)\n    updateFxn = fxn\nend\n\ndef compute(time, oSubs)\n    auto eSubs = time.subs + deltaSubs\n    auto inc = eSubs < time.subs ? 1 : 0\n    (*oSubs) = eSubs if oSubs\n    return time.secs + deltaSecs + inc\nend\n\ndef getCurrent(oSubs)\n    return compute(Uptimer.read(), oSubs)\nend\n\ndef getRaw(oSubs)\n    auto time = Uptimer.read()\n    *oSubs = time.subs if oSubs\n    return time.secs\nend\n\ndef mkSecs256(secs, subs)\n    return (secs << 8) | (subs >> 24)\nend\n\ndef setCurrent(eSecs, eSubs, syncFlag)\n    auto time = Uptimer.read()\n    deltaSubs = eSubs - time.subs\n    auto dec = deltaSubs > eSubs ? 1 : 0\n    deltaSecs = eSecs - time.secs - dec\n    auto eSecs256 = mkSecs256(eSecs, eSubs)\n    if syncFlag\n        Uptimer.calibrate(eSecs256 - lastSecs256, time.ticks - lastTicks) if lastSecs256\n        lastSecs256 = eSecs256\n        lastTicks = time.ticks\n    else\n        lastSecs256 = lastTicks = 0\n    end\n    var subs: uint32\n    auto secs = compute(time, &subs)\n    updateFxn(eSecs, eSubs) if updateFxn\nend\n
"},{"location":"cargo/em.core/em.utils/Error/","title":"Error","text":""},{"location":"cargo/em.core/em.utils/Error/#unit-error","title":"unit Error","text":"em.utils/Error.em
package em.utils\n\nimport Logger\n\nmodule Error\n\n    type Kind: enum\n        APPLICATION, ASSERTION, EXCEPTION, EXPIRATION, WATCHDOG\n    end\n\n    type RaiseFxn: function (kind: Kind, infoA: iarg_t, infoB: iarg_t)\n\n    host function bindOnRaiseH(fxn: RaiseFxn)\n    function raise: RaiseFxn\n\nprivate:\n\n    config KIND_ATOM: atom_t[] = [\n        @\"APPLICATION\", @\"ASSERTION\", @\"EXCEPTION\", @\"EXPIRATION\", @\"WATCHDOG\"\n    ]\n\n    config errorE: Logger.EventKind&\n    config onRaiseFxn: RaiseFxn\n\nend\n\ndef em$construct()\n    ## TODO -- atomize error kind\n    errorE = Logger.declareEventH(\"ERROR: $a [0x%08x, 0x%08x]\", \"*--*\")\nend\n\ndef bindOnRaiseH(fxn)\n    onRaiseFxn = fxn\nend\n\ndef raise(kind, infoA, infoB)\n    errorE.log(<addr_t>KIND_ATOM[<uint8>kind], <addr_t>infoA, <addr_t>infoB)\n    onRaiseFxn(kind, infoA, infoB) if onRaiseFxn\nend\n
"},{"location":"cargo/em.core/em.utils/FftC32/","title":"FftC32","text":""},{"location":"cargo/em.core/em.utils/FftC32/#unit-fftc32","title":"unit FftC32","text":"em.utils/FftC32.em
package em.utils\n\nfrom em.lang import Math\n\nmodule FftC32\n\n    type Complex: class\n        re: int16\n        im: int16\n        function get(): uint32\n        function set(w: uint32)\n    end\n\n    config fftSize: uint16 = 128\n    config shift: uint8 = 1\n\n    function exec(buf: Complex[])\n\nprivate:\n\n    config N_WAVE: uint16\n    config N_WAVE_LOG2: uint8\n\n    config SINE_WAVE: int16[]\n\n    function fixMul(a: int16, b: int16): int16\n\nend\n\ndef em$construct()\n    N_WAVE = fftSize\n    N_WAVE_LOG2 = Math.log2(N_WAVE)\n    auto numHalf = N_WAVE / 2\n    auto numQtr = N_WAVE / 4\n    SINE_WAVE.length = N_WAVE - numQtr\n    auto rng = Math.PI / 2\n    for auto i = 0; i < SINE_WAVE.length; i++\n        if i <= numQtr\n            auto sx = Math.sin((rng / numQtr) * i)\n            SINE_WAVE[i] = Math.round(sx * 32767) >> shift\n        elif i < numHalf\n            SINE_WAVE[i] = SINE_WAVE[numHalf - i]\n        else\n            SINE_WAVE[i] = -(SINE_WAVE[i - numHalf])\n        end\n    end\nend\n\ndef exec(buf)\n    auto mr = 0\n    for auto m = 1; m < fftSize; m++\n        auto l = fftSize\n        for ;;\n            l >>= 1\n            continue if mr + l > fftSize - 1\n            break\n        end\n        mr = (mr & (l - 1)) + l\n        continue if mr <= m\n        auto t = buf[m].get()\n        buf[m].set(buf[mr].get())\n        buf[mr].set(t)\n    end\n    auto stage = 1\n    auto sineStep = N_WAVE_LOG2 - 1\n    while stage < fftSize\n        auto twiddleStep = stage << 1\n        for auto grp = 0; grp < stage; grp++\n            auto idx = grp << sineStep\n            auto wr = SINE_WAVE[idx + N_WAVE / 4]\n            auto wi = -SINE_WAVE[idx]\n            for auto i = grp; i < fftSize; i += twiddleStep\n                auto j = i + stage\n                auto fci = &buf[i]\n                auto fcj = &buf[j]\n                auto tr = fixMul(wr, fcj.re) - fixMul(wi, fcj.im)\n                auto ti = fixMul(wr, fcj.im) + fixMul(wi, fcj.re)\n                auto qr = fci.re >> shift\n                auto qi = fci.im >> shift\n                fcj.re = qr - tr\n                fcj.im = qi - ti\n                fci.re = qr + tr\n                fci.im = qi + ti\n            end\n        end\n        sineStep -= 1\n        stage = twiddleStep\n    end\nend\n\n\ndef fixMul(a, b)\n    auto c = (<int32>a * <int32>b) >> 14\n    b = <int16>(<uint32>c & 0x01)\n    a = <int16>((c >> 1) + b)\n    return a\nend\n\ndef Complex.get()\n    return *(<uint32*>this)\nend\n\ndef Complex.set(w)\n    *(<uint32*>this) = w\nend\n
"},{"location":"cargo/em.core/em.utils/FftQ15/","title":"FftQ15","text":""},{"location":"cargo/em.core/em.utils/FftQ15/#unit-fftq15","title":"unit FftQ15","text":"em.utils/FftQ15.em
package em.utils\n\nfrom em.lang import Math\n\nmodule FftQ15\n\n    config fftSize: uint16 = 128\n    config shift: uint8 = 1\n\n    function exec(fr: int16[], fi: int16[])\n\nprivate:\n\n    config N_WAVE: uint16\n    config N_WAVE_LOG2: uint8\n\n    config SINE_WAVE: int16[]\n\n    function fixMul(a: int16, b: int16): int16\n\nend\n\ndef em$construct()\n    N_WAVE = fftSize\n    N_WAVE_LOG2 = Math.log2(N_WAVE)\n    auto numHalf = N_WAVE / 2\n    auto numQtr = N_WAVE / 4\n    SINE_WAVE.length = N_WAVE - numQtr\n    auto rng = Math.PI / 2\n    for auto i = 0; i < SINE_WAVE.length; i++\n        if i <= numQtr\n            auto sx = Math.sin((rng / numQtr) * i)\n            SINE_WAVE[i] = Math.round(sx * 32767) >> shift\n        elif i < numHalf\n            SINE_WAVE[i] = SINE_WAVE[numHalf - i]\n        else\n            SINE_WAVE[i] = -(SINE_WAVE[i - numHalf])\n        end\n    end\nend\n\ndef exec(fr, fi)\n    auto mr = 0\n    for auto m = 1; m < fftSize; m++\n        auto l = fftSize\n        for ;;\n            l >>= 1\n            continue if mr + l > fftSize - 1\n            break\n        end\n        mr = (mr & (l - 1)) + l\n        continue if mr <= m\n        auto tr = fr[m]\n        fr[m] = fr[mr]\n        fr[mr] = tr\n        auto ti = fi[m]\n        fi[m] = fi[mr]\n        fi[mr] = ti\n    end\n    auto stage = 1\n    auto sineStep = N_WAVE_LOG2 - 1\n    while stage < fftSize\n        auto twiddleStep = stage << 1\n        for auto grp = 0; grp < stage; grp++\n            auto idx = grp << sineStep\n            auto wr = SINE_WAVE[idx + N_WAVE / 4]\n            auto wi = -SINE_WAVE[idx]\n            for auto i = grp; i < fftSize; i += twiddleStep\n                auto j = i + stage\n                auto tr = fixMul(wr, fr[j]) - fixMul(wi, fi[j])\n                auto ti = fixMul(wr, fi[j]) + fixMul(wi, fr[j])\n                auto qr = fr[i] >> shift\n                auto qi = fi[i] >> shift\n                fr[j] = qr - tr\n                fi[j] = qi - ti\n                fr[i] = qr + tr\n                fi[i] = qi + ti\n            end\n        end\n        sineStep -= 1\n        stage = twiddleStep\n    end\nend\n\ndef fixMul(a, b)\n    auto c = (<int32>a * <int32>b) >> 14\n    b = <int16>(<uint32>c & 0x01)\n    a = <int16>((c >> 1) + b)\n    return a\nend\n
"},{"location":"cargo/em.core/em.utils/FiberMgr/","title":"FiberMgr","text":""},{"location":"cargo/em.core/em.utils/FiberMgr/#unit-fibermgr","title":"unit FiberMgr","text":"em.utils/FiberMgr.em
package em.utils\n\nfrom em.mcu import Common\nfrom em.utils import ListMgr\n\nmodule FiberMgr\n            #   ^| manages opaque fiber objects\n    type FiberBodyFxn: function(arg: uarg_t)\n            #   ^| function signature of fiber body\n    type Fiber: opaque\n            #   ^| opaque fiber object - public specification\n        host function initH(fxn: FiberBodyFxn, arg: uarg_t = 0)\n            #   ^| initialize this fiber and bind its function and argument\n        function getArg(): uarg_t\n            #   ^| get this fiber's body function argument\n        function getFxn(): FiberBodyFxn\n            #   ^| get this fiber's body function\n        function post()\n            #   ^| make this fiber ready-to-run\n        function setArg(a: uarg_t)\n            #   ^| set this fiber's body function argument\n        function setFxn(f: FiberBodyFxn)\n            #   ^| set this fiber's body function\n    end\n\n    host function createH(fxn: FiberBodyFxn, arg: uarg_t = 0): Fiber&\n            #   ^| allocate and initialize a fiber; see Fiber.initH\n    function run()\n            #   ^| initiate dispatch of ready-to-run fibers\nprivate:\n\n    def opaque Fiber\n        elem: ListMgr.Element\n        fxn_: FiberBodyFxn\n        arg_: uarg_t\n    end\n\n    function dispatch()\n\n    var fiberTab: Fiber[]\n    var readyList: ListMgr.List\n\nend\n\ndef em$construct() \n    readyList.initH()\nend\n\ndef createH(fxn, arg)\n    var fiber: Fiber& = fiberTab[fiberTab.length++]\n    fiber.initH(fxn, arg)\n    return fiber\nend\n\ndef dispatch()\n    for ;;\n        break if readyList.hasElements() == 0\n        auto fiber = <Fiber&>readyList.get()\n        Common.GlobalInterrupts.enable()\n        auto fxn = fiber.fxn_\n        fxn(fiber.arg_)\n        Common.GlobalInterrupts.disable()\n    end   \nend\n\ndef run()\n    Common.Idle.wakeup()\n    Common.GlobalInterrupts.enable()\n    for ;;\n        Common.GlobalInterrupts.disable()\n        dispatch()\n        Common.Idle.exec()\n    end\nend\n\ndef Fiber.initH(fxn, arg)\n    this.elem.initH()\n    this.fxn_ = fxn\n    this.arg_ = arg\nend\n\ndef Fiber.post()\n    auto key = Common.GlobalInterrupts.disable()\n    readyList.add(this.elem) if !this.elem.isActive()\n    Common.GlobalInterrupts.restore(key)\nend\n\ndef Fiber.getArg()\n    return this.arg_\nend\n\ndef Fiber.setArg(a)\n    this.arg_ = a\nend\n\ndef Fiber.setFxn(f)\n    this.fxn_ = f\nend\n\ndef Fiber.getFxn()\n    return this.fxn_\nend\n
"},{"location":"cargo/em.core/em.utils/Formatter/","title":"Formatter","text":""},{"location":"cargo/em.core/em.utils/Formatter/#unit-formatter","title":"unit Formatter","text":"em.utils/Formatter.em
package em.utils\n\nfrom em.lang import Console\n\nmodule Formatter\n\n    function print(fmt: string, a1: iarg_t = 0, a2: iarg_t = 0, a3: iarg_t = 0, a4: iarg_t = 0, a5: iarg_t = 0, a6: iarg_t = 0)\n    function puts(s: string)\n\nprivate:\n\n    const OUTMAX: uint8 = ((32 + 2) / 3) + 5\n\n    function c2d(c: char): uint8\n    function formatNum(buf: char*, num: uint32, base: uint8, pad: char, len: uint8): char*\n    function isDigit(c: char): bool\n\n    config hexDigs: string = \"0123456789abcdef\"\n\nend\n\ndef c2d(c)\n    return c - '0'\nend\n\ndef formatNum(buf, num, base, pad, len)\n    auto cnt = len\n    *(--buf) = 0\n    for ;;\n        *(--buf) = hexDigs[<uint8> (num % base)]\n        num /= base\n        break if len > 0 && --cnt == 0\n        break if num == 0\n    end\n    while cnt-- > 0\n        *(--buf) = pad\n    end\n    return buf\nend\n\ndef isDigit(c)\n    return c >= '0' && c <= '9'\nend\n\ndef print(fmt, a1, a2, a3, a4, a5, a6)\n    var ch: char\n    var buf: char[OUTMAX]\n    var args: iarg_t[6]\n    var argp: iarg_t* = &args[0]\n    args[0] = a1\n    args[1] = a2\n    args[2] = a3\n    args[3] = a4\n    args[4] = a5\n    args[5] = a6\n    while (ch = *fmt++) != 0\n        auto pad = ' '\n        auto len = 0\n        if (ch != '%') \n            Console.wrC(ch)\n            continue\n        end\n        ch = *fmt++\n        if ch == '0'\n            pad = '0'\n            ch = *fmt++\n            end\n        while isDigit(ch)\n            len = (len * 10) + c2d(ch)\n            ch = *fmt++\n            end\n        var out: char*\n        if ch == 'd'\n            var dn: int32 = <int32> *argp++\n            if dn < 0\n                Console.wrC('-')\n                dn = -dn\n            end\n            out = formatNum(&buf[OUTMAX], <uint32> dn, 10, pad, len)\n        elif ch == 'x' \n            var xn: uint32 = <uint32> *argp++\n            out = formatNum(&buf[OUTMAX], xn, 16, pad, len)\n        elif ch == 's'\n            out = <char*> *argp++\n        else\n            Console.wrC(ch == 'c' ? <char> *argp++ : ch)\n            continue\n        end\n        puts(<string>out)\n    end\nend\n\ndef puts(s)\n    var cp: char* = <char*>s\n    var ch: char\n    while (ch = *cp++) != 0\n        Console.wrC(ch)\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/FormattingConsole/","title":"FormattingConsole","text":""},{"location":"cargo/em.core/em.utils/FormattingConsole/#unit-formattingconsole","title":"unit FormattingConsole","text":"em.utils/FormattingConsole.em
package em.utils\n\nfrom em.lang import ConsoleProviderI\n\nfrom em.mcu import ConsoleUart\n\nimport Formatter\n\nmodule FormattingConsole: ConsoleProviderI\n\nend\n\ndef flush()\n    ConsoleUart.flush()\nend\n\ndef print(fmt, a1, a2, a3, a4, a5, a6)\n    Formatter.print(fmt, a1, a2, a3, a4, a5, a6)\nend\n\ndef put(data)\n    ConsoleUart.put(data)\nend\n
"},{"location":"cargo/em.core/em.utils/HeapMem/","title":"HeapMem","text":""},{"location":"cargo/em.core/em.utils/HeapMem/#unit-heapmem","title":"unit HeapMem","text":"em.utils/HeapMem.em
package em.utils\n\nfrom em.mcu import Common\nfrom em.mcu import Copier\n\nmodule HeapMem\n\n    config baseAddr: addr_t\n    config maxBytes: uint16\n\n    function alloc(size: uint16): ptr_t\n    function avail(): uint16\n    function mark()\n    function release()\n\nprivate:\n\n    var curTopPtr: uint32*\n    var savTopPtr: uint32*\n\nend\n\ndef em$startup()\n    return if Common.Mcu.isWarm()\n    curTopPtr = baseAddr\nend\n\ndef alloc(size)\n    auto ptr = curTopPtr\n    auto wc = ((size + 3) & ~0x3) / 4\n    curTopPtr += wc\n    return ptr\nend\n\ndef avail()\n    return <uint16>((baseAddr + maxBytes) - <uint32>curTopPtr)\nend\n\ndef mark()\n    *curTopPtr = <uint32>savTopPtr\n    savTopPtr = curTopPtr++\nend\n\ndef release()\n    fail if !savTopPtr\n    curTopPtr = savTopPtr\n    savTopPtr = <uint32*>*curTopPtr\n\n\nend\n
"},{"location":"cargo/em.core/em.utils/HeapStatic/","title":"HeapStatic","text":""},{"location":"cargo/em.core/em.utils/HeapStatic/#unit-heapstatic","title":"unit HeapStatic","text":"em.utils/HeapStatic.em
package em.utils\n\nfrom em.mcu import Common\n\nmodule HeapStatic\n\n    config baseAddr: addr_t\n    config maxBytes: uint16\n\n    host function allocH(size: uint16): ptr_t\n\n    function getTopAddr(): addr_t\n    host function getTopAddrH(): addr_t\n\nprivate:\n\n    const MASK: uint32 = 0x3\n    config topAddr: addr_t\nend\n\ndef em$construct()\n    return if baseAddr || maxBytes == 0\n    printf \"*** HeapStatic:  baseAddr == 0\\n\"\n    fail\nend\n\ndef em$startup()\n    return if Common.Mcu.isWarm()\n    ^memset(<ptr_t>baseAddr, 0, topAddr - baseAddr) if topAddr && Common.Mcu.getResetCode() <= Common.Mcu.COLD_RESET\nend\n\ndef allocH(size)\n    topAddr = baseAddr if topAddr == 0\n    auto p = <ptr_t>topAddr\n    topAddr += size\n    topAddr = (topAddr + MASK) & ~MASK\n    return p if (topAddr - baseAddr) < maxBytes\n    printf \"*** HeapStatic.allocH: maxBytes = %d, size = %d\\n\", maxBytes, size\n    fail\nend\n\ndef getTopAddr()\n    return topAddr\nend\n\ndef getTopAddrH()\n    return topAddr\nend\n
"},{"location":"cargo/em.core/em.utils/LedBlinkerI/","title":"LedBlinkerI","text":""},{"location":"cargo/em.core/em.utils/LedBlinkerI/#unit-ledblinkeri","title":"unit LedBlinkerI","text":"em.utils/LedBlinkerI.em
package em.utils\n\nfrom em.hal import LedI\n\ninterface LedBlinkerI: LedI\n\n    function blink(count: uint16, rateSecs: uint16 = 1, rateMs: uint16 = 0)\n\nend\n
"},{"location":"cargo/em.core/em.utils/LedBlinkerT/","title":"LedBlinkerT","text":""},{"location":"cargo/em.core/em.utils/LedBlinkerT/#unit-ledblinkert","title":"unit LedBlinkerT","text":"em.utils/LedBlinkerT.em
package em.utils\n\ntemplate LedBlinkerT\n\nend\n\ndef em$generateUnit(pn, un)\n|->>>\npackage `pn`\n\nfrom em.hal import LedI\n\nfrom em.utils import LedBlinkerAux\nfrom em.utils import LedBlinkerI\n\nmodule `un`: LedBlinkerI\n\n    proxy Led: LedI\n\nend\n\ndef isOn()\n    return Led.isOn()\nend\n\ndef on()\n    Led.on()\nend\n\ndef off()\n    Led.off()\nend\n\ndef toggle()\n    Led.toggle()\nend\n\ndef blink(count, rateSecs, rateMs)\n    LedBlinkerAux.setFxns(Led.on, Led.off)\n    LedBlinkerAux.blink(count, rateSecs, rateMs)\nend\n\ndef wink(onMs, offMs)\n    LedBlinkerAux.setFxns(Led.on, Led.off)\n    LedBlinkerAux.wink(onMs, offMs)\nend\n|-<<<\nend\n
"},{"location":"cargo/em.core/em.utils/LedT/","title":"LedT","text":""},{"location":"cargo/em.core/em.utils/LedT/#unit-ledt","title":"unit LedT","text":"em.utils/LedT.em
package em.utils\n\ntemplate LedT \n\nend\n\ndef em$generateUnit(pn, un)\n|->>>\n    package `pn`\n\n    from em.hal import LedI\n    from em.hal import GpioI\n\n    from em.mcu import Poller\n\n    module `un`: LedI\n        proxy Pin: GpioI\n        config activeLow: bool = false\n    end\n\n    def em$startup()\n        Pin.makeOutput()\n        if activeLow\n            Pin.set()            \n        else \n            Pin.clear()                \n        end\n    end\n\n    def on()\n        if activeLow\n            Pin.clear()            \n        else \n            Pin.set()                \n        end   \n    end\n\n    def off()\n        if activeLow\n            Pin.set()            \n        else \n            Pin.clear()                \n        end   \n    end\n\n    def toggle()\n        Pin.toggle()\n    end\n\n    def isOn()\n        return activeLow ? !Pin.get() : Pin.get()\n    end\n\n    def wink(msecs)\n        on()\n        Poller.pause(msecs)\n        off()\n    end          \n|-<<<\nend\n
"},{"location":"cargo/em.core/em.utils/ListManagerI/","title":"ListManagerI","text":""},{"location":"cargo/em.core/em.utils/ListManagerI/#unit-listmanageri","title":"unit ListManagerI","text":"em.utils/ListManagerI.em
package em.utils\n\n#! Implemented by a List Manager module\n#! Element and List declarations.\n\ninterface ListManagerI \n\n    type Element: opaque \n\n        #! Target and Host function to initialize an Element\n        function init()\n        host function initH()\n\n        #! Returns non-null if the Element is currently a member of a List\n        function isActive(): uarg_t\n    end\n\n    type List: opaque \n\n        #! Target and Host function to initialize a List\n        function init()\n        host function initH()\n\n        #! Adds an element to the List as defined by the List Manager\n        function add(elem: Element&)\n\n        #! Returns a reference to an Element and removes it from the List\n        function get(): ref_t\n\n        #! Returns a reference to the Element at the specified index\n        function getAt(index: uint8): ref_t\n\n        #! Returns a reference to the next Element from the specified Element\n        function getNext(elem: Element&): ref_t\n\n        #! Returns a non-zero value if the List is not empty\n        function hasElements(): uarg_t\n\n        #! Displays information about the List\n        function print()\n\n        #! Removes the specified Element from the List\n        function remove(elem: Element&)\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/ListMgr/","title":"ListMgr","text":""},{"location":"cargo/em.core/em.utils/ListMgr/#unit-listmgr","title":"unit ListMgr","text":"em.utils/ListMgr.em
package em.utils\n\nmodule ListMgr\n\n    type Element: opaque \n\n        function init()\n        host function initH()\n\n        function isActive(): uarg_t\n    end\n\n    type List: opaque \n\n        function init()\n        host function initH()\n\n        function add(elem: Element&)\n        function get(): ref_t\n        function getAt(index: uint8): ref_t\n        function getNext(elem: Element&): ref_t\n        function hasElements(): uarg_t\n        function print()\n        function remove(elem: Element&)\n    end\n\nprivate:\n\n    def opaque Element \n        next: Element& volatile\n    end\n\n    def opaque List \n        first: Element& volatile\n        last: Element& volatile\n    end\nend\n\ndef Element.init() \n    this.next = null\nend\n\ndef Element.initH() \n    this.next = null\nend\n\ndef Element.isActive() \n    return <uarg_t> this.next\nend\n\ndef List.init() \n    this.first = this.last = <Element&> &this.first\nend\n\ndef List.initH() \n    this.first = this.last = <Element&> &this.first;\nend\n\ndef List.add(elem)\n    this.last.next = elem\n    this.last = elem\n    elem.next = <Element&> this\nend\n\ndef List.get() \n    auto elem = this.first\n    this.last = <Element&>this if (this.first = elem.next) == <Element&>this\n    elem.next = null\n    return elem\nend\n\ndef List.getAt(index)\n    auto elem = this.first\n    auto i = 0\n    if this.hasElements()\n        for ;;\n            break if i++ == index                \n            elem = elem.next                \n            break if elem == <Element&> this\n        end\n        elem = null if elem == <Element&> this\n    else \n        elem = null\n    end\n    return elem\nend\n\ndef List.getNext(elem) \n    return elem == this.last ? null : elem.next\nend\n\ndef List.hasElements() \n    return (<uarg_t> this.first) ^ <uarg_t> this\nend\n\ndef List.print() \n    auto elem = this.first\n    auto i = 0\n    if this.hasElements()\n        for ;;\n            printf \"elem%d %p\\n\", i++, elem\n            elem = elem.next\n            break if elem == <Element&> this\n        end\n    else \n        printf \"list empty\\n\"\n    end\n    printf \"\\n\" \nend\n\ndef List.remove(elem)\n    auto e = this.first\n    if this.hasElements()\n        if elem == this.first\n            this.first = this.first.next\n        else \n            for ;; \n                if e.next == elem\n                    e.next = elem.next                    \n                    break    \n                end \n                break if e == <Element&> this\n            end\n        end\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/LoaderAuxI/","title":"LoaderAuxI","text":""},{"location":"cargo/em.core/em.utils/LoaderAuxI/#unit-loaderauxi","title":"unit LoaderAuxI","text":"em.utils/LoaderAuxI.em
package em.utils\n\ninterface LoaderAuxI\n\n    function jumpTo(codeAddr: addr_t)\n\nend\n
"},{"location":"cargo/em.core/em.utils/Logger/","title":"Logger","text":""},{"location":"cargo/em.core/em.utils/Logger/#unit-logger","title":"unit Logger","text":"em.utils/Logger.em
package em.utils\n\nfrom em.hal import FlashI\nfrom em.hal import FlashN\n\nfrom em.lang import Assert\nfrom em.mcu import Common\nfrom em.lang import Console\n\nimport EpochTime\nimport Formatter\nimport HeapStatic\n\nmodule Logger\n\n    proxy Flash: FlashI\n\n    type Accum: opaque\n        function add(val: uint32 = 0)\n        function clear()\n        function getBin(idx: uint8): uint32\n        function getCount(): uint32\n        function getMax(): uint32\n        function print()\n    end\n\n    type EventKind: opaque\n        function cache(a1: addr_t = 0, a2: addr_t = 0, a3: addr_t = 0)\n        function log(a1: addr_t = 0, a2: addr_t = 0, a3: addr_t = 0)\n        function print(a1: addr_t = 0, a2: addr_t = 0, a3: addr_t = 0)\n    end\n\n    type Policy: enum\n        NIL, QUIET, PRINT, STORE\n    end\n\n    config POLICY: Policy = Policy.NIL\n    config ENTRY_COUNT: uint16 = 16\n    config STORE_SECTOR: uint8 = 0\n\n    host function createAccumH(lab: string, grp: string, lims: uint32[] = null): Accum&\n    host function declareEventH(msg: string, grp: string): EventKind&\n\n    function flush()\n    function isEmpty(): bool\n    function mkTime(): uint32\n    function print()\n    function putBytes(bp: uint8*, cnt: uint16)\n    function putc(b: uint8)\n    function store()\n\nprivate:\n\n    const PKT_CODE: uint8 = 0xFE\n    const EVT_CODE: uint8 = 0xFD\n    const ACC_CODE: uint8 = 0xFC\n    const BEG_CODE: uint8 = 0xFB\n    const END_CODE: uint8 = 0xFA\n\n    type Group: class\n        chars: char[4]\n        host function initH(gs: string)\n    end\n\n    def opaque Accum\n        data: uint32[]\n        metaIdx: uint8\n        function getMeta(): AccumMeta&\n    end\n\n    type AccumMeta: struct\n        lab: string\n        lims: uint32[]\n        hasMax: bool\n        limCnt: uint8\n        group: Group\n        size: uint8\n    end\n\n    def opaque EventKind\n        msg: string\n        kidx: uint16\n        group: Group\n    end\n\n    type EventInst: class\n        time: uint32\n        a1: iarg_t\n        a2: iarg_t\n        a3: iarg_t\n        kidx: uint16\n        function put()\n    end\n\n    type Cursor: class\n        idx: uint16\n        function next(): EventInst&\n    end\n\n    config accMetaTab: AccumMeta[]\n\n    config sectBeg: addr_t\n    config sectEnd: addr_t\n\n    config totalAccSize: uint16\n\n    var accTab: Accum&[..]\n    var evkTab: EventKind&[..]\n\n    var buf: EventInst[]\n    var curs: Cursor&\n\nend\n\ndef em$configure()\n    Flash ?= FlashN\nend\n\ndef em$construct()\n    buf = HeapStatic.allocH(sizeof<EventInst> * ENTRY_COUNT) if POLICY != Policy.NIL\n    curs = HeapStatic.allocH(sizeof<Cursor>) if POLICY != Policy.NIL\n    sectBeg = <addr_t>(Flash.getSectorSizeH() * STORE_SECTOR)\n    sectEnd = sectBeg + Flash.getSectorSizeH()\n end\n\ndef createAccumH(lab, grp, lims)\n    return null if POLICY == Policy.NIL\n    auto accMeta = <AccumMeta&>accMetaTab[accMetaTab.length++]\n    accMeta.lab = lab\n    accMeta.group.initH(grp)\n    accMeta.hasMax = (lims != null)\n    accMeta.lims = lims if accMeta.hasMax\n    accMeta.limCnt = <uint8>lims.length if accMeta.hasMax\n    accMeta.size = (1 + (!accMeta.hasMax ? 0 : (1 + accMeta.limCnt))) * sizeof<uint32>\n    auto acc = new<Accum>\n    accTab[accTab.length++] = acc\n    acc.data = HeapStatic.allocH(accMeta.size)\n    acc.metaIdx = <uint8>accMetaTab.length\n    totalAccSize += accMeta.size\n    return acc\nend\n\ndef declareEventH(msg, grp)\n    return null if POLICY == Policy.NIL\n    auto ek = new<EventKind>\n    evkTab[evkTab.length++] = ek\n    ek.kidx = evkTab.length\n    ek.msg = <string>msg\n    ek.group.initH(grp)\n    return ek\nend\n\ndef flush()\n    print() if POLICY == Policy.PRINT\n    store() if POLICY == Policy.QUIET || POLICY == Policy.STORE\nend\n\ndef isEmpty()\n    if POLICY != Policy.NIL\n        for acc in accTab\n            return false if acc.data[0]\n        end\n        for auto i = 0; i < ENTRY_COUNT; i++\n            return false if buf[i].kidx != 0\n        end\n    end\n    return true\nend\n\ndef mkTime()\n    var subs: uint32\n    auto secs = EpochTime.getRaw(&subs)\n    return (secs << 8) | (subs >> 24)\nend\n\ndef print()\n    if POLICY > Policy.QUIET\n        putc(PKT_CODE)\n        putc(BEG_CODE)\n        for acc in accTab\n            acc.print()\n        end\n        for auto i = 0; i < ENTRY_COUNT; i++\n            auto evt = curs.next()\n            continue if evt.kidx == 0\n            evt.put()\n        end\n        putc(PKT_CODE)\n        putc(END_CODE)\n    end\nend\n\ndef putBytes(bp, cnt)\n    while cnt--\n        auto b = *bp++\n        putc(PKT_CODE) if b == PKT_CODE\n        putc(b)\n    end\nend\n\ndef putc(b)\n    Console.Provider.put(b)\nend\n\ndef store()\n    if POLICY != Policy.NIL && STORE_SECTOR > 0\n        auto saddr = sectBeg\n        Flash.erase(saddr)\n        var et: uint32 = EpochTime.getCurrent()\n        saddr = Flash.write(saddr, &et, sizeof<uint32>)\n        for acc in accTab\n            saddr = Flash.write(saddr, &acc.data[0], acc.getMeta().size)\n        end\n        for auto i = 0; i < ENTRY_COUNT; i++\n            auto evt = curs.next()\n            continue if evt.kidx == 0\n            saddr = Flash.write(saddr, evt, sizeof<EventInst>)\n            evt.kidx = 0\n        end\n    end\nend\n\ndef Accum.add(val)\n    auto accMeta = this.getMeta()\n    this.data[0] += 1\n    return if !accMeta.hasMax\n    this.data[1] = val if val > this.data[1]\n    for auto i = 0; i < accMeta.limCnt; i++\n        this.data[2 + i] += 1 if val < accMeta.lims[i]\n    end\nend\n\ndef Accum.clear()\n    auto accMeta = this.getMeta()\n    auto words = accMeta.hasMax ? (2 + accMeta.limCnt) : 1\n    ^memset(&this.data[0], 0, words * sizeof<uint32>)\nend\n\ndef Accum.getBin(idx)\n    return this.data[idx + 2]\nend\n\ndef Accum.getCount()\n    return this.data[0]\nend\n\ndef Accum.getMax()\n    return this.data[1]\nend\n\ndef Accum.getMeta()\n    return <AccumMeta&>(&accMetaTab[this.metaIdx-1])\nend\n\ndef Accum.print()\n    if POLICY > Policy.QUIET\n        auto accMeta = this.getMeta()\n        putc(PKT_CODE)\n        putc(ACC_CODE)\n        putc(this.metaIdx)\n        putBytes(<uint8*>&this.data[0], accMeta.size)\n    end\nend\n\ndef Cursor.next()\n    auto evt = &buf[this.idx++]\n    this.idx = 0 if this.idx >= ENTRY_COUNT\n    return evt\nend\n\ndef EventInst.put()\n    putc(PKT_CODE)\n    putc(EVT_CODE)\n    putBytes(<uint8*>this, sizeof<EventInst> - sizeof<uint16>)\nend\n\ndef EventKind.cache(a1, a2, a3)\n    if POLICY != Policy.NIL && ENTRY_COUNT > 0\n        auto evt = curs.next()\n        evt.time = mkTime()\n        evt.kidx = this.kidx\n        evt.a1 = <iarg_t>a1\n        evt.a2 = <iarg_t>a2\n        evt.a3 = <iarg_t>a3\n    end\nend\n\ndef EventKind.log(a1, a2, a3)\n    this.cache(a1, a2, a3) if POLICY == Policy.STORE || POLICY == Policy.QUIET\n    this.print(a1, a2, a3) if POLICY == Policy.PRINT\nend\n\ndef EventKind.print(a1, a2, a3)\n    if POLICY > Policy.QUIET\n        var evt: EventInst\n        evt.time = mkTime()\n        evt.kidx = this.kidx\n        evt.a1 = <iarg_t>a1\n        evt.a2 = <iarg_t>a2\n        evt.a3 = <iarg_t>a3\n        evt.put()\n    end\nend\n\ndef Group.initH(gs)\n    for auto i = 0; i < this.chars.length; i++\n        this.chars[i] = ^^gs && gs[i] ? gs.charCodeAt(i) : \" \".charCodeAt(0)^^\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/MemDump/","title":"MemDump","text":""},{"location":"cargo/em.core/em.utils/MemDump/#unit-memdump","title":"unit MemDump","text":"em.utils/MemDump.em
package em.utils\n\nmodule MemDump\n\n    function print32(addr: ptr_t, count: uint8)\n\nend\n\ndef print32(addr, count)\n    auto p32 = <uint32*>addr\n    while count--\n        auto v = *p32\n        printf \"%08x: %08x\\n\", p32, v\n        p32 += 1\n    end\nend\n
"},{"location":"cargo/em.core/em.utils/MinConsole/","title":"MinConsole","text":""},{"location":"cargo/em.core/em.utils/MinConsole/#unit-minconsole","title":"unit MinConsole","text":"em.utils/MinConsole.em
package em.utils\n\nfrom em.lang import ConsoleProviderI\n\nfrom em.mcu import ConsoleUart\n\nimport Formatter\n\nmodule MinConsole: ConsoleProviderI\n\nend\n\ndef flush()\n    ConsoleUart.flush()\nend\n\ndef print(fmt, a1, a2, a3, a4, a5, a6)\nend\n\ndef put(data)\n    ConsoleUart.put(data)\nend\n
"},{"location":"cargo/em.core/em.utils/MsCounterUptimer/","title":"MsCounterUptimer","text":""},{"location":"cargo/em.core/em.utils/MsCounterUptimer/#unit-mscounteruptimer","title":"unit MsCounterUptimer","text":"em.utils/MsCounterUptimer.em
package em.utils\n\nfrom em.hal import MsCounterI\nfrom em.hal import UptimerI\n\nmodule MsCounterUptimer: MsCounterI\n\n    proxy Uptimer: UptimerI\n\nprivate:\n\n    var t0: uint32\n\n    function readMsecs(): uint32\n\nend\n\ndef readMsecs()\n    auto time = Uptimer.read()\n    return ((time.secs & 0xFF) << 16) + (time.subs >> 16)\nend\n\ndef start()\n    t0 = readMsecs()\nend\n\ndef stop()\n    return 0 if t0 == 0\n    auto dt = readMsecs() - t0\n    t0 = 0\n    return (dt * 1000) >> 16\nend\n
"},{"location":"cargo/em.core/em.utils/PollerAux/","title":"PollerAux","text":""},{"location":"cargo/em.core/em.utils/PollerAux/#unit-polleraux","title":"unit PollerAux","text":"em.utils/PollerAux.em
package em.utils\n\nfrom em.hal import OneShotMilliI\nfrom em.hal import PollerI\n\nfrom em.mcu import Common\n\nmodule PollerAux: PollerI\n\n    proxy OneShot: OneShotMilliI\n\n    config pauseOnly: bool = false\n\nprivate:\n\n    function handler: OneShot.Handler\n    function pause(msecs: uint32)\n\n    var doneFlag: bool volatile\n\nend\n\ndef handler(arg)\n    doneFlag = true\nend\n\ndef pause(msecs)\n    return if msecs == 0\n    doneFlag = false\n    OneShot.enable(msecs, handler, null)\n    while !doneFlag\n        Common.Idle.exec()\n    end\nend\n\ndef poll(rate, count, fxn)\n    if pauseOnly\n        pause(rate)\n        return 1\n    else\n        count = 0 if rate == 0\n        while count\n            pause(rate)\n            count -= 1\n            break if fxn && fxn()\n        end\n        return count        \n    end\nend\n
"},{"location":"cargo/em.core/em.utils/ProcMgr/","title":"ProcMgr","text":""},{"location":"cargo/em.core/em.utils/ProcMgr/#unit-procmgr","title":"unit ProcMgr","text":"em.utils/ProcMgr.em
package em.utils\n\nfrom em.mcu import Common\nfrom em.utils import BasicListManager\n\nmodule ProcMgr\n\n    type ProcFxn: function(arg: uarg_t)\n\n    type Proc: opaque\n        host function declareStartH()\n        host function initH(fxn: fxn_t, arg: uarg_t = 0)\n        function arg(a: uarg_t)\n        function fxn(f: fxn_t)\n        function getArg(): uarg_t\n        function getFxn(): fxn_t\n        function post()\n    end\n\n    host function createH(fxn: fxn_t, arg: uarg_t = 0): Proc&\n\n    function run()\n\nprivate:\n\n    def opaque Proc\n        elem: BasicListManager.Element\n        fxn_: fxn_t\n        arg_: uarg_t\n    end\n\n    function dispatch()\n\n    config startP: Proc&\n\n    var procList: BasicListManager.List\n\nend\n\ndef em$construct() \n    procList.initH()\nend\n\ndef em$startup()\n    startP.post() if startP && !Common.Mcu.isWarm()\nend\n\ndef createH(fxn, arg)\n    auto proc = new<Proc>\n    proc.initH(fxn, arg)\n    return proc\nend\n\ndef dispatch()\n    for ;;\n        break if procList.hasElements() == 0\n        auto proc = <Proc&>procList.get()\n        Common.GlobalInterrupts.enable()\n        auto fxn = <ProcFxn>proc.fxn_\n        fxn(proc.arg_)\n        Common.GlobalInterrupts.disable()\n    end   \nend\n\ndef run()\n    Common.Idle.wakeup()\n    Common.GlobalInterrupts.enable()\n    for ;;\n        Common.GlobalInterrupts.disable()\n        dispatch()\n        Common.Idle.exec()\n    end\nend\n\ndef Proc.declareStartH()\n    startP = this\nend\n\ndef Proc.initH(fxn, arg)\n    this.elem.initH()\n    this.fxn_ = fxn\n    this.arg_ = arg\nend\n\ndef Proc.arg(a)\n    this.arg_ = a\nend\n\ndef Proc.fxn(f)\n    this.fxn_ = f\nend\n\ndef Proc.getArg()\n    return this.arg_\nend\n\ndef Proc.getFxn()\n    return this.fxn_\nend\n\ndef Proc.post()\n    auto key = Common.GlobalInterrupts.disable()\n    procList.add(this.elem) if !this.elem.isActive()\n    Common.GlobalInterrupts.restore(key)\nend\n
"},{"location":"cargo/em.core/em.utils/SoftUart/","title":"SoftUart","text":""},{"location":"cargo/em.core/em.utils/SoftUart/#unit-softuart","title":"unit SoftUart","text":"em.utils/SoftUart.em
package em.utils\n\nfrom em.hal import ConsoleUartI\nfrom em.hal import GpioI\nfrom em.hal import UsThreshI\n\nfrom em.lang import Math\n\nfrom em.mcu import Common\n\nmodule SoftUart: ConsoleUartI\n\n    proxy TxPin: GpioI\n    proxy UsThresh: UsThreshI\n\nprivate:\n\n    config baudRate: uint32 = 115200\n    config bitTime: uint16 = 7\n\nend\n\ndef em$startup()\n    TxPin.makeOutput()\n    TxPin.set()\nend\n\ndef setBaudH(rate)\n    ## TODO -- implement\nend\n\ndef flush()\nend\n\ndef put(data)\n    var bitCnt: uint8 = 10                              # Load Bit counter, 8data + ST/SP/SP\n    var txByte: uint16 = (data << 1) | 0x600            # Add mark stop bits and space start bit\n    var key: uarg_t = Common.GlobalInterrupts.disable()\n    for ;;\n        UsThresh.set(bitTime)\n        if bitCnt-- == 0\n            TxPin.set()\n            break\n        else\n            if txByte & 0x01\n                TxPin.set()\n            else\n                TxPin.clear()\n            end\n            txByte = txByte >> 1                        # shift next bit\n        end\n        UsThresh.pause()\n    end\n    Common.GlobalInterrupts.restore(key)\nend\n
"},{"location":"cargo/em.core/em.utils/TickerMgr/","title":"TickerMgr","text":""},{"location":"cargo/em.core/em.utils/TickerMgr/#unit-tickermgr","title":"unit TickerMgr","text":"em.utils/TickerMgr.em
package em.utils\n\nimport AlarmMgr\nimport FiberMgr\n\nmodule TickerMgr\n            #   ^|\n    type TickCallback: function()\n            #   ^|\n    type Ticker: opaque\n            #   ^|\n        host function initH()\n            #   ^|\n        function start(rate256: uint32, tickCb: TickCallback)\n            #   ^|        \n        function stop()\n            #   ^|        \n    end\n\n    host function createH(): Ticker&\n            #   ^|\nprivate:\n\n    def opaque Ticker\n        alarm: AlarmMgr.Alarm&\n        fiber: FiberMgr.Fiber&\n        rate256: uint32\n        tickCb: TickCallback\n    end\n\n    function alarmFB: FiberMgr.FiberBodyFxn\n\n    var tickerTab: Ticker[]\n\nend\n\ndef createH()\n    var ticker: Ticker& = tickerTab[tickerTab.length++]\n    ticker.initH()\n    return ticker\nend\n\ndef Ticker.initH()\n    this.fiber = FiberMgr.createH(alarmFB, ^^this.$$cn^^)\n    this.alarm = AlarmMgr.createH(this.fiber)\nend\n\ndef alarmFB(arg)\n    auto ticker = <Ticker&>arg\n    return if ticker.tickCb == null\n    ticker.tickCb() \n    ticker.alarm.wakeupAt(ticker.rate256)\nend\n\ndef Ticker.start(rate256, tickCb)\n    this.rate256 = rate256\n    this.tickCb = tickCb\n    this.alarm.wakeupAt(rate256)\nend\n\ndef Ticker.stop()\n    this.alarm.cancel()\n    this.tickCb = null\nend\n
"},{"location":"cargo/em.core/em.utils/TimeoutAux/","title":"TimeoutAux","text":""},{"location":"cargo/em.core/em.utils/TimeoutAux/#unit-timeoutaux","title":"unit TimeoutAux","text":"em.utils/TimeoutAux.em
package em.utils\n\nfrom em.hal import OneShotMilliI\nfrom em.hal import TimeoutI\n\nmodule TimeoutAux: TimeoutI\n\n    proxy OneShot: OneShotMilliI\n\nprivate:\n\n    var flag: bool volatile\n\n    function handler: OneShot.Handler\n\nend\n\ndef active()\n    return flag\nend\n\ndef cancel()\n    flag = false\n    OneShot.disable()\nend\n\ndef handler(arg)\n    cancel()\nend\n\ndef set(msecs)\n    flag = true\n    OneShot.enable(msecs, handler, null)\nend\n
"},{"location":"cargo/em.docs/","title":"Index","text":""},{"location":"cargo/em.docs/#bundle-emdocs","title":"bundle em.docs","text":""},{"location":"cargo/em.docs/em.examples.basic/","title":"Index","text":""},{"location":"cargo/em.docs/em.examples.basic/#package-emexamplesbasic","title":"package em.examples.basic","text":""},{"location":"cargo/em.docs/em.examples.basic/Alarm1P/","title":"Alarm1P","text":""},{"location":"cargo/em.docs/em.examples.basic/Alarm1P/#unit-alarm1p","title":"unit Alarm1P","text":"em.examples.basic/Alarm1P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.utils import AlarmMgr\nfrom em.utils import FiberMgr\n\nmodule Alarm1P\n\nprivate:\n\n    function blinkFB: FiberMgr.FiberBodyFxn\n\n    config alarm: AlarmMgr.Alarm&\n    config blinkF: FiberMgr.Fiber&\n\n    var counter: uint32\n\nend\n\ndef em$construct()\n    blinkF = FiberMgr.createH(blinkFB)\n    alarm = AlarmMgr.createH(blinkF)\nend\n\ndef em$run()\n    blinkF.post()\n    FiberMgr.run()\nend\n\ndef blinkFB(arg)\n    %%[c]\n    AppLed.wink(100)            # 100ms\n    counter += 1\n    if counter & 0x1\n        alarm.wakeup(512)       # 2s\n    else\n        alarm.wakeup(192)       # 750ms\n    end\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/Alarm2P/","title":"Alarm2P","text":""},{"location":"cargo/em.docs/em.examples.basic/Alarm2P/#unit-alarm2p","title":"unit Alarm2P","text":"em.examples.basic/Alarm2P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.utils import AlarmMgr\nfrom em.utils import FiberMgr\n\nmodule Alarm2P\n\nprivate:\n\n    function blinkFB: FiberMgr.FiberBodyFxn\n\n    config alarm: AlarmMgr.Alarm&\n    config blinkF: FiberMgr.Fiber&\n\n    var counter: uint32\n\nend\n\ndef em$construct()\n    blinkF = FiberMgr.createH(blinkFB)\n    alarm = AlarmMgr.createH(blinkF)\nend\n\ndef em$run()\n    blinkF.post()\n    FiberMgr.run()\nend\n\ndef blinkFB(arg)\n    %%[c]\n    counter += 1\n    if counter & 0x1\n        AppLed.wink(100)    # 100ms\n    else\n        AppLed.wink(5)      # 5ms\n    end\n    alarm.wakeupAt(384)     # 1.5s window \nend\n
"},{"location":"cargo/em.docs/em.examples.basic/BlinkerDbgP/","title":"BlinkerDbgP","text":""},{"location":"cargo/em.docs/em.examples.basic/BlinkerDbgP/#unit-blinkerdbgp","title":"unit BlinkerDbgP","text":"em.examples.basic/BlinkerDbgP.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.mcu import Common\n\nmodule BlinkerDbgP\n\n    config dbgFlag: bool = true\n\n    config minCnt: uint16 = 1000\n    config maxCnt: uint16 = 1020 \n\nend\n\ndef em$run()\n    AppLed.on()\n    for cnt: uint16 = minCnt; cnt < maxCnt; cnt++\n        %%[d+]\n        Common.BusyWait.wait(500 * 1000L)\n        %%[d-]\n        AppLed.toggle()\n        continue if !dbgFlag\n        fail if cnt > ((minCnt + maxCnt) / 2)\n        %%[>cnt]\n        var bits11: uint8 = cnt & 0b0011\n        %%[>bits11]\n        %%[c:bits11]\n        printf \"cnt = %d (0x%04x), bits11 = %d\\n\", cnt, cnt, bits11\n    end\n    AppLed.off()\n    halt\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/BlinkerP/","title":"BlinkerP","text":""},{"location":"cargo/em.docs/em.examples.basic/BlinkerP/#unit-blinkerp","title":"unit BlinkerP","text":"em.examples.basic/BlinkerP.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.mcu import Common\n\nmodule BlinkerP\n\nend\n\ndef em$run()\n    AppLed.on()\n    for auto i = 0; i < 10; i++\n        Common.BusyWait.wait(500 * 1000L)\n        AppLed.toggle()\n    end\n    AppLed.off()\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/Button1P/","title":"Button1P","text":""},{"location":"cargo/em.docs/em.examples.basic/Button1P/#unit-button1p","title":"unit Button1P","text":"em.examples.basic/Button1P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em$distro import McuC\nfrom McuC import AppButEdge\n\nfrom em.mcu import Common\n\nmodule Button1P\n\nprivate:\n\n    function handler: AppButEdge.Handler\n\nend\n\ndef em$construct()\n    AppButEdge.setDetectHandlerH(handler)\nend\n\ndef em$startup()\n    AppButEdge.makeInput()\n    AppButEdge.setInternalPullup(true)\n    AppButEdge.setDetectFallingEdge()\nend\n\ndef em$run()\n    Common.GlobalInterrupts.enable()\n    for ;;\n        AppButEdge.enableDetect()\n        Common.Idle.exec()\n    end\nend\n\ndef handler()\n    %%[c]\n    AppButEdge.clearDetect()\n    AppLed.on()\n    Common.BusyWait.wait(5000)\n    AppLed.off()\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/Button2P/","title":"Button2P","text":""},{"location":"cargo/em.docs/em.examples.basic/Button2P/#unit-button2p","title":"unit Button2P","text":"em.examples.basic/Button2P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em$distro import McuC\nfrom McuC import AppButEdge\n\nfrom em.mcu import Common\n\nfrom em.utils import FiberMgr\n\nmodule Button2P\n\nprivate:\n\n    function blinkFB: FiberMgr.FiberBodyFxn\n    function handler: AppButEdge.Handler\n\n    config blinkF: FiberMgr.Fiber&\n\nend\n\ndef em$construct()\n    AppButEdge.setDetectHandlerH(handler)\n    blinkF = FiberMgr.createH(blinkFB)\nend\n\ndef em$startup()\n    AppButEdge.makeInput()\n    AppButEdge.setInternalPullup(true)\n    AppButEdge.setDetectFallingEdge()\nend\n\ndef em$run()\n    AppButEdge.enableDetect()\n    FiberMgr.run()\nend\n\ndef blinkFB(arg)\n    %%[d]\n    AppLed.on()\n    Common.BusyWait.wait(5000)\n    AppLed.off()\n    AppButEdge.enableDetect()\nend\n\ndef handler()\n    %%[c]\n    AppButEdge.clearDetect()\n    blinkF.post()\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/Button3P/","title":"Button3P","text":""},{"location":"cargo/em.docs/em.examples.basic/Button3P/#unit-button3p","title":"unit Button3P","text":"em.examples.basic/Button3P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppBut\nfrom BoardC import AppLed\nfrom BoardC import SysLed\n\nfrom em.mcu import Common\nfrom em.utils import FiberMgr\n\nmodule Button3P\n\nprivate:\n\n    function onPressedCB: AppBut.OnPressedCB\n\nend\n\ndef em$run()\n    AppBut.onPressed(onPressedCB)\n    FiberMgr.run()\nend\n\ndef onPressedCB()\n    %%[c]\n    if AppBut.isPressed()\n        SysLed.on()\n        Common.BusyWait.wait(40000)  # 40ms\n        SysLed.off()\n    else\n        AppLed.on()\n        Common.BusyWait.wait(5000)  # 5ms\n        AppLed.off()\n    end\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/FiberP/","title":"FiberP","text":""},{"location":"cargo/em.docs/em.examples.basic/FiberP/#unit-fiberp","title":"unit FiberP","text":"em.examples.basic/FiberP.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.mcu import Common\nfrom em.utils import FiberMgr\n\nmodule FiberP\n\nprivate:\n\n    function blinkFB: FiberMgr.FiberBodyFxn\n\n    config blinkF: FiberMgr.Fiber&\n\n    var count: uint8 = 5\n\nend\n\ndef em$construct()\n    blinkF = FiberMgr.createH(blinkFB)\nend\n\ndef em$run()\n    blinkF.post()\n    FiberMgr.run()\nend\n\ndef blinkFB(arg)\n    %%[d]\n    halt if --count == 0\n    AppLed.on()\n    Common.BusyWait.wait(100000)\n    AppLed.off()\n    Common.BusyWait.wait(100000)\n    blinkF.post()\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/HelloP/","title":"HelloP","text":""},{"location":"cargo/em.docs/em.examples.basic/HelloP/#unit-hellop","title":"unit HelloP","text":"em.examples.basic/HelloP.em
package em.examples.basic\n\nfrom em$distro import BoardC\n\nmodule HelloP\n\nend\n\ndef em$run()\n    printf \"hello world\\n\"\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/OneShot1P/","title":"OneShot1P","text":""},{"location":"cargo/em.docs/em.examples.basic/OneShot1P/#unit-oneshot1p","title":"unit OneShot1P","text":"em.examples.basic/OneShot1P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em$distro import McuC\nfrom McuC import OneShotMilli\n\nfrom em.mcu import Common\n\nmodule OneShot1P\n\nprivate:\n\n    function handler: OneShotMilli.Handler\n\n    var doneFlag: bool volatile = true\n\nend\n\ndef em$run()\n    Common.GlobalInterrupts.enable()\n    for auto i = 0; i < 5; i++\n        %%[d]\n        AppLed.on()\n        Common.BusyWait.wait(5000)\n        AppLed.off()\n        doneFlag = false\n        OneShotMilli.enable(100, handler)\n        while !doneFlag\n            Common.Idle.exec()\n        end\n    end\nend\n\ndef handler(arg)\n    %%[c]\n    doneFlag = true\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/OneShot2P/","title":"OneShot2P","text":""},{"location":"cargo/em.docs/em.examples.basic/OneShot2P/#unit-oneshot2p","title":"unit OneShot2P","text":"em.examples.basic/OneShot2P.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em$distro import McuC\nfrom McuC import OneShotMilli\n\nfrom em.mcu import Common\nfrom em.utils import FiberMgr\n\nmodule OneShot2P\n\nprivate:\n\n    function blinkFB: FiberMgr.FiberBodyFxn\n    function handler: OneShotMilli.Handler\n\n    config blinkF: FiberMgr.Fiber&\n    var count: uint8 = 5\n\nend\n\ndef em$construct()\n    blinkF = FiberMgr.createH(blinkFB)\nend\n\ndef em$run()\n    blinkF.post()\n    FiberMgr.run()\nend\n\ndef blinkFB(arg)\n    %%[d]\n    AppLed.on()\n    Common.BusyWait.wait(5000)\n    AppLed.off()\n    halt if --count == 0\n    OneShotMilli.enable(100, handler, null)\nend\n\ndef handler(arg)\n    %%[c]\n    blinkF.post()\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/PollerP/","title":"PollerP","text":""},{"location":"cargo/em.docs/em.examples.basic/PollerP/#unit-pollerp","title":"unit PollerP","text":"em.examples.basic/PollerP.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\n\nfrom em.mcu import Common\nfrom em.mcu import Poller\n\nmodule PollerP\n\nend\n\ndef em$run()\n    Common.GlobalInterrupts.enable()\n    auto k = 5\n    while k--\n        Poller.pause(100)   # 100ms\n        AppLed.wink(5)      # 5ms\n    end\nend\n
"},{"location":"cargo/em.docs/em.examples.basic/TickerP/","title":"TickerP","text":""},{"location":"cargo/em.docs/em.examples.basic/TickerP/#unit-tickerp","title":"unit TickerP","text":"em.examples.basic/TickerP.em
package em.examples.basic\n\nfrom em$distro import BoardC\nfrom BoardC import AppLed\nfrom BoardC import SysLed\n\nfrom em.utils import FiberMgr\nfrom em.utils import TickerMgr\n\nmodule TickerP\n\nprivate:\n\n    function appTickCb: TickerMgr.TickCallback\n    function sysTickCb: TickerMgr.TickCallback\n\n    config appTicker: TickerMgr.Ticker&\n    config sysTicker: TickerMgr.Ticker&\n\nend\n\ndef em$construct()\n    appTicker = TickerMgr.createH()\n    sysTicker = TickerMgr.createH()\nend\n\ndef em$run()\n    appTicker.start(256, appTickCb)\n    sysTicker.start(384, sysTickCb)\n    FiberMgr.run()\nend\n\ndef appTickCb()\n    %%[c]\n    AppLed.wink(100)\nend\n\ndef sysTickCb()\n    %%[d]\n    SysLed.wink(100)\nend\n
"},{"location":"cargo/ti.cc23xx/","title":"Index","text":""},{"location":"cargo/ti.cc23xx/#bundle-ticc23xx","title":"bundle ti.cc23xx","text":""},{"location":"cargo/ti.cc23xx/ti.build.cc23xx/","title":"Index","text":""},{"location":"cargo/ti.cc23xx/ti.build.cc23xx/#package-tibuildcc23xx","title":"package ti.build.cc23xx","text":""},{"location":"cargo/ti.cc23xx/ti.build.cc23xx/GccBuilder/","title":"GccBuilder","text":""},{"location":"cargo/ti.cc23xx/ti.build.cc23xx/GccBuilder/#unit-gccbuilder","title":"unit GccBuilder","text":"ti.build.cc23xx/GccBuilder.em
package ti.build.cc23xx\n\nfrom em.build.misc import UniFlash\nfrom em.build.misc import Utils\n\nfrom em.build.gcc import BuilderBase as Base\n\nfrom em.lang import BuilderI\nfrom em.lang import BuildC\n\nmodule GccBuilder: BuilderI\n\nend\n\ndef em$configure()\n    Base.gccFlav ?= \"arm-none-eabi\"\n    if BuildC.bootFlash\n        Base.dmemBase ?= 0x20005000\n        Base.dmemSize ?= 0x4000\n        Base.imemBase ?= 0x20000000\n        Base.imemSize ?= 0x5000\n        Base.lmemBase ?= 0x00000000\n        Base.lmemSize ?= 0x80000\n    else\n        Base.dmemBase ?= 0x20000000\n        Base.dmemSize ?= 0x9000\n        Base.imemBase ?= 0x00000000\n        Base.imemSize ?= 0x80000\n    end\n    Base.vectSize ?= 0x90\n    Utils.addInclude(\"com.ti/devices/cc23x0r5\")\n    Utils.addSection(0x4e020000, 0x800, \"FLASH_CCFG\", \".ccfg\")\nend\n\ndef compile(buildDir)\n    return <CompileInfo&>Base.compile(buildDir)\nend\n\ndef getTypeInfo()\n    return <TypeInfo&>Base.getTypeInfo()\nend\n\ndef populate(buildDir, sysFlag)\n    Base.populate(buildDir, sysFlag)\n    Utils.copy(buildDir, \"CC2340R5.ccxml\", \"ti.build.cc23xx\")\n    UniFlash.genLoadScript(buildDir, \"CC2340R5\")\nend\n
"},{"location":"cargo/ti.cc23xx/ti.build.cc23xx/SeggerBuilder/","title":"SeggerBuilder","text":""},{"location":"cargo/ti.cc23xx/ti.build.cc23xx/SeggerBuilder/#unit-seggerbuilder","title":"unit SeggerBuilder","text":"ti.build.cc23xx/SeggerBuilder.em
package ti.build.cc23xx\n\nfrom em.build.misc import UniFlash\nfrom em.build.misc import Utils\n\nfrom em.build.segger import BuilderBase as Base\n\nfrom em.lang import BuilderI\nfrom em.lang import BuildC\n\nmodule SeggerBuilder: BuilderI\n\nend\n\ndef em$configure()\n    if BuildC.bootFlash\n        Base.dmemBase ?= 0x20005000\n        Base.dmemSize ?= 0x4000\n        Base.imemBase ?= 0x20000000\n        Base.imemSize ?= 0x5000\n        Base.lmemBase ?= 0x00000000\n        Base.lmemSize ?= 0x80000\n    else\n        Base.dmemBase ?= 0x20000000\n        Base.dmemSize ?= 0x9000\n        Base.imemBase ?= 0x00000000\n        Base.imemSize ?= 0x80000\n    end\n    Base.vectSize ?= 0x90\n    Utils.addInclude(\"com.ti/devices/cc23x0r5\")\n    Utils.addInclude(\"com.ti/devices/cc23x0r5/cmsis/core\")\n    Utils.addSection(0x4e020000, 0x800, \"FLASH_CCFG\", \".ccfg\")\nend\n\ndef compile(buildDir)\n    return <CompileInfo&>Base.compile(buildDir)\nend\n\ndef getTypeInfo()\n    return <TypeInfo&>Base.getTypeInfo()\nend\n\ndef populate(buildDir, sysFlag)\n    Base.populate(buildDir, sysFlag)\n    Utils.copy(buildDir, \"CC2340R5.ccxml\", \"ti.build.cc23xx\")\n    UniFlash.genLoadScript(buildDir, \"CC2340R5\")\nend\n
"},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/","title":"Index","text":""},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/#package-tidistrocc23xx","title":"package ti.distro.cc23xx","text":""},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/BoardC/","title":"BoardC","text":""},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/BoardC/#unit-boardc","title":"unit BoardC","text":"ti.distro.cc23xx/BoardC.em
package ti.distro.cc23xx\n\nfrom em.lang import Atom                    # force ordering\n\nimport McuC\nfrom McuC import AppButEdge\nfrom McuC import AppLedPin\nfrom McuC import AppOutPin\nfrom McuC import AppOutUart\nfrom McuC import SysDbgA\nfrom McuC import SysDbgB\nfrom McuC import SysDbgC\nfrom McuC import SysDbgD\nfrom McuC import SysLedPin\nfrom McuC import OneShotMilli\nfrom McuC import Uptimer\nfrom McuC import WakeupTimer\n\nfrom em.lang import Console\nfrom em.lang import Debug\n\nfrom em.mcu import ConsoleUart\nfrom em.mcu import Poller\n\nfrom em.utils import AlarmMgr\nfrom em.utils import BoardController\nfrom em.utils import BoardInfo\nfrom em.utils import EpochTime\nfrom em.utils import FormattingConsole\nfrom em.utils import PollerAux\n\nfrom em.utils import DebugPinT {} as DbgA\nfrom em.utils import DebugPinT {} as DbgB\nfrom em.utils import DebugPinT {} as DbgC\nfrom em.utils import DebugPinT {} as DbgD\n\nfrom em.utils import LedT {} as AppLed\nfrom em.utils import LedT {} as SysLed\n\nfrom em.utils import ButtonT {} as AppBut\n\nexport AppBut\nexport AppLed\nexport SysLed\n\ncomposite BoardC\n\nend\n\ndef em$configure()\n    auto brdRec = BoardInfo.readRecordH()\n    auto pm = brdRec.pinMap\n    AlarmMgr.WakeupTimer ?= WakeupTimer\n    AppBut.Edge ?= AppButEdge\n    AppLed.activeLow ?= brdRec.activeLowLeds\n    AppLed.em$used ?= true\n    AppLed.Pin ?= AppLedPin\n    AppOutUart.TxPin ?= AppOutPin\n    BoardController.em$used ?= true\n    BoardController.Led ?= SysLed\n    Console.em$used ?= true\n    Console.Provider ?= FormattingConsole\n    ConsoleUart.Impl ?= AppOutUart\n    DbgA.Pin ?= SysDbgA\n    DbgB.Pin ?= SysDbgB\n    DbgC.Pin ?= SysDbgC\n    DbgD.Pin ?= SysDbgD\n    Debug.Pin_a ?= DbgA\n    Debug.Pin_b ?= DbgB\n    Debug.Pin_c ?= DbgC\n    Debug.Pin_d ?= DbgD\n    EpochTime.Uptimer ?= Uptimer\n    Poller.Impl ?= PollerAux\n    PollerAux.OneShot ?= OneShotMilli\n    SysLed.activeLow ?= brdRec.activeLowLeds\n    SysLed.em$used ?= true\n    SysLed.Pin ?= SysLedPin\nend\n
"},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/BoardMeta/","title":"BoardMeta","text":""},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/BoardMeta/#unit-boardmeta","title":"unit BoardMeta","text":"ti.distro.cc23xx/BoardMeta.em
package ti.distro.cc23xx\n\nfrom em.utils import BoardMeta as BaseMeta\n\nhost module BoardMeta\n\n    type DrvDesc: BaseMeta.DrvDesc\n\n    type PinMap: struct\n        appBut: int8\n        appLed: int8\n        appOut: int8\n        extFlashCS: int8\n        extFlashCLK: int8\n        extFlashPICO: int8\n        extFlashPOCI: int8\n        sysDbgA: int8\n        sysDbgB: int8\n        sysDbgC: int8\n        sysDbgD: int8\n        sysLed: int8\n    end\n\n    type Record: struct\n        activeLowLeds: bool\n        baudRate: uint32\n        clockFreq: uint32\n        extFlashDisable: bool\n        lfXtalEnable: bool\n        pinMap: PinMap&\n        drvDescs: DrvDesc&[]\n    end\n\n    config baseFileLoc: string = \"ti.distro.cc23xx/em-boards\"\n\n    config attrNames: string[] = [\n        \"$inherits\",\n        \"$overrides\",\n        \"activeLowLeds\",\n        \"baudRate\",\n        \"clockFreq\",\n        \"extFlashDisable\",\n        \"lfXtalEnable\",\n    ]\n\n    config pinNames: string[] = [\n        \"appBut\",\n        \"appLed\",\n        \"appOut\",\n        \"extFlashCS\",\n        \"extFlashCLK\",\n        \"extFlashPICO\",\n        \"extFlashPOCI\",\n        \"sysDbgA\",\n        \"sysDbgB\",\n        \"sysDbgC\",\n        \"sysDbgD\",\n        \"sysLed\",\n    ] \n\nend\n
"},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/McuC/","title":"McuC","text":""},{"location":"cargo/ti.cc23xx/ti.distro.cc23xx/McuC/#unit-mcuc","title":"unit McuC","text":"ti.distro.cc23xx/McuC.em
package ti.distro.cc23xx\n\nfrom ti.mcu.cc23xx import Regs     # force ordering\n\nfrom ti.mcu.cc23xx import EdgeDetectGpioT {} as AppButEdge\nfrom ti.mcu.cc23xx import GpioT {} as AppLedPin\nfrom ti.mcu.cc23xx import GpioT {} as AppOutPin\nfrom ti.mcu.cc23xx import GpioT {} as SysDbgA\nfrom ti.mcu.cc23xx import GpioT {} as SysDbgB\nfrom ti.mcu.cc23xx import GpioT {} as SysDbgC\nfrom ti.mcu.cc23xx import GpioT {} as SysDbgD\nfrom ti.mcu.cc23xx import GpioT {} as SysLedPin\n\nfrom ti.mcu.cc23xx import ConsoleUart0 as AppOutUart\nfrom ti.mcu.cc23xx import BusyWait\nfrom ti.mcu.cc23xx import ExtFlashDisabler\nfrom ti.mcu.cc23xx import GlobalInterrupts\nfrom ti.mcu.cc23xx import Idle\nfrom ti.mcu.cc23xx import IntrVec\nfrom ti.mcu.cc23xx import Mcu\nfrom ti.mcu.cc23xx import MsCounter\nfrom ti.mcu.cc23xx import OneShotGpt3 as OneShotMilli\nfrom ti.mcu.cc23xx import Uptimer\nfrom ti.mcu.cc23xx import UsCounter\nfrom ti.mcu.cc23xx import WakeupTimer\n\nfrom em.mcu import Common\nfrom em.mcu import CommonC\n\nfrom em.utils import BoardInfo\n\nexport AppButEdge\nexport AppLedPin\nexport AppOutPin\nexport AppOutUart\nexport OneShotMilli\nexport SysDbgA\nexport SysDbgB\nexport SysDbgC\nexport SysDbgD\nexport SysLedPin\nexport Uptimer\nexport WakeupTimer\n\ncomposite McuC\n\nend\n\ndef em$preconfigure()\n    auto brdRec = BoardInfo.readRecordH()\n    auto pm = brdRec.pinMap\n    AppButEdge.pin ?= pm.appBut\n    AppLedPin.pin ?= pm.appLed\n    AppOutPin.pin ?= pm.appOut\n    AppOutUart.setBaudH(brdRec.baudRate)\n    ExtFlashDisabler.em$used ?= brdRec.extFlashDisable\n    ExtFlashDisabler.CLK_pin ?= pm.extFlashCLK\n    ExtFlashDisabler.CS_pin ?= pm.extFlashCS\n    ExtFlashDisabler.PICO_pin ?= pm.extFlashPICO\n    ExtFlashDisabler.POCI_pin ?= pm.extFlashPOCI\n    IntrVec.em$used ?= true\n    Mcu.hasLfXtal ?= brdRec.lfXtalEnable\n    Mcu.mclkFrequency ?= brdRec.clockFreq\n    Regs.em$used ?= true\n    SysDbgA.pin ?= pm.sysDbgA\n    SysDbgB.pin ?= pm.sysDbgB\n    SysDbgC.pin ?= pm.sysDbgC\n    SysDbgD.pin ?= pm.sysDbgD\n    SysLedPin.pin ?= pm.sysLed\nend\n\ndef em$configure()\n    Common.BusyWait ?= BusyWait\n    Common.GlobalInterrupts ?= GlobalInterrupts\n    Common.Idle ?= Idle\n    Common.Mcu ?= Mcu\n    Common.MsCounter ?= MsCounter\n    Common.UsCounter ?= UsCounter\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/","title":"Index","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/#package-timcucc23xx","title":"package ti.mcu.cc23xx","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWait/","title":"BusyWait","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWait/#unit-busywait","title":"unit BusyWait","text":"ti.mcu.cc23xx/BusyWait.em
package ti.mcu.cc23xx\n\nfrom em.hal import BusyWaitI\n\nmodule BusyWait: BusyWaitI\n\nend\n\ndef wait(usecs)\n    ^HapiWaitUs(usecs)\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWaitSysTick/","title":"BusyWaitSysTick","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/BusyWaitSysTick/#unit-busywaitsystick","title":"unit BusyWaitSysTick","text":"ti.mcu.cc23xx/BusyWaitSysTick.em
package ti.mcu.cc23xx\n\nfrom em.hal import BusyWaitI\n\nmodule BusyWaitSysTick: BusyWaitI\n\nend\n\ndef wait(usecs)\n    ^^SysTick->VAL^^ = 0\n    ^^SysTick->LOAD^^ = usecs\n    ^^SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk^^\n    while ^^SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk^^ != 0\n        %%[d]\n    end\n    ^^SysTick->CTRL^^ = 0\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/ConsoleUart0/","title":"ConsoleUart0","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/ConsoleUart0/#unit-consoleuart0","title":"unit ConsoleUart0","text":"ti.mcu.cc23xx/ConsoleUart0.em
package ti.mcu.cc23xx\n\nfrom em.hal import ConsoleUartI\nfrom em.hal import GpioI\n\nfrom em.lang import Math\n\nimport Idle\nimport Mcu\n\nmodule ConsoleUart0: ConsoleUartI\n\n    proxy TxPin: GpioI\n\nprivate:\n\n    config baud: uint32\n    config fbrd: uint32\n    config ibrd: uint32\n\n    function sleepEnter: Idle.Callback\n    function sleepLeave: Idle.Callback\n\nend\n\ndef em$construct()\n    Idle.addSleepEnterCbH(sleepEnter)\n    Idle.addSleepLeaveCbH(sleepLeave)\n    auto brd = <num_t>(Mcu.mclkFrequency / (baud * 16))\n    ibrd = Math.floor(brd)\n    fbrd = Math.round((brd - ibrd) * 64)\nend\n\ndef em$startup()\n    sleepLeave()\nend\n\ndef setBaudH(rate)\n    baud = rate\nend\n\ndef sleepEnter()\n    ^^HWREG(CLKCTL_BASE + CLKCTL_O_CLKENCLR0)^^ = ^CLKCTL_CLKENSET0_UART0\n    TxPin.reset()\nend\n\ndef sleepLeave()\n    ^^HWREG(CLKCTL_BASE + CLKCTL_O_CLKENSET0)^^ = ^CLKCTL_CLKENSET0_UART0\n    TxPin.makeOutput()\n    TxPin.set()\n    TxPin.functionSelect(2)\n    ^^HWREG(UART0_BASE + UART_O_CTL)^^ &= ~^UART_CTL_UARTEN\n    ^^HWREG(UART0_BASE + UART_O_IBRD)^^ = ibrd\n    ^^HWREG(UART0_BASE + UART_O_FBRD)^^ = fbrd\n    ^^HWREG(UART0_BASE + UART_O_LCRH)^^ = ^UART_LCRH_WLEN_BITL8\n    ^^HWREG(UART0_BASE + UART_O_CTL)^^ |= ^UART_CTL_UARTEN\nend\n\ndef flush()\n    while (^^HWREG(UART0_BASE + UART_O_FR)^^ & ^UART_FR_BUSY) != 0\n    end\nend\n\ndef put(data)\n    ^^HWREG(UART0_BASE + UART_O_DR)^^ = data\n    flush()\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioAux/","title":"EdgeDetectGpioAux","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioAux/#unit-edgedetectgpioaux","title":"unit EdgeDetectGpioAux","text":"ti.mcu.cc23xx/EdgeDetectGpioAux.em
package ti.mcu.cc23xx\n\nimport InterruptT { name: \"GPIO_COMB\" } as Intr\n\nmodule EdgeDetectGpioAux\n\n    type Handler: function ()\n\n    type HandlerInfo: struct\n        link: HandlerInfo&\n        mask: uint32\n        handler: Handler\n    end\n\n    function addHandler(hi: HandlerInfo&)\n\n private:\n\n    var handlerList: HandlerInfo&\n    function edgeIsr: Intr.Handler\n\nend\n\ndef em$construct()\n    Intr.setHandlerH(edgeIsr)\nend\n\ndef em$startup()\n    Intr.enable()\nend\n\ndef addHandler(hi)\n    hi.link = handlerList\n    handlerList = hi\nend\n\ndef edgeIsr()\n    auto mis = <uint32>^^HWREG(GPIO_BASE + GPIO_O_MIS)^^\n    for hi: HandlerInfo& = handlerList; hi != null; hi = hi.link\n        hi.handler() if (mis & hi.mask) && hi.handler\n    end\n    ^^HWREG(GPIO_BASE + GPIO_O_ICLR)^^ = 0xffffffff\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioT/","title":"EdgeDetectGpioT","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/EdgeDetectGpioT/#unit-edgedetectgpiot","title":"unit EdgeDetectGpioT","text":"ti.mcu.cc23xx/EdgeDetectGpioT.em
package ti.mcu.cc23xx\n\ntemplate EdgeDetectGpioT\n\n    const UNDEF: int8 = -1\n\n    config pin: int8 = UNDEF\n\nend\n\ndef em$generateUnit(pn, un)\n    auto bq = \"`\"\n    auto p = pin\n    auto pre = ^^pn.replace(/[.]/g, '_') + '_' + un + '__'^^\n|->>>\n    package `pn`\n\n    from ti.mcu.cc23xx import EdgeDetectGpioAux as Aux\n    from ti.mcu.cc23xx import GpioT {} as Pin\n\n    from em.hal import GpioEdgeDetectMinI\n\n    module `un`: GpioEdgeDetectMinI\n\n        config pin: int16 = `p`\n\n    private:\n\n        config isDef: bool\n        config mask: uint32        \n\n        var info: Aux.HandlerInfo\n\n    end\n\n    def em$configure()\n        Pin.pin ?= pin\n    end\n\n    def em$construct()\n        isDef = pin != `UNDEF`\n        mask = isDef ? <uint32>(1 << <uint8>pin) : 0\n        info.mask = mask\n    end\n\n    def em$startup()\n        Aux.addHandler(info)\n    end    \n\n    def clear() \n        Pin.clear()\n    end\n\n    def set()\n        Pin.set()\n    end\n\n    def get()\n        return Pin.get()\n    end\n\n    def toggle()\n        Pin.toggle()\n    end\n\n    def isInput()\n        return Pin.isInput()\n    end\n\n    def isOutput()\n        return Pin.isOutput()\n    end\n\n    def makeInput()\n        Pin.makeInput()\n    end\n\n    def makeOutput()\n        Pin.makeOutput()\n    end\n\n    def functionSelect(select)\n        Pin.functionSelect(select)\n    end\n\n    def setInternalPullup(enable)\n        Pin.setInternalPullup(enable)\n    end\n\n    def pinId()\n        return pin\n    end\n\n    def reset()\n        Pin.reset()\n    end\n\n    def enableDetect()\n        ^^HWREG(GPIO_BASE + GPIO_O_IMSET)^^ = mask if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ |= ^IOC_IOC0_WUENSB if isDef\n    end\n\n    def disableDetect()\n        ^^HWREG(GPIO_BASE + GPIO_O_IMCLR)^^ = mask if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ &= ~^IOC_IOC0_WUENSB if isDef\n    end\n\n    def clearDetect()\n        ^^HWREG(GPIO_BASE + GPIO_O_ICLR)^^ = mask if isDef\n    end\n\n    def setDetectRisingEdge()\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ &= ~^IOC_IOC0_EDGEDET_M if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ |= ^IOC_IOC0_EDGEDET_EDGE_POS if isDef\n    end\n\n    def setDetectFallingEdge()\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ &= ~^IOC_IOC0_EDGEDET_M if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ |= ^IOC_IOC0_EDGEDET_EDGE_NEG if isDef\n    end\n\n    def setDetectHandlerH(h)\n        info.handler = <Aux.Handler>h\n    end\n|-<<<\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/ExtFlashDisabler/","title":"ExtFlashDisabler","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/ExtFlashDisabler/#unit-extflashdisabler","title":"unit ExtFlashDisabler","text":"ti.mcu.cc23xx/ExtFlashDisabler.em
package ti.mcu.cc23xx\n\nimport GpioT {} as CS\nimport GpioT {} as CLK\nimport GpioT {} as PICO\nimport GpioT {} as POCI\n\nfrom em.mcu import Common\n\nmodule ExtFlashDisabler\n\n    config CS_pin: int8\n    config CLK_pin: int8\n    config PICO_pin: int8\n    config POCI_pin: int8\n\nprivate:\n\n    const SD_CMD: uint8 = 0xb9\n\nend\n\ndef em$construct()\n    CS.pin = CS_pin\n    CLK.pin = CLK_pin\n    PICO.pin = PICO_pin\n    POCI.pin = POCI_pin\nend\n\ndef em$startup()\n    %%[c+]\n    CS.makeOutput()\n    CLK.makeOutput()\n    PICO.makeOutput()\n    POCI.makeInput()\n    # attention\n    CS.set()\n    Common.BusyWait.wait(1)\n    CS.clear()\n    Common.BusyWait.wait(1)\n    CS.set()\n    Common.BusyWait.wait(50)\n    # shutdown command\n    CS.clear()\n    for auto i = 0; i < 8; i++\n        CLK.clear()\n        if ((SD_CMD >> (7 - i)) & 0x01) == 0\n            PICO.clear()\n        else\n            PICO.set()\n        end\n        CLK.set()\n        Common.BusyWait.wait(1)\n    end\n    CLK.clear()\n    CS.set()\n    Common.BusyWait.wait(50)\n    #\n    CS.reset()\n    CLK.reset()\n    PICO.reset()\n    POCI.reset()\n    %%[c-]\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/GlobalInterrupts/","title":"GlobalInterrupts","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/GlobalInterrupts/#unit-globalinterrupts","title":"unit GlobalInterrupts","text":"ti.mcu.cc23xx/GlobalInterrupts.em
package ti.mcu.cc23xx\n\nfrom em.hal import GlobalInterruptsI\n\nmodule GlobalInterrupts: GlobalInterruptsI\n\nend\n\ndef disable()\n    auto key = <uarg_t>(^^__get_PRIMASK()^^)\n    ^^__set_PRIMASK(1)^^\n    return key\nend\n\ndef enable()\n    ^^__set_PRIMASK(0)^^\nend\n\ndef restore(key)\n    ^^__set_PRIMASK(key)^^\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/GpioT/","title":"GpioT","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/GpioT/#unit-gpiot","title":"unit GpioT","text":"ti.mcu.cc23xx/GpioT.em
package ti.mcu.cc23xx\n\ntemplate GpioT\n\n    const UNDEF: int16 = -1\n\n    config pin: int16 = UNDEF\n\nend\n\ndef em$generateUnit(pn, un)\n    auto bq = \"`\"\n    auto pre = ^^pn.replace(/[.]/g, '_') + '_' + un + '__'^^\n|->>>\n    package `pn`\n\n    from em.hal import GpioI\n\n    module `un`: GpioI\n\n        config pin: int16 = `pin`\n\n        function pinMask(): uint32    \n\n    private:\n\n        config isDef: bool\n        config mask: uint32\n\n    end\n\n    def em$construct()\n        isDef = pin != `UNDEF`\n        mask = isDef ? <uint32>(1 << <uint8>pin) : 0\n    end\n\n    def clear() \n        ^^HWREG(GPIO_BASE + GPIO_O_DOUTCLR31_0)^^ = mask if isDef\n    end\n\n    def set()\n        ^^HWREG(GPIO_BASE + GPIO_O_DOUTSET31_0)^^ = mask if isDef\n    end\n\n    def get()\n        return 0 if !isDef\n        return isInput() ? ((^^HWREG(GPIO_BASE + GPIO_O_DIN31_0)^^ & mask) != 0) : ((^^HWREG(GPIO_BASE + GPIO_O_DOUT31_0)^^ & mask) != 0)\n    end\n\n    def toggle()\n        ^^HWREG(GPIO_BASE + GPIO_O_DOUTTGL31_0)^^ = mask if isDef\n    end\n\n    def isInput()\n        return isDef && (^^HWREG(GPIO_BASE + GPIO_O_DOE31_0)^^ & mask) == 0\n    end\n\n    def isOutput()\n        return isDef && (^^HWREG(GPIO_BASE + GPIO_O_DOE31_0)^^ & mask) != 0\n    end\n\n    def makeInput()\n        ^^HWREG(GPIO_BASE + GPIO_O_DOECLR31_0)^^ = mask if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ |= ^IOC_IOC0_INPEN if isDef\n    end\n\n    def makeOutput()\n        ^^HWREG(GPIO_BASE + GPIO_O_DOESET31_0)^^ = mask if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ &= ~^IOC_IOC0_INPEN if isDef\n    end\n\n    def functionSelect(select)\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ = select if isDef\n    end\n\n    def setInternalPullup(enable)\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ |= ^IOC_IOC0_PULLCTL_PULL_UP if isDef && enable\n    end\n\n    def pinId()\n        return pin\n    end\n\n    def pinMask()\n        return mask\n    end\n\n    def reset()\n        ^^HWREG(GPIO_BASE + GPIO_O_DOECLR31_0)^^ = mask if isDef\n        ^^HWREG(IOC_BASE + IOC_O_IOC0 + pin * 4)^^ |= (^IOC_IOC0_IOMODE_M | ^IOC_IOC0_PULLCTL_M) if isDef\n    end\n|-<<<\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Idle/","title":"Idle","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Idle/#unit-idle","title":"unit Idle","text":"ti.mcu.cc23xx/Idle.em
package ti.mcu.cc23xx\n\nfrom em.hal import IdleI\nfrom em.lang import Debug\n\nmodule Idle: IdleI\n\n    type Callback: function()\n\n    host function addSleepEnterCbH(cb: Callback) \n    host function addSleepLeaveCbH(cb: Callback) \n\n    function doSleep()\n    function doWait()\n\n    function setWaitOnly(val: bool)\n\nprivate:\n\n    config sleepEnterCbTab: Callback[..]\n    config sleepLeaveCbTab: Callback[..]\n\n    var waitOnly: bool\n\nend\n\ndef em$startup()\n    %%[b+]\n    ^^HWREG(PMCTL_BASE + PMCTL_O_VDDRCTL)^^ = ^PMCTL_VDDRCTL_SELECT     # LDO\n    ^^HWREG(EVTULL_BASE + EVTULL_O_WKUPMASK)^^ = ^EVTULL_WKUPMASK_AON_RTC_COMB | ^EVTULL_WKUPMASK_AON_IOC_COMB\nend\n\ndef addSleepEnterCbH(cb)\n    sleepEnterCbTab[sleepEnterCbTab.length++] = cb\nend\n\ndef addSleepLeaveCbH(cb)\n    sleepLeaveCbTab[sleepLeaveCbTab.length++] = cb\nend\n\ndef doSleep()\n    for cb in sleepEnterCbTab\n        cb()\n    end\n    %%[b:2]\n    %%[b-]\n    Debug.sleepEnter()\n    ^^HWREG(CKMD_BASE + CKMD_O_LDOCTL)^^ = 0x0\n    ^^__set_PRIMASK(1)^^\n    ^^HapiEnterStandby(NULL)^^\n    Debug.sleepLeave()\n    %%[b+]\n    for cb in sleepLeaveCbTab\n        cb()\n    end\n    ^^__set_PRIMASK(0)^^\nend\n\ndef doWait()\n    %%[b:1]\n    %%[b-]\n    ^^__set_PRIMASK(1)^^\n    ^^asm(\"wfi\")^^\n    %%[b+]\n    ^^__set_PRIMASK(0)^^\nend\n\n\ndef exec()\n    if waitOnly\n        doWait()\n    else\n        doSleep()\n    end\nend\n\ndef setWaitOnly(val)\n    waitOnly = val\nend\n\ndef wakeup()\n    ## TODO -- implement\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/InterruptT/","title":"InterruptT","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/InterruptT/#unit-interruptt","title":"unit InterruptT","text":"ti.mcu.cc23xx/InterruptT.em
package ti.mcu.cc23xx\n\ntemplate InterruptT\n\n    config name: string\n\nend\n\ndef em$generateUnit(pn, un) \n    auto intrName = name\n    auto handlerNameQ = \"`\" + un + \".handlerName`\"\n|->>>\n    package `pn`\n\n    from ti.mcu.cc23xx import IntrVec\n\n    from em.hal import InterruptSourceI\n\n    module `un`: InterruptSourceI \n\n    private:\n        host var handlerName: string\n    end\n\n    def em$construct()\n        IntrVec.addIntrH(\"`intrName`\")\n    end\n\n    def em$generateCode( prefix )\n        if `un`.handlerName\n            |-> void `intrName`_Handler() {\n            |->     `handlerNameQ`();\n            |-> }\n        end\n    end\n\n    def setHandlerH(h)\n        handlerName = h ? ^^String(h).substring(1)^^ : null\n    end\n\n    def enable() \n        ^^NVIC_EnableIRQ(`intrName`_IRQn)^^\n    end\n\n    def disable() \n        ^^NVIC_DisableIRQ(`intrName`_IRQn)^^\n    end\n\n    def clear()\n        ^^NVIC_ClearPendingIRQ(`intrName`_IRQn)^^\n    end\n\n    def isEnabled() \n        return ^^NVIC_GetEnableIRQ(`intrName`_IRQn)^^\n    end\n|-<<<\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/IntrVec/","title":"IntrVec","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/IntrVec/#unit-intrvec","title":"unit IntrVec","text":"ti.mcu.cc23xx/IntrVec.em
package ti.mcu.cc23xx\n\nfrom em.hal import IntrVecI\n\nmodule IntrVec: IntrVecI\n\n    host function addIntrH(name: string)\n\nprivate:\n\n    const HARD_FAULT: uint32 = 3\n\n    type IsrFxn: function()\n\n    host config nameTab: string[] = [\n        \"NMI\",\n        \"HardFault\",\n        null,\n        null,\n        null,\n        null,\n        null,\n        null,\n        null,\n        \"SVC\",\n        null,\n        null,\n        \"PendSV\",\n        \"SysTick\",\n        \"CPUIRQ0\",\n        \"CPUIRQ1\",\n        \"CPUIRQ2\",\n        \"CPUIRQ3\",\n        \"CPUIRQ4\",\n        \"GPIO_COMB\",     \n        \"LRFD_IRQ0\",     \n        \"LRFD_IRQ1\",     \n        \"DMA_DONE_COMB\",     \n        \"AES_COMB\",      \n        \"SPI0_COMB\",     \n        \"UART0_COMB\",    \n        \"I2C0_IRQ\",     \n        \"LGPT0_COMB\",    \n        \"LGPT1_COMB\",    \n        \"ADC0_COMB\",     \n        \"CPUIRQ16\", \n        \"LGPT2_COMB\",    \n        \"LGPT3_COMB\",\n    ]\n\n    host config usedTab: string[]\n\n    config excHandler: ExceptionHandler\n\n    function nullIsr()\n\nend\n\ndef em$generateCode(prefix)\n|->>>\ntypedef void( *intfunc )( void );\ntypedef union { intfunc fxn; void* ptr; } intvec_elem;\n\n|-<<<\n    for n in nameTab\n        continue if n == null\n        |-> extern void `n`_Handler( void );\n        |-> #define `n`_ISR `prefix`::nullIsr\n    end    \n|->>>\n\n|-<<<\n    for u in usedTab\n        |-> #undef `u`_ISR\n        |-> #define `u`_ISR `u`_Handler\n    end    \n|->>>\n\nextern em_uint32 __stack_top__;\nextern \"C\" void __em_program_start( void );\nextern \"C\" const intvec_elem  __attribute__((section(\".intvec\"))) __vector_table[] = {\n    { .ptr = (void*)&__stack_top__ },\n    { .fxn = __em_program_start },\n|-<<<\n    for n in nameTab\n        if n == null\n            |->     0,\n        else\n            |->     { .fxn = `n`_ISR },\n        end\n    end    \n    |-> };\n|->>>\n\n|-<<<\nend\n\ndef em$startup()\n    ^^SCB->VTOR = (uint32_t)(&__vector_table)^^\nend\n\ndef addIntrH(name)\n    usedTab[usedTab.length++] = name\nend\n\ndef bindExceptionHandlerH(handler)\n    excHandler = handler\nend\n\ndef nullIsr()\n    auto vecNum = <uint32>(^^__get_IPSR()^^)\n    %%[b:4]\n    %%[><uint8>vecNum]\n    auto frame = <uint32[]>(^^__get_MSP()^^)\n    %%[><uint32>&frame[0]]\n    for auto i = 0; i < 8; i++\n        %%[b]\n        %%[>frame[i]]\n    end\n    fail\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Mcu/","title":"Mcu","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Mcu/#unit-mcu","title":"unit Mcu","text":"ti.mcu.cc23xx/Mcu.em
package ti.mcu.cc23xx\n\nfrom em.hal import McuI\n\nfrom em.lang import Debug\n\nmodule Mcu: McuI\n\n    config noCache: bool\n    config hasLfXtal: bool\n\nend\n\ndef getResetCode()\n    ## TODO -- implement\n    return 0\nend\n\ndef getStashAddr()\n    ## TODO -- implement\n    return null\nend\n\ndef isWarm()\n    ## TODO -- implement\n    return false\nend\n\ndef readEui48(dst)\n    ## TODO -- implement\nend\n\ndef reset(code)\n    ## TODO -- implement\nend\n\ndef startup()\n    Debug.startup()\n    if hasLfXtal\n        ^^HWREG(CKMD_BASE + CKMD_O_LFINCOVR) = 0x001E8480 | CKMD_LFINCOVR_OVERRIDE_M^^\n        ^^HWREG(CKMD_BASE + CKMD_O_LFCLKSEL) = CKMD_LFCLKSEL_MAIN_LFXT^^\n        ^^HWREG(CKMD_BASE + CKMD_O_LFXTCTL) = CKMD_LFXTCTL_EN^^\n        ^^HWREG(CKMD_BASE + CKMD_O_IMSET) = CKMD_IMASK_LFCLKGOOD^^\n    else\n        ^^HWREG(CKMD_BASE + CKMD_O_TRIM1) |= CKMD_TRIM1_NABIAS_LFOSC^^\n        ^^HWREG(CKMD_BASE + CKMD_O_LFCLKSEL) = CKMD_LFCLKSEL_MAIN_LFOSC^^\n        ^^HWREG(CKMD_BASE + CKMD_O_LFOSCCTL) = CKMD_LFOSCCTL_EN^^\n        ^^HWREG(CKMD_BASE + CKMD_O_LFINCCTL) &= ~CKMD_LFINCCTL_PREVENTSTBY_M^^\n        ^^HWREG(CKMD_BASE + CKMD_O_IMSET) = CKMD_IMASK_LFCLKGOOD^^\n    end\n    ^^HWREG(CLKCTL_BASE + CLKCTL_O_IDLECFG)^^ = 1 if noCache\n    ^^HWREG(VIMS_BASE + VIMS_O_CCHCTRL)^^ = 0 if noCache\nend\n\ndef shutdown()\n    ## TODO -- implement\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/MsCounter/","title":"MsCounter","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/MsCounter/#unit-mscounter","title":"unit MsCounter","text":"ti.mcu.cc23xx/MsCounter.em
package ti.mcu.cc23xx\n\nfrom em.hal import MsCounterI\n\nimport Rtc\n\nmodule MsCounter: MsCounterI\n\nprivate:\n\n    var t0: uint32\n\nend\n\ndef start()\n    t0 = Rtc.getMsecs()\nend\n\ndef stop()\n    return 0 if t0 == 0\n    auto t1 = Rtc.getMsecs()\n    auto dt = (t1 > t0) ? (t1 - t0) : (t0 - t1)\n    t0 = 0\n    return dt\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotGpt3/","title":"OneShotGpt3","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotGpt3/#unit-oneshotgpt3","title":"unit OneShotGpt3","text":"ti.mcu.cc23xx/OneShotGpt3.em
package ti.mcu.cc23xx\n\nimport InterruptT { name: \"LGPT3_COMB\" } as Intr\n\nimport BusyWait\nimport Idle\nimport Mcu\n\nfrom em.hal import OneShotMilliI\n\nmodule OneShotGpt3: OneShotMilliI\n\nprivate:\n\n    var curArg: ptr_t\n    var curFxn: Handler\n\n    function isr: Intr.Handler\n\nend\n\ndef em$construct()\n    Intr.setHandlerH(isr)\nend\n\ndef disable()\n    curFxn = null\n    Idle.setWaitOnly(false)\n    Intr.disable()\n    ^^HWREG(LGPT3_BASE + LGPT_O_ICLR) = LGPT_ICLR_TGT^^\nend\n\ndef enable(msecs, handler, arg)\n    curFxn = handler\n    curArg = arg\n    Idle.setWaitOnly(true)\n    Intr.enable()\n    ^^HWREG(CLKCTL_BASE + CLKCTL_O_CLKENSET0)^^ = ^CLKCTL_CLKENSET0_LGPT3\n    ^^HWREG(LGPT3_BASE + LGPT_O_IMSET) = LGPT_IMSET_TGT^^\n    ^^HWREG(LGPT3_BASE + LGPT_O_TGT)^^ = msecs * (Mcu.mclkFrequency / 1000)\n    ^^HWREG(LGPT3_BASE + LGPT_O_CTL) = LGPT_CTL_MODE_UP_ONCE | LGPT_CTL_C0RST^^\nend\n\ndef isr()\n    auto fxn = curFxn\n    disable()\n    fxn(curArg) if fxn\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTick/","title":"OneShotSysTick","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTick/#unit-oneshotsystick","title":"unit OneShotSysTick","text":"ti.mcu.cc23xx/OneShotSysTick.em
package ti.mcu.cc23xx\n\nimport InterruptT { name: \"SysTick\" } as Intr\n\nimport Idle\nimport Mcu\n\nfrom em.hal import OneShotMilliI\n\nmodule OneShotSysTick: OneShotMilliI\n\nprivate:\n\n    var curArg: ptr_t\n    var curFxn: Handler\n\n    function isr: Intr.Handler\n\nend\n\ndef em$construct()\n    Intr.setHandlerH(isr)\nend\n\ndef em$startup()\n    ^^SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk^^\nend\n\ndef disable()\n    curFxn = null\n    Idle.setWaitOnly(false)\n    Intr.disable()\n    ^^SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk)^^\nend\n\ndef enable(msecs, handler, arg)\n    curFxn = handler\n    curArg = arg\n    Idle.setWaitOnly(true)\n    Intr.enable()\n    ^^SysTick->LOAD^^ = msecs * (Mcu.mclkFrequency / 1000)\n    ^^SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk^^\nend\n\ndef isr()\n    auto fxn = curFxn\n    disable()\n    fxn(curArg) if fxn\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTim0/","title":"OneShotSysTim0","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/OneShotSysTim0/#unit-oneshotsystim0","title":"unit OneShotSysTim0","text":"ti.mcu.cc23xx/OneShotSysTim0.em
package ti.mcu.cc23xx\n\nimport InterruptT { name: \"CPUIRQ1\" } as Intr\n\nimport Idle\nimport Mcu\n\nfrom em.hal import OneShotMilliI\n\nmodule OneShotSysTim0: OneShotMilliI\n\nprivate:\n\n    var curArg: ptr_t\n    var curFxn: Handler\n\n    function isr: Intr.Handler\n\nend\n\ndef em$construct()\n    Intr.setHandlerH(isr)\nend\n\ndef disable()\n    curFxn = null\n    Idle.setWaitOnly(false)\n    Intr.disable()\n    ^^HWREG(SYSTIM_BASE + SYSTIM_O_ICLR) = SYSTIM_ICLR_EV0^^\nend\n\ndef enable(msecs, handler, arg)\n    curFxn = handler\n    curArg = arg\n    Idle.setWaitOnly(true)\n    Intr.clear()\n    Intr.enable()\n    ^^HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ1SEL) = EVTSVT_CPUIRQ1SEL_PUBID_SYSTIM0^^\n    ^^HWREG(SYSTIM_BASE + SYSTIM_O_IMSET) = SYSTIM_IMSET_EV0^^\n    auto time1u = <uint32>(^^HWREG(SYSTIM_BASE + SYSTIM_O_TIME1U)^^)\n    auto thresh = time1u + (msecs * 1000)\n    ^^HWREG(SYSTIM_BASE + SYSTIM_O_CH0CC)^^ = thresh\n    printf \"time1u = %d, thresh = %d\\n\", time1u, thresh\nend\n\ndef isr()\n    %%[a]\n    auto fxn = curFxn\n    disable()\n    fxn(curArg) if fxn\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Regs/","title":"Regs","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Regs/#unit-regs","title":"unit Regs","text":"ti.mcu.cc23xx/Regs.em
package ti.mcu.cc23xx\n\nmodule Regs\n\nend\n\ndef em$generateCode(prefix)\n|->>>\n    #include \"cmsis/cc23x0r5.h\"\n    #include \"cmsis/core/core_cm0plus.h\"\n\n    #include \"driverlib/hapi.h\"\n\n    #include \"inc/hw_memmap.h\"\n    #include \"inc/hw_types.h\"\n\n    #include \"inc/hw_ckmd.h\"\n    #include \"inc/hw_clkctl.h\"\n    #include \"inc/hw_evtull.h\"\n    #include \"inc/hw_evtsvt.h\"\n    #include \"inc/hw_gpio.h\"\n    #include \"inc/hw_ioc.h\"\n    #include \"inc/hw_lgpt.h\"\n    #include \"inc/hw_lgpt3.h\"\n    #include \"inc/hw_pmctl.h\"\n    #include \"inc/hw_rtc.h\"\n    #include \"inc/hw_systim.h\"\n    #include \"inc/hw_uart.h\"\n    #include \"inc/hw_vims.h\"\n\n    #include \"inc/hw_ccfg.h\"\n\n#if 0\n\n    extern \"C\" const ccfg_t __ccfg __attribute__((section(\".ccfg\"), used)) = {\n\n        .bootCfg.pBldrVtor = XCFG_BC_PBLDR_UNDEF,\n\n        .bootCfg.bldrParam.serialRomBldrParamStruct.bldrEnabled = XCFG_BC_BLDR_DIS,\n        .bootCfg.bldrParam.serialRomBldrParamStruct.serialIoCfgIndex = 0,\n        .bootCfg.bldrParam.serialRomBldrParamStruct.pinTriggerDio = 0,\n        .bootCfg.bldrParam.serialRomBldrParamStruct.pinTriggerEnabled = XCFG_BC_PINTRIG_DIS,\n        .bootCfg.bldrParam.serialRomBldrParamStruct.pinTriggerLevel = XCFG_BC_PINTRIG_LEVEL_LO,\n        .bootCfg.pAppVtor = (void*)0x0,\n\n        .hwOpts = {0xffffffff, 0xffffffff},\n\n        .permissions.allowDebugPort = CCFG_PERMISSION_ALLOW,\n        .permissions.allowEnergyTrace = CCFG_PERMISSION_ALLOW,\n        .permissions.allowFlashVerify = CCFG_PERMISSION_ALLOW,\n        .permissions.allowFlashProgram = CCFG_PERMISSION_ALLOW,\n        .permissions.allowChipErase = CCFG_PERMISSION_ALLOW,\n        .permissions.allowToolsClientMode = CCFG_PERMISSION_ALLOW,\n        .permissions.allowFakeStby = CCFG_PERMISSION_ALLOW,\n        .permissions.allowReturnToFactory = CCFG_PERMISSION_ALLOW,\n\n        .misc.saciTimeoutOverride = 1U,\n        .misc.saciTimeoutExp = 7,\n\n        .flashProt.writeEraseProt.mainSectors0_31 = 0xffffffff,\n        .flashProt.writeEraseProt.mainSectors32_255 = 0xffffffff,\n\n        .flashProt.writeEraseProt.ccfgSector = 0,\n        .flashProt.writeEraseProt.fcfgSector = 0,\n        .flashProt.writeEraseProt.engrSector = 0,\n\n        .flashProt.res = 0xFFFFFFFFU,\n\n        .flashProt.chipEraseRetain.mainSectors0_31 = 0x0,\n        .flashProt.chipEraseRetain.mainSectors32_255 = 0x0,\n\n        .debugCfg.authorization = CCFG_DBGAUTH_DBGOPEN,\n        .debugCfg.allowBldr = CCFG_DBGBLDR_ALLOW,\n        .debugCfg.pwdId = {0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15},\n        .debugCfg.pwdHash = {0x6d, 0xd7, 0xe4, 0x36, 0xeb, 0xf4, 0x31, 0xdf,\n                            0x95, 0xae, 0x15, 0xee, 0x03, 0xba, 0x8e, 0xe4,\n                            0xc4, 0xc6, 0x3f, 0xd8, 0x45, 0x3f, 0x67, 0x5e,\n                            0x74, 0xd7, 0xc2, 0x01, 0x2c, 0x90, 0x58, 0xe5},\n    };\n\n#else\n\n    extern \"C\" const uint32_t __ccfg[] __attribute__((section(\".ccfg\"), used)) = {\n        0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,\n        0xFFFFFFFF, 0xFFFFFFFF, 0xAAAAAAAA, 0x0000000F,\n        0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x00000000, 0x00000000, 0x00000000, 0x00000000,\n        0x0000A55A, 0x03020101, 0x150D0805, 0x36E4D76D,\n        0xDF31F4EB, 0xEE15AE95, 0xE48EBA03, 0xD83FC6C4,\n        0x5E673F45, 0x01C2D774, 0xE558902C, 0x00000000,\n    };\n#endif\n|-<<<\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Rtc/","title":"Rtc","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Rtc/#unit-rtc","title":"unit Rtc","text":"ti.mcu.cc23xx/Rtc.em
package ti.mcu.cc23xx\n\nimport InterruptT { name: \"CPUIRQ0\" } as Intr\n\nmodule Rtc\n\n    type Handler: function()\n\n    function disable()\n    function enable(thresh: uint32, handler: Handler)\n    function getMsecs(): uint32\n    function getRaw(oSubs: uint32*): uint32\n    function toThresh(ticks: uint32): uint32\n    function toTicks(secs256: uint32): uint32\n\nprivate:\n\n    const MSECS_SCALAR: uint16 = 1000 / 8\n    const RES_BITS: uint8 = 20\n\n    var curHandler: Handler\n\n    function isr: Intr.Handler\n\nend\n\ndef em$construct()\n    Intr.setHandlerH(isr)\nend\n\ndef em$startup()\n    ^^HWREG(CKMD_BASE + CKMD_O_LFINCOVR)^^ = 0x80000000 + (1 << RES_BITS)\n    ^^HWREG(RTC_BASE + RTC_O_CTL)^^ = ^RTC_CTL_RST\n    ^^HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ0SEL) = EVTSVT_CPUIRQ0SEL_PUBID_AON_RTC_COMB^^\n    Intr.enable()\nend\n\ndef disable()\n    curHandler = null\n    ^^HWREG(RTC_BASE + RTC_O_IMCLR)^^ = ^RTC_IMCLR_EV0\nend\n\ndef enable(thresh, handler)\n    curHandler = handler\n    ^^HWREG(RTC_BASE + RTC_O_CH0CC8U)^^ = thresh\n    ^^HWREG(RTC_BASE + RTC_O_IMSET)^^ = ^RTC_IMSET_EV0\nend\n\ndef getMsecs()\n    auto ticks = <uint32>^^HWREG(RTC_BASE + RTC_O_TIME8U)^^\n    return (ticks * MSECS_SCALAR) >> (RES_BITS - 7)\nend\n\ndef getRaw(oSubs)\n    var lo: uint32\n    var hi: uint32\n    for ;;\n        lo = ^^HWREG(RTC_BASE + RTC_O_TIME8U)^^\n        hi = ^^HWREG(RTC_BASE + RTC_O_TIME524M)^^\n        break if lo == ^^HWREG(RTC_BASE + RTC_O_TIME8U)^^\n    end\n    *oSubs = lo << 16\n    return hi\nend\n\ndef isr()\n    ^^HWREG(RTC_BASE + RTC_O_ICLR)^^ = ^RTC_ICLR_EV0\n    curHandler() if curHandler\nend\n\n\ndef toThresh(ticks)\n    return ^^HWREG(RTC_BASE + RTC_O_TIME8U)^^ + ticks\nend\n\ndef toTicks(secs256)\n    return secs256 << 8\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Uptimer/","title":"Uptimer","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/Uptimer/#unit-uptimer","title":"unit Uptimer","text":"ti.mcu.cc23xx/Uptimer.em
package ti.mcu.cc23xx\n\nimport Rtc\n\nfrom em.hal import UptimerI\n\nmodule Uptimer: UptimerI\n\nprivate:\n\n    var curTime: Time\n\nend\n\ndef calibrate(secs256, ticks)\n    ## TODO -- implement\n    return 0\nend\n\ndef read()\n    curTime.secs = Rtc.getRaw(&curTime.subs)\n    return curTime\nend\n\ndef resetSync()\n    ## TODO -- implement\nend\n\ndef trim()\n    ## TODO -- implement\n    return 0\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/UsCounter/","title":"UsCounter","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/UsCounter/#unit-uscounter","title":"unit UsCounter","text":"ti.mcu.cc23xx/UsCounter.em
package ti.mcu.cc23xx\n\nfrom em.hal import UsCounterI\n\nimport Mcu\n\nmodule UsCounter: UsCounterI\n\nend\n\ndef start()\n    ^^SysTick->CTRL = (1 << SysTick_CTRL_CLKSOURCE_Pos) | (1 << SysTick_CTRL_ENABLE_Pos)^^\n    ^^SysTick->LOAD = 0xFFFFFF^^\n    ^^SysTick->VAL = 0^^\nend\n\ndef stop()\n    auto lr = <uint32>^^SysTick->LOAD^^\n    auto vr = <uint32>^^SysTick->VAL^^\n    auto dt = (((lr - vr) << 1) / (Mcu.mclkFrequency / 1000000)) >> 1\n    ^^SysTick->CTRL = 0^^\n    return dt\nend\n
"},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/WakeupTimer/","title":"WakeupTimer","text":""},{"location":"cargo/ti.cc23xx/ti.mcu.cc23xx/WakeupTimer/#unit-wakeuptimer","title":"unit WakeupTimer","text":"ti.mcu.cc23xx/WakeupTimer.em
package ti.mcu.cc23xx\n\nfrom em.hal import WakeupTimerI\n\nimport Rtc\n\nmodule WakeupTimer: WakeupTimerI\n\nend\n\ndef disable()\n    Rtc.disable()\nend\n\ndef enable(secs256, handler)\n    Rtc.enable(secs256, <Rtc.Handler>handler)\nend\n\ndef secs256ToTicks(secs256)\n    return secs256 << 8\nend\n\ndef ticksToThresh(ticks)\n    return Rtc.toThresh(ticks)\nend\n\ndef timeToTicks(secs, subs)\n    return (secs << 16) | (subs >> 16)\nend\n
"},{"location":"intro/","title":"Why another language\u2009???","text":"

For the past fifty years, the C Programming Language has significantly streamlined software development for resource-constrained embedded microcontrollers [MCUs]. Already coming into maturity by 1980, C had proven itself as a practical \u201cmedium-level\u201d language for many of the first 8\u2009/\u200916\u2009/\u200932-bit MCUs \u2013 enabling full entitlement to the underlying silicon, while offering developers greater software productivity and portability over native assembly language.

As a testimony to its staying power, C continues to this day as the dominant programming language for resource-constrained MCUs; and given that we still write embedded software targeting 8\u2009/\u200916\u2009/\u200932-bit processors \u2013 often with less than 32K of memory \u2013 do we really have a practical alternative to C\u2009???\u00a0\u00a0 Yes, we do \u2013 EM.

Other embedded programming languages

Besides C and assembler, practitioners cite C++, Java, and Python as other languages of choice for embedded software development \u2013 with interest in Go and Rust starting to grow. For a variety of reasons, none of these languages come close to overtaking the dominant position of C:\u00a0 developers often fear a steep learning curve with a new language, offsetting any potential gain in productivity; and the language itself might introduce additional runtime overhead in time and (especially) space that render it impractical for the most resource-constrained MCUs.

"},{"location":"intro/#the-big-picture","title":"The big picture","text":"

The EM software platform comprises a novel programming language and run-time environment which targets resource-constrained embedded hardware \u2013 on the low-end, systems potentially managed by 8-bit MCUs using as little as 4\u2009K of program memory and 256\u2009B of data. Compared with C, EM features a higher-level programming paradigm centered around highly-reusable software modules which embody the principles of encapsulation, abstraction, and composition.

At the same time, higher-level language constructs introduced by EM don't necessarily cause higher-levels of run-time overhead; modular EM applications designed using modern software techniques will often outperform comparable C programs written in a more conventional style. As you'll learn later on, the EM language translator will in fact generate monolithic C/C++ programs from a set of EM source modules \u2013 leveraging the maturity and ubiquity of optimizing C/C++compilers for embedded MCUs.

More than a programming language, the EM platform also features a modular run-time environment (written in EM, of course\u2009!!!) which streamlines developer productivity through software re-use as well as increases application portability through abstraction \u2013 all without compromising overall system performance. The EM run-time modules include basic services which handle and dispatch real-time application events, as well as device-drivers which manage hardware peripherals typically found within embedded MCUs.

Write once, run anywhere

Not unlike other software platforms ranging from Java and Linux to Ruby and Python, EM offers up a \"write once, run anywhere\u2009...\" value-proposition for its application developers. The difference, needless to say, lies in the underlying hardware configurations targeted by EM \u2013 memory-constrained MCUs otherwise incapable of supporting Java or Linux (let alone Ruby or Python), for which C has remained the dominant programming environment for over a half-century.

"},{"location":"intro/#tiny-code-tiny-chips","title":"Tiny code \u2192 Tiny chips","text":"

EM programs typically consume less memory than their C counterparts \u2013 a critical feature when targeting resource-constrained MCUs. With 3\u2009X\u2009\u2013\u20095\u2009X reductions in program size not uncommon in practice, many real-world EM applications can comfortably fit in (say) a 32K memory space.

The latest 32-bit MCUs deployed in edge-computing applications will often feature generous amounts of flash memory [\u2009\u2265\u2009512K\u2009] for storing program code, as well as large blocks of SRAM [\u2009\u2265\u200964K\u2009] for reading\u2009+\u2009writing program data; these MCUs also feature processors with sophisticated pipelines as well as advanced memory caches \u2013 all boosting the performance of large (and ever-growing\u2009!!!) bodies of legacy C code used in today's applications.

But what if our EM-based applications really did require only 32\u2009K of memory\u2009???

We could take conventional MCU designs \"over-the-edge\" by embracing a radically simple set of hardware featues which collectively would define the fringe of embedded processing:

\u00a0entry-level CPU core\u00a0 \u2009 no larger than Arm Cortex-M0+ \u00a0tightly-coupled memories (TCMs)\u00a0 \u2009code\u2009+\u2009data; \u2264\u200932K per bank; zero wait-state SRAM \u00a0bulk flash and NO cache\u00a0 \u2009TCMs loaded under firmware control \u00a0rudimentary peripherals\u00a0 \u2009 no specialized auxiliary CPU cores \u00a0always-on domain\u00a0 \u2009 wakeup events from deep-sleep power modes \u00a0\u2265\u2009100MHz system clock\u00a0 \u2009no TCM wait-states \u2192 maximize CPU throughput

Features through would collectively minimize the number of logic gates and memory cells required to implement this MCU in silicon \u2013 resulting in a smaller chip die compared with a more fully-featured design, which (holding other factors constant) forecasts lower manufacturing costs as well as lower leakage power.

To support \"sleepy applications\" with short active-duty cycles, feature enables our MCU to execute for years on small batteries \u2013 or even indefinitely using harvested energy. Because of its relatively small die-size, our MCU could likely consume \u2264\u20091\u03bcW of power when sleeping; and by retaining all program state in the (small) TCMs of , our MCU can quickly return to its fully-powered active mode when awoken by an event.

Feature , however, seems at odds with achieving an energy-efficient design \u2013 faster clocks proportionally increase switching (dynamic) power consumption; but since the CPU can access its TCMs without stalling, increased clock speed also results in proportionally faster software execution \u2013 enabling our duty-cycled application to spend more time in deep-sleep. In practice, this approach actually improves overall energy(1)utilization by reducing the (static) overhead of leakage power during active execution periods.

  1. E = \u222b\u2009 (Pleakage + Pswitching) dt

Given that feature enables faster execution, the peripherals of can now leverage software running on the main CPU core to perform functions that would otherwise require additional hardware \u2013 such as advanced encryption modes or the upper layers of a comm stack. Unlike conventional cryto or radio blocks (which often contain their own dedicated cores) our peripherals embody a \"RISC-like\" approach which efficiently implements only rudimentary primitives in hardware and then relegates higher-levels functions to software.

EM programs that target our idealized MCU will often exhibit a simple, cyclic structure:

wake-up from deep-sleep

acquire data from the environment

analyze this data using an algorithm

transmit results (wirelessly) to the edge

re-enter deep-sleep

Because of their single-threaded design, these programs would only require a single CPU core to maximize application throughput; software functions normally relegated (say) to an auxiliary cyrto or radio core can now execute exclusively on the main CPU. Consolidating all software onto a single core not only maximizes re-use of MCU logic elements, but can further reduce cost and power by minimizing the silicon footprint of certain peripherals.(1)

  1. We'll return to this topic further downstream.

So thanks to EM \u2013 10\u2009X fewer bytes, 10\u2009X fewer transistors, 10\u2009X lower power, 10\u2009X lower cost\u2009!!!

The promise of RISC-V

The emergence of RISC-V as an open instruction-set architecture has triggered an abundance of innovation in MCU design; you can literally find dozens of open-source projects containing synthesizable cores expressed in languages like Verilog and VHDL. While much of the RISC-V community has set its sights on high-performance computing from the edge up to the cloud, some practitioners have focused on \"tiny cores\" suitable for low-power, low-cost applications on the fringe; visit the X-HEEP and NEORV32 projects as examples.

With more degrees of freedom when implementing the entry-level RV32ICM instruction set \u2013 often compared against the ARM Cortex-M0+ \u2013 MCU designers can truly innovate when realizing our earlier feature \u2013 all in the interest of further shrinking silicon and software:

Here again, the tiny-code of EM serves as a catalyst which can drive novel RISC-V tiny-chips.

"},{"location":"intro/#technical-overview","title":"Technical overview","text":"

Building upon the tiny\u00a0code\u2009\u2192\u2009tiny\u00a0chips premise behind EM, let's dive into some technical details.\u00a0 The following chapters each focus on a particular aspect of the language and its runtime enviorment, and collectively provide a technical overview of the EM platform:

1)\u2003 EM modules & interfaces \u2022\u2022\u2022 The client/server dichotomy\u2003\u2003 2)\u2003 EM composites & templates \u2022\u2022\u2022 Assembling application elements\u2003\u2003 3)\u2003 EM program life-cycle \u2022\u2022\u2022 From build-time to run-time\u2003\u2003 4)\u2003 EM runtime bundles \u2022\u2022\u2022 Software platform content\u2003\u2003

We encourage you to read these chapters in sequence, as each subsequent chapter builds on material covered by its predecessors. At the same time, we recognize that this document introduces a lot of (new) information about a (new) programming environment; feel free to proceed iteratively, skimming the content on your first pass before circling back for a more thorough reading.

The technical overivew also includes exemplary source-code fragments, written in the EM programming language and formatted as follows:

Hello.em
# we've omitted a few details here\n# but you should get the basic idea\n\nmodule Hello\nend\n\ndef em$run()\n    printf \"Hello world\\n\"\nend\n

Even if you don't plan to (initially) install and use EM, these fragments should give you an intuitive sense of the language \u2013 which relies upon familiar programming constructs (such as seen at line 8 above) that you've likely encountered elsewhere.

So with that, let's move onward to Chapter 1 and begin our technical overview of EM.

"},{"location":"intro/#the-history-of-em","title":"The history of EM","text":"

EM's origin story

The EM programming language first appeared at UC Santa Barbara in 2010, where undergraduate students taking CS190C\u2009/\u2009ECE1940 would develop \u201creal-world\u201d embedded applications targeting resource-constrained MCUs \u2013 with all software written in EM, of course, using this (now outdated) language primer as a guide.

The EM language had emerged through deep discussion and intense interaction with Amichai Amar \u2013 a UCSB PhD candidate at that time. Consult his thesis for more details on the outcome of our undergraduate course, as well as a more comprehensive exposition of programming resource-constrained MCUs using EM.

But the true EM backstory actually began decades before its debut at UCSB. In 1998, Texas Instruments acquired Spectron Microsystems \u2013 whose SPOX and DSP\u2009/\u2009BIOS products had already emerged as de facto industry standards. This milestone validated the importance of software technology in further solidifying TI's leadership as a DSP silicon vendor, and in fact triggered a flurry of similar acquisitions during the dot-com boom.

Once inside TI, the Spectron team broadened the application of its patented configuration technology \u2013 which had already enabled DSP\u2009/\u2009BIOS to fit comfortably within the 2\u2009K boot ROM of broadly-deployed, low-power DSPs. This effort culminated in the open-source RTSC project, hosted at the Eclipse Foundation beginning in 2007 and still used today within TI software products. But RTSC fell a bit short in fulfilling its vision \u2013 and provided some much needed impetus for the birth of EM a few years later.

EM's coming-of-age began in 2011 with the founding of Emmoco \u2013 an early player offering an embedded\u2009\u2194\u2009mobile connectivity stack targeting new TI wireless MCUs which supported the emerging BLE standard. Acquired by Shelfbucks in late 2015, the Emmoco stack ultimately evolved to support long-range, low-power subGHz radios in which just one cloud-connected HUB could interact with (say) 10,000 TAGs in a 500,000 sq ft venue.

After Shelfbucks ceased operations in 2019 \u2013 and thanks to some legacy licensing agreements \u2013 EM found its way onto other low-power wireless MCUs from vendors such as NXP, Analog Devices, and ON Semiconductor; EM's foray into the world of RISC-V (as detailed in an earlier note) also began in this time frame. Targeting very high-volume applications for over a decade now, EM's uncanny ability to reduce firmware footprint proved critical in keeping system size, power, and cost in check.

As of today, EM has supported more than twenty 8\u2009/\u200916\u2009/\u200932-bit MCUs from almost a dozen silicon vendors. The EM language translator \u2013 which ultimately outputs ANSI C/C++ code for portability \u2013 has also targeted the most popular toolchains for embedded development [GCC, IAR, Keil, LLVM].\u00a0 Thanks to a recent rewrite of the translator into TypeScript, EM now enjoys robust language support within the VS Code IDE.

More important, perhaps, just a handful of EM programmers have developed thousands of EM modules used (and often re-used\u2009) across a broad spectrum of IoT applications targeting these MCUs. But due to the proprietary nature of these applications, the EM language and its runtime has remained closed \u2013 until now\u2009!!!

"},{"location":"intro/to-1/","title":"The client/supplier dichotomy","text":"

EM revolves around the concept of a concrete module, a programmatic construct that plays a seminal role within the language comparable to the position held by a class within C++ or Java. Not unlike classes, each EM module defines a programmatic boundary between its clients \u2013 users of the module \u2013 and the supplier of the module itself.

To minimize direct coupling between clients and suppliers \u2013 and therefore to increase software re-use \u2013 EM also supports module abstraction through an interface construct which clients in turn can leverage through a module proxy.

"},{"location":"intro/to-1/#source-code-structure","title":"Source-code structure","text":"

Reflecting a basic dichotomy between module clients and module suppliers, consider the overall organization of a sample EM module named Mod1, whose source code will reside in a file named Mod1.em:

bob.pkg/Mod1.em
package bob.pkg\n\nmodule Mod1         # client-visible feature declarations\n    const C: ...\n    type T:  ...\n    function f( ... )\n    # etc\n\nprivate:            # supplier-proprietary feature declarations\n    var x: ...\n    function g( ... )\n    # etc\nend\n\ndef f(...)          # supplier-proprietary function definitions\n    # body of 'f'\nend\n\ndef g(...)\n    # body of 'g'\nend\n\n# etc...\n

Starting from the top, each EM module lives within the logical scope of a package which physically corresponds to a file-system directory of the same name. As in Java or Python, an EM package will generally bear a globally-unique qualified name that identifies its supplier \u2013 bob.pkg, bob.pkg.test, dave.pkg, and so forth. By extension, all EM modules have a (globally-unique) fully-qualified canonical name \u2013 bob.pkg/Mod1 in the current example \u2013 though in practice you'll invariably refer to modules using simple names like Mod1.

Flat directory structure

But unlike Java or Python, where the contents of a package named bob.pkg would actually reside in a nested directory structure with the path bob/pkg, EM employs a flat organization in which the logical package-name and physical directory-name must match exactly.

Moving on, the declarations beginning at line 3 comprise the public specification of this module \u2013 a coherent collection of constants, types, and functions (what others might term an \"API\"\u2009) available for direct use by clients of Mod1. Taken together, these externally-visible features of the module constitute a programmatic contract in which future changes on the part of the supplier should (hopefully!!!\u2009) not violate prior client assumptions.

By contrast, features of Mod1 declared beginning at line 9 along with all definitions of its public and private functions beginning at line 15 remain hidden from any clients of this module. The supplier of Mod1 can consequently change the internal implementation of this module \u2013 optimizing performance or improving robustness \u2013 while maintaining a measure of \"plug-compatibility\" from its clients' perspective.

Separation of concerns

By enforcing crisp boundaries between clients and suppliers, EM modules encourage a software \"best-practice\" known as separation of concerns \u2013 organizing application functionality into discrete programmatic elements that encapsulate specific implementation decisions. Besides helping us digest software-rich systems in \"bite-sized\" chunks (where each EM module becomes a small world unto itself), our ability to manage change throughout the software life-cycle emerges as the most enduring benefit of modularity in general.

"},{"location":"intro/to-1/#importing-modules","title":"Importing modules","text":"

To gain access to public features of bob.pkg/Mod1, clients must explicitly import this module within their own\u2009.em files prior to any direct usage. As an illustration, consider a sample module named dave.pkg/Mod2:

dave.pkg/Mod2.em
package dave.pkg\n\nfrom bob.pkg import Mod1\n\nmodule Mod2       # client-visible feature declarations\n    function f( ... )\n\nprivate:          # supplier-proprietary feature declarations\n    var t: Mod1.T\nend\n\ndef f(...)        # supplier-proprietary function definitions\n    Mod1.f( ... )\nend\n

The directive at line 3 effectively adds the identifier Mod1 to this file's top-level namespace, which already includes all public\u2009/\u2009private feature names of Mod2; an optional trailing as clause can resolve name conflicts, should they arise. Through their import directives, EM modules organize themselves into a static hierarchy of clients and suppliers. As a rule, this client-supplier relation must remain acyclic; an EM module can neither directly nor indirectly import itself.

After importing Mod1, the example accesses this module's public type T at line 9 followed by its public function f at line 13 using a qualified name of the form Mod1.feature. This syntax enables client modules using Mod1 to (coincidentally) declare their own features with identical names, such as the function f defined here within the scope of Mod2; unqualified identifiers always refer to features defined within the current module.

Main programs

By implementing a special (intrinsic) function named em$run, any EM module can potentially serve as the entry-point for an executable application \u2013 a common pattern in many modern languages. Said another way, EM has no inherent notion of a \"main-program\"; instead, application developers will designate a particular module as the top of a client-supplier hierarchy defined via import directives.

"},{"location":"intro/to-1/#abstracting-suppliers","title":"Abstracting suppliers","text":"

At the end of the day, EM application programs comprise a set of concrete modules \u2013 each contributing some measure of encapsulated code and data to the final executable image. In the example above, where we directly imported bob.pkg/Mod1, this module will auto\u00admatically and unconditionally become an element of any application program that directly or indirectly uses dave.pkg/Mod2.

As an alternative to this mode of direct coupling between modules, EM introduces a language construct known as a proxy that adds a level of indirection between clients and suppliers \u2013 abstracting a particular supplier's identity from the client's perspective. Akin to polymorphism within object-oriented programming, EM proxies can enhance application flexibility and improve software re-use by further decoupling clients from suppliers; the same client module, as you'll soon see, can effectively (re-)use different supplier imple\u00admentations of otherwise common functionality.

And even more important than re-use, we can better manage change\u2009!!!

By not having to modify client modules that employ proxies, our software becomes more resilient and malleable when \u2013 and not if \u2013 application requirements evolve over time.

To capture commonality amongst a family of \"plug-compatible\" modules, EM enables us to separately publish a set of client-visible features as an interface \u2013 a public specification independent of any particular supplier implementation. As an illustration, let's refactor the bob.pkg/Mod1 module presented earlier.

bob.pkg/ModI.em

package bob.pkg\n\ninterface ModI             # public specification only  \n    const C: ...\n    type T:  ...\n    function f( ... )\nend\n
bob.pkg/Mod1.em
package bob.pkg\n\nfrom bob.pkg import ModI\n\nmodule Mod1: ModI         # public specification  \n    # additional features\n\nprivate:                  # internal implementation\n    # same as before\nend\n\ndef f()\n    # body of 'f'\nend\n\n# etc...\n

The declarations beginning at line 3 mimic the earlier public specification of bob.pkg/Mod1; but unlike a concrete module, an abstract EM interface cannot have an internal implementation. Our new rendition of Mod1 now inherits its public specification from the interface ModI at line 3, while declaring any additional (public) features unique to this module; the private portion of Mod1 beginning at line 8 remains unchanged from before.

More on interfaces

In practice, abstract interfaces and implementing modules will often reside in different packages: for instance, the EM runtime contains a package named em.hal holding ConsoleUartI, GpioI, WakeupTimerI, and other interfaces; packages such as ti.mcu.cc23xx then hold concrete implementations of these abstract interfaces targeting a particular MCU architecture.

Returning to the matter at hand \u2013 abstracting suppliers \u2013 we'll now refactor our original dave.pkg/Mod2 client module to remove its direct dependence on bob.pkg/Mod1 and instead leverage a local proxy implementing the ModI interface.

dave.pkg/Mod2.em
package dave.pkg\n\nfrom bob.pkg import ModI\n\nmodule Mod2       # client-visible feature declarations\n    proxy ModX: ModI\n    function f( ... )\n\nprivate:          # supplier-proprietary feature declarations\n    var t: ModX.T\nend\n\ndef f(...)        # supplier-proprietary function definitions\n    ModX.f( ... )\nend\n

The syntax at line 6 adds the name ModX to the top-level scope of Mod2, as well as declares that the proxy ModX provides all client features specified within the interface ModI; access to the public type T and the public function f at lines 10 and 14 respectively mirror earlier direct usage of bob.pkg/Mod1.

Once again, we should emphasize that client Mod2 has no overt coupling to the concrete module Mod1; instead, Mod2 only knows about the abstract interface ModI \u2013 which would admit an unbounded number of alternate implementations beyond that provided by Mod1.

The proxy\u2009\u2013\u2009interface pattern

The pattern exemplified here occurs extensively within the EM runtime, and largely holds the key to maintaining platform portability. As a case in point, the package em.utils contains only portable modules such as AlarmMgr which declares a local proxy implementing the em.hal/WakeupTimerI interface. Client application modules likewise desiring hardware independence can simply follow suit, using the proxy\u2009\u2013\u2009interface pattern at each point of potential variability.

Moving on to Chapter 2, we'll now explore the process of binding the Mod2.ModX proxy to the Mod1 module.

"},{"location":"intro/to-2/","title":"Assembling application elements","text":"

By leveraging the proxy\u2009\u2013\u2009interface design pattern, EM modules exhibit component-like qualities \u2013 enabling third-party integrators to effectively compose a set of modules that otherwise have no direct knowledge of one another.

To facilitate general aggregation and assembly of discrete modules into larger application entities, the EM language introduces a multi-faceted construct known as a composite to service these needs.

"},{"location":"intro/to-2/#aggregating-modules","title":"Aggregating modules","text":"

Like modules and interfaces, each EM composite resides under a named package and will import other units \u2013 modules, interfaces, even composites \u2013 into its top-level namespace. Consistent with their role as higher-level collection points for discrete modules, EM composites will often import surprisingly large numbers of modules in practice.(1)

  1. ti.distro.cc23xx/McuC for example

In their most elementary form, EM composites will selectively export a group of concrete modules under logical names known to higher-level clients.

bob.pkg/CompC.em
package bob.pkg\n\nimport Mod1 as ModX     # omit redundant 'from' clause\n\nexport ModX             # a logical module\n\ncomposite CompC             \nend\n

After re-labeling bob.pkg/Mod1 at line 3 using an as clause, the export directive at line 5 publicizes the name ModX; clients importing CompC can then use the (logical) module named ModX, otherwise oblivious to its true identity as bob.pkg/Mod1. While not declared explicitly, ModX in fact belongs to the ModI family of modules \u2013 serving as a concrete delegate suitable for binding to an abstract proxy implementing a common programmatic interface.

Component-oriented programming

Programming with components \u2013 which takes modularity, separation of concerns, and resilience in the face of change to entirely new levels \u2013 dictates that (abstract) interfaces define all functional interactions between independently-replaceable elements. As such, each (concrete) software component \"provides\" and \"requires\" services defined by some set of interfaces \u2013 not unlike the standardized \"plugs\" and \"sockets\" found in hardware components. Through disciplined use of export directives within EM composites and proxy declarations within EM modules, we can emulate the provides\u2009\u2013\u2009requires paradigm that forms the backbone of all component-oriented systems.

"},{"location":"intro/to-2/#binding-proxies","title":"Binding proxies","text":"

Besides aggregating modules, EM composites will often take on the task of \"wiring\" together a set of modules into a more integrated assembly \u2013 especially modules like our last version of dave.pkg/Mod2, which utilize local proxies to further decouple themselves from potential suppliers. To illustrate:

geof.pkg/CompC.em
package geof.pkg\n\nfrom bob.pkg import Mod1      # concrete delegate\nfrom dave.pkg import Mod2     # exposes abstract proxy\n\ncomposite CompC\n    # no features\nend\n\ndef em$configure()\n    Mod2.ModX ?= Mod1         # bind proxy to its delegate\nend\n

Reflecting its higher-level position within the application hierarchy, this particular composite reaches across multiple packages starting at line 3 when importing a set of modules. The actual binding of bob.pkg/Mod1 to dave.pkg/Mod2 via the latter's ModX proxy then occurs at line 11, using a special single-assignment operator [\u2009?=\u2009] which we'll explain later. We'll also have more to say about the role played by the intrinsic function em$configure.

EM distro packages

To use the EM language, you'll need an EM distro \u2013 a multi-tiered sub-system that melds portable runtime content in packages like em.utils with hardware-specific content in packages like ti.mcu.cc23xx. By design, each EM distro will publish a top-level composite with a fully-qualified name like ti.distro.cc23xx/BoardC. This BoardC composite in turn builds upon other composites \u2013 whether hardware-specific ti.distro.cc23xx/McuC or else portable em.mcu/CommonC.

"},{"location":"intro/to-2/#configuring-parameters","title":"Configuring parameters","text":"

Just as individual functions may have parameters, EM modules as a whole can publicize a special kind of parameter known as a config which clients in turn can selectively assign inside of em$configure. To illustrate typical usage, let's expand our earlier versions of bob.pkg/Mod1 and dave.pkg2/Mod2 to now expose some new client-visible features in the form of configuration parameters.

bob.pkg/Mod1.em
package bob.pkg\n\nmodule Mod1\n\n    config flag: bool\n        #   ^| Enable some functionality\n    # other public features\n\nprivate:\n\n# etc...\n
dave.pkg/Mod2.em
package dave.pkg\n\nmodule Mod2\n\n    config count: uint8\n        #   ^| Establish some threshold\n    # other public features\n\nprivate:\n\n# etc...\n

As you might glean from the special documentation comments, the flag parameter declared at Mod1 6 and the count parameter declared at Mod2 6 should each render these modules more flexible than before, and hence increase opportunities for clients to (re-)use Mod1 and Mod2 in a wider range of applications. Syntactically similar to const and var declarations within the language, config parameters have a very special semantic property:

An EM config behaves like an assignable var at build-time, but like a read-only const at run-time.

Once we delve into the EM program life-cycle \u2013 from build-time through run-time \u2013 you'll understand the rationale behind this paradox, as well as more fully appreciate the implications of module configuration for resource-constrained embedded applications. For now, suffice it to say that EM composites serve as an ideal site for assigning module config parameters when assembling application programs. Expanding our earlier example:

geof.pkg/CompC.em
package geof.pkg\n\nfrom bob.pkg import Mod1\nfrom dave.pkg import Mod2\n\ncomposite CompC\nend\n\ndef em$configure()\n    Mod2.ModX ?= Mod1         # bind proxy to its delegate\n\n    Mod1.flag ?= true         # assign config parameters\n    Mod2.count ?= 100\nend\n

Just as we bound proxies to delegates, the single-assignment statements at lines 12 and 13 bind parameter values consistent with the types used in corresponding config declarations found at Mod1 6 and Mod2 6. In this light, clients can treat proxies as a special kind of con\u00adfiguration parameter \u2013 assigned module values implementing a declared interface type.

More configuration examples

The em$preconfigure and em$configure functions defined within McuC provide a realistic example of configuration \u2013 starting with a call to BoardInfo.readRecordH, which returns a data-structure of board-specific parameter values read from a YAML source file. The (portable) implementation of readRecordH found within the em.utils/BoardInfo module hints at the range of programmability we can bring to bear during configuration.

"},{"location":"intro/to-2/#instantiating-templates","title":"Instantiating templates","text":"

The EM language provides a general-purpose template mechanism for synthesizing other source-level artifacts \u2013 from fragments of C code to complete\u2009.em files \u2013 during the program build process. The latter scenario, which we'll focus on here, enables suppliers to deliver concrete modules in a more generic embodiment \u2013 one that clients will frequently instantiate within the context of an EM composite.

Starting from the client's perspective, the following composite effectively manufactures a pair of new modules \u2013 locally aliased as Clone1 and Clone2 \u2013 by instantiating a common imported template named thom.pkg/GenT.

geof.pkg/CompC.em
package geof.pkg\n\nfrom thom.pkg import GenT {flag: true, count: 100} as Clone1\nfrom thom.pkg import GenT {flag: false, count: 200} as Clone2\n\nexport Clone1\nexport Clone2\n\ncomposite CompC\nend\n\ndef em$configure()\n    # assign Clone<n> config parameters\n    # bind Clone<n> proxies to delegates\n    # delegate other proxies to Clone<n>\nend\n

Using an expanded form of import directive at lines 3 and 4, this composite works with (synthesized) modules Clone1 and Clone2 no differently than how we employed the bob.pkg/Mod1 or dave.pkg/Mod2 modules defined earlier. Since Clone1 and Clone2 have no prior outside identity, composites will often export these newly-formed modules for use by higher-level clients; composites may further configure and assemble these synthesized modules within the body of their own em$configure function.

The flag and count values bound at lines at lines 3 and 4 above \u2013 which shape the essential characteristics of the synthesized Clone1 and Clone2 modules \u2013 ultimately correspond to public configuration parameters declared within thom.pkg/GenT:

thom.pkg/GenT.em
package thom.pkg\n\ntemplate GenT\n\n    config flag: bool\n        #   ^| Enable some functionality\n    config count: uint8\n        #   ^| Establish some threshold\nend\n\ndef em$generateUnit(pn, un)\n            |-> package `pn`\n            |->\n            |-> module `un`\n            |->\n    if flag\n            |-> const MAX: Uint8 = `count`\n    end\n            # generate remainder of this module\nend\n

Like any other config, the parameters declared after line 5 become assignable variables at program build-time \u2013 in this case, via import directives beginning at line 3 of CompC. The GenT template will then consume these configuration parameters within the body of its em$generateUnit function, which synthesizes lines of source code using special EM output statements prefixed by the |-> symbol.

The flag config declared at 6 impacts the generated output by controlling execution flow within em$generateUnit; by contrast, this function directly interpolates the count config declared at 9 within the generated output. When invoked, em$generateUnit receives pn and un arguments bound to strings like \"geof.pkg\" and \"CompC__Clone1\" \u2013 reflecting the original context in which the geof.pkg/CompC composite imported and instantiated the GenT template back on the earlier line 3.

More template examples

Our McuC composite instantiates a module-per-pin using this GpioT template. Inspecting this template's em$generateUnit function, note how the pin config ultimately shapes the synthesized module through interpolation within the |-> output statements. Though not a rule, synthesized modules will often implement an interface that captures their commonality \u2013 em.hal/GpioI in the example at hand.

To further grasp the special role played by composite and template units, let's proceed onward to Chapter 3 and explore EM's rather unique build flow.

"},{"location":"intro/to-3/","title":"From build-time to run-time","text":"

We turn now to the life-cycle of an EM program \u2013 covering its build-time transformation from a single \"main\" source module into a binary program image comprising multiple modules, as well as its run-time execution phases from hardware reset to system shutdown.

Along the way, you'll understand the role played by EM language intrinsics throughout the program life-cycle \u2013 not only to demarcate execution phases at program run-time (em$run), but also to enable active participation by content suppliers at various stages during program build-time (em$configure and em$generateUnit).

"},{"location":"intro/to-3/#high-level-build-flow","title":"High-level build flow","text":"

The following figure depicts the four principal phases of the EM program life-cycle, as well as maps out the high-level flow of build-time artifacts \u2013 starting with a ModP.em source file and ending with a main.out binary image. The first three of these phases unfold on your host computer, and collectively constitute program build-time; the final phase, needless to say, represents run-time execution of the generated program on target hardware.

Program build flow"},{"location":"intro/to-3/#unit-translation","title":"Unit translation","text":"

Each\u2009.em source file \u2013 whether a module, interface, composite, or template \u2013 represents an independent unit of translation within EM. Starting from a designated top-level unit \u2013 in our case, a module named ModP which would implement the em$run intrinsic \u2013 EM will (recursively) process an N-element hierarchy of other translation units that ModP directly or indirectly imports; since the relation defined by import directives cannot have cycles, translating ModP effectively yields a top-to-bottom (partial) ordering of its dependent units.

Translating concrete modules such as ModP will generally produce three corresponding output files, consumed in subsequent phases of the program build process:

ModP.hpp the public\u2009/\u2009private features of ModP translated into a C++ header file ModP.cpp internal function definitions within ModP translated into equivalent C++ code ModP.js a JavaScript rendition of ModP which will contribute during program configuration

Translating abstract interfaces such as our earlier ModI example will only yield a ModI.js and ModI.hpp output file. Translating composites or templates such as our earlier CompC or GenT examples \u2013 which contribute at build-time but not run-time \u2013 will only yield a CompC.js or GenT.js output file.

Finally, all template instantiations encountered en route through import directives (such as the references to GenT in CompC) will trigger immediate execution of the designated template's em$generateUnit intrinsic \u2013 already translated to JavaScript within the GenT.js output file. Unit translation of the new\u2009.em file produced at this step then proceeds recursively.

Translator efficiency

A top-level module such as ModP could easily have static dependencies on more than 100 other translation units \u2013 especially when imported composites aggressively instantiate templates managing discrete MCU resources like GPIO pins. To accelerate program build-time, the EM translator maintains an internal cache of all generated files and will only (re-)translate a particular\u2009.em file when deemed necessary.

"},{"location":"intro/to-3/#program-configuration","title":"Program configuration","text":"

The configuration phase of the EM program life-cycle \u2013 still upstream from the final compilation of all generated C++ code into a binary image \u2013 actually entails executing a special hosted version of the program rendered in JavaScript. Labeled main.js in the earlier figure, this fabricated program basically amalgamates the\u2009.js files output for each module or composite found within the N-element import hierarchy rooted at ModP itself.

But why JavaScript\u2009???

Seemingly, any hosted language (Java, Python, Ruby) could provide a suitable execution environment for this phase of the EM program life-cycle. Some might argue the case for Python, as this language already plays a similar role with respect to C/C++ code \u2013 especially in emerging platforms such as TinyML, which deploy machine-learning algorithms (developed in a hosted Python environment) onto embedded target hardware.

As it turns out, JavaScript had already claimed the host language role among EM's predecessors \u2013 notably the Eclipse\u2009/\u2009RTSC project which in turn drew upon earlier DSP/BIOS configuration technology. Given the Java-centricity of the Eclipse IDE, Mozilla's Rhino \u2013 a JavaScript engine written in Java and seemlessly integrated with the JVM runtime \u2013 served as an ideal environment at that point in time.

Indeed, an Eclipse plug-in (written in Java) provided almost a decade of IDE support for the EM language; and Rhino therefore remained our JavaScript platform of choice. But now that language support for EM has migrated to the VS Code IDE \u2013 written in TypeScript and running on the Chromium\u2009/\u2009V8 engine \u2013 Node.js provides an even richer JavaScript platform for hosting the configuration phase of the EM program life-cycle.

During its execution, the prog.js program makes three top-to-bottom passes over the N-element import hierarchy rooted in ModP \u2013 invoking JavaScript translations of certain EM intrinsics on a per-unit basis (if defined).

The 1st pass invokes em$preconfigure, which only composites may elect to define; public proxies and config parameters bound at this time using the single-assignment operator [\u2009?=\u2009] become immune to further modification in the next pass.

The 2nd pass invokes em$configure, which modules as well as composites may elect to define; proxies and configs bound here using the [\u2009?=\u2009] operator become immune to further modification by lower-level units yet to execute in this pass.

The 3rd pass invokes two intrinsics on modules whose special em$used config parameter tests true: em$construct, for initializing private module state; and em$generateCode, for synthesizing internal C/C++ code using the EM template mechanism illustrated in GenT.

The [\u2009?=\u2009] operator, as hinted earlier, implements single-assignment semantics \u2013 sealing the first value assigned to a configurable proxy or parameter, while silently ignoring all sub\u00adsequent assignments to the same feature. With a top-to-bottom ordering imposed on the ModP import hierarchy, [\u2009?=\u2009] operations executed by higher-level modules and composites essentially \"override\" (default) binding decisions made by lower-level units. By implementing em$configure, ModP itself can now preempt proxy\u2009/\u2009parameter assignments otherwise made by any modules or composites it may import.

More on pre-configuration

Higher-level modules such as ModP cannot, however, effect the values of configurable features already bound in the first configuration pass via em$preconfigure; the latter intrinsic enables suppliers of EM composites to selectively freeze proxy bindings and parameter values, tempering flexibility in the interest of robustly assembling elements for a fixed application setting. As an example, our McuC composite binds physical pin numbers read from a board-specific YAML file \u2013 reflecting the \"hard reality\" of the underlying hardware.

Referring to the earlier figure, one practical consequence of configuration becomes pruning the original (and often large) N\u2013element import hierarchy into a more tractable M\u2013element subset comprising those modules actually used within the program. In support, each module has an intrinsic em$used parameter \u2013 automatically bound in most cases, but explicitly con\u00adfigurable if necessary \u2013 that ultimately determines membership in the M\u2013element subset.

The top-level module ModP has its em$used parameter automatically set, and is always used within the program.

If module Mod1 is used and Mod1 imports module Mod2 (directly or via a composite), then Mod2 is used as well.

If module Mod1 is used and proxy Mod1.ModX ultimately delegates to module Mod2, then Mod2 is used as well.

Otherwise Mod1 is not used in the program, unless some higher-level module or composite explicitly sets Mod1.em$used.

The final configuration pass gives each used module within the M\u2013element subset an opportunity to focus internally; configuration of all public features of these modules would have already occurred. By defining the em$construct intrinsic, modules may programmatically initialize their private var, config, or even proxy features at this point within the flow.

But since em$construct actually executes on your host computer, module suppliers can now implement complex initialization algorithms at build-time that would otherwise prove far too costly to execute at run-time on resource-constrained MCUs.

With language constructs normally used to implement target-side functions like em$run also available in hosted functions like em$construct, module suppliers can now migrate (expensive) computations from run-time to build-time with little effort. Said another way, EM can serve as its own meta-language \u2013 synthesizing the final form of a concrete module by statically reflecting upon values assigned to its configurable parameters.

Examples of EM meta-programming \u2013 data initialization

The em$construct function of ti.mcu.cc23xx/ConsoleUart0 computes values for private configs ibrd and fbrd, eventually used to initialize hardware registers defining the UART's baud-rate; a less efficient implementation would perform this computation at run-time. Taking this approach to the next level, the em$construct function of em.utils/FftC32 initializes a custom sine-wave table at build-time.

Besides executing (costly) math functions, EM meta-programming can also initialize complex, linked data-structures at build-time \u2013 such as the em$construct function and createH functions of em.utils/FiberMgr, which in turn call build-time functions of em.utils/ListMgr. As a general rule, any static initialization of data at build-time results in more compact programs at run-time.

Complementing em$construct \u2013 oriented towards initializing private state \u2013 some modules will also implement the em$generateCode intrinsic. Using the same form of templatized output statements illustrated earlier in GenT, module suppliers can inject customized C/C++ code fragments into the final program image \u2013 with public config par\u00adameters typically shaping the synthesized output.

Examples of EM meta-programming \u2013 code generation

On the low end of the scale, MCU-specific modules like ti.mcu.cc23xx/Regs use the em$generateCode intrinsic to #include vendor-supplied header files; modules such as Rtc will then reference symbols and macros defined in these headers using a special ^^ escape token.

Moving up a notch, the ti.mcu.cc23xx/IntrVec module programmatically synthesizes the run-time vector table for this MCU using build-time bindings of interrupt handlers \u2013 complete with compiler-specific directives to control placement in memory. In the limit, em$generateCode can leverage the full capabilities of JavaScript executing on your host computer.

"},{"location":"intro/to-3/#program-compilation","title":"Program compilation","text":"

Referring back to the earlier figure, the ultimate outcome of executing the main.js (meta-) program within the overall EM build-flow becomes yet another program \u2013 this time, a single C++ program labeled main.cpp. As suggested earlier, this program only incorporates generated code from the M used modules selected from the original set of N imported units traced back to ModP.em.

Each module Mod participating in this consolidated C++ program respectively contributes (in order) the following portions of code, which collectively represents the bulk of the generated main.cpp file's content:

constant, type, variable, and function declarations from Mod.hpp, generated during the initial translation of Mod.em;

static data initializers reflecting the values assigned to public\u2009/\u2009private features of Mod during the prior configuration phase;

any C/C++ code synthesized by the Mod.em$generateCode intrinsic, executed during the prior configuration phase; and

definitions of declared and intrinsic functions from Mod.cpp, generated during the initial translation of Mod.em.

By merging all generated C/C++ code into a single input file, the underlying compiler for the target MCU can aggressively optimize the program as a whole \u2013 folding away constants, inlining small functions, and eliminating unused code or data. As a case in point, client function calls via abstract proxies to configured delegate modules \u2013 seemingly a double-indirection at run-time \u2013 will usually \"melt-away\" and leave the delegate function body inlined at the client call-site.

Example of whole-program optimization

Returning to FftC32, its exec function uses three config parameters at run-time which em$construct previously initialized by at build-time \u2013 N_WAVE, N_WAVE_LOG2, SINE_WAVE. Knowing the values of these parameters when digesting main.cpp, the compiler has greater latitude in making time\u2009/\u2009space tradeoffs when generating object code for FftC32.exec.

As another example, em.utils/FiberMgr makes many function calls via Common.GlobalInterrupts \u2013 a proxy which conforms to the GlobalInterruptsI interface, and ultimately delegates to a hardware-specific implementation such as ti.cc23xx.mcu/GlobalInterrupts. Knowing this particular proxy\u2009-\u2009delegate binding, the compiler would inline the delegate's (small) functions directly at each Common.GlobalInterrupts call site.

"},{"location":"intro/to-3/#program-execution","title":"Program execution","text":"

This final phase of the EM program life-cycle \u2013 which represents the transition from build-time to run-time \u2013 technically commences when you load the executable main.out image into target memory and reset the MCU. But as you'll see, run-time contributions from the M concrete modules used within this program won't occur until execution reaches main.

The path to main

The path actually taken from loading the main.out file to executing the C/C++ main function can vary widely from one target environment [MCU\u2009+\u2009compiler\u2009+\u2009board] to the next; but fortunately, each distribution of the EM software platform will render this process transparent to the application developer. In practice, each EM distro will leverage much of the tooling infrastructure supporting the underlying MCU \u2013 from flash loaders that operate on standard\u2009.bin or\u2009.hex files, to compiler startup files like crt0.s that manage the transition from MCU reset to C/C++ main as efficiently as possible.

For the M concrete modules bound within the main.out image, program run-time actually begins when target execution reaches the C/C++ main function. Since the un\u00adderlying compiler's own startup file does little more than prepare data memory and initialize critical CPU registers, more comprehensive startup of the target board and the MCU peri\u00adpherals still needs to occur prior to calling the top-level ModP.em$run intrinsic.

The main function initially calls a C++ rendition of Modr.em$reset, where Modr represents the first module to implement this intrinsic found by a top-to-bottom scan of the M modules used in this program; needless to say, this scan occurs at program build-time, not run-time. In practice, some target-specific module included with your EM distribution will assume responsibility for defining the em$reset intrinsic; higher-level application modules generally avoid (re-)defining this intrinsic.

The main function will next call C++ renditions of Modi.em$startup for each Modi found to implement this intrinsic; here too, a top-to-bottom scan of all M program modules occurs at build-time. Unlike em$reset, higher-level application modules down to target-specific driver modules will define this intrinsic in order to perform (run-time) initializations not possible during (build-time) execution of em$construct.

The main function then calls a C++ rendition of Mods.em$startupDone, where Mods represents the first module found to implement this intrinsic through a top-to-bottom scan of all M modules participating in the program. As with em$reset, your EM distribution will usually take responsibility for defining em$startupDone \u2013 which performs any final hardware setup before the application program assumes control.

The main function finally calls a C++ rendition of ModP.em$run, which effectively transfers control to the top-level module of this application. Since embedded applications often execute some form of \"run forever\" loop \u2013 whether explicitly coded within the program or else implicitly managed by some run-time task scheduler \u2013 in practice the em$run intrinsic will not return control back to the calling main function.

Examples of em$startup

Many modules that manage MCU hardware peripherals will define em$startup \u2013 such as Idle and Rtc found in the ti.mcu.cc23xx package; clearly, this sort of hardware setup must occur at run-time. By extension, portable modules like em.utils/SoftUart which leverage proxies to interact with underlying hardware may likewise rely upon em$startup to perform some run-time initialization \u2013 in this case, initializing a GpioI proxy named TxPin.

Should the top-level ModP.em$run intrinsic actually return to main, control then transfers to a distinguished __halt function \u2013 also generated prior to program compilation \u2013 which supervises an orderly shutdown of the target application. If necessary, any program module can explicitly initiate the shutdown sequence at run-time through a special halt statement that can appear inside EM function definitions.

The __halt function will first call C++ renditions of Modi.em$shutdown for each Modi found to implement this intrinsic; higher-level applications down to target-specific drivers modules will define this intrinsic in order to perform run-time finalization prior to halting the processor.

The __halt function then calls a C++ rendition of Modh.em$halt, where Modh represents the first module to implement this intrinsic found by a top-to-bottom scan; each EM distro offers a \"default\" version of em$halt, though higher-level modules may (re-)define this intrinsic in some cases.

Should the implementation of em$halt happen to return to __halt, program control would fall-through to a special block of code that simply spins within an infinite loop.

In cases where something goes \"seriously wrong\" within the system and execution should terminate more abruptly, EM also supports a special fail statement that can appear in any function definition. When executed at run-time, fail immediately transfers control to an implementation of the em$fail intrinsic \u2013 often found within the same module implementing em$halt; should em$fail return, the program likewise enters an infinite loop.

More on startup/shutdown intrinsics

By design, each EM distro relies upon the portable em.utils/BoardController module which centralizes definitions of the singleton intrinsics em$reset, em$startupDone, em$halt, and em$fail; configuration of the BoardController module and its dependents typically occurs within the distro's BoardC composite. In those (rare) circumstances where some higher-level module needs to \"override\" one of these special functions, the higher-level intrinsic definition would likely call the corresponding \"base\" function within BoardController.

While we've already directed you to browse selected\u2009.em source files drawn from EM platform runtime, Chapter 4 concludes our technical overview with more comprehensive picture of this environment.

"},{"location":"intro/to-4/","title":"Software platform content","text":"

While software design and development focuses on individual\u2009.em files \u2013 modules, interfaces, composites, templates \u2013 a more coarse-grained construct known as a bundle serves as the unit of software delivery within the EM platform. Like the packages they ultimately contain, each EM bundle bears a globally-unique qualified name suggestive of its publisher and purpose \u2013 though individual\u2009.em files will only reference packages by name, and never the containing bundle itself.

Representing \"components-in-the-large\", an EM bundle will not only publicize the elements it provides but will also identify other bundles it requires for successful deployment; de\u00adpendent bundles may in turn require other bundles \u2013 reminiscent of the hierarchic import relation between individual\u2009.em files. Bundles can also serve as a unit of software versioning within the platform, with dependencies optionally constrained to particular labeled releases.

In the sections that follow, we'll respectively explore these three EM bundles:

em.core

hardware-independent packages fundamental to EM

ti.cc23xx

hardware-dependent packages comprising a typical EM distro

em.docs

hardware-independent example programs which use the prior bundles

"},{"location":"intro/to-4/#portable-content","title":"Portable content","text":"

As its name suggests, the em.core bundle incorporates rudimentary and essential content present in all distributions of the EM software platform \u2013 some of which we've already visited earlier in this document. Through aggressive use of the proxy\u2009\u2013\u2009interface pattern, a critical subset of the em.core bundle \u2013 specifically, its em.mcu and em.utils packages \u2013 in fact remain 100% portable across all target environments.

em.hal

This package contains abstract interfaces reflecting the functionality of low-level hardware elements found within embedded MCUs \u2013 ConsoleUartI, LedI, WakeupTimerI, and many others; this package contains also contains \"empty\" implementations of these interfaces (ConsoleUartN, LedN, etc), often used as default proxy bindings. As such, this package serves as a critical hardware abstraction layer (HAL) \u2013 prescribing a fundamental architectural boundary that insulates portable (hardware-independent) content from target-specific (hardware-dependent) content.

em.utils

This package comprises a somewhat eclectic (and ever-expanding) collection of run-time application services \u2013 ranging from elementary modules like ListMgr and FiberMgr up to more sophisticated templates like ButtonT and LedT. While mostly supporting program run-time, special host modules like BoardInfo and BoardMeta offer (portable) services used by EM distros at program build-time.

em.mcu

Unlike em.utils, this package generally limits its contents to what we'll term as global proxies \u2013 a set of well-known modules that implement certain em.hal interfaces by effectively forwarding function calls to a conformant delegate; ConsoleUart and Poller illustrate this pattern. This package also contains the widely-used Common module, which conveniently aggregates additional global proxies into a single unit.

em.lang

Invisible to most clients, this package helps bootstrap the implementation of the EM language itself through several distinguished interfaces declaring intrinsic configs and functions:\u00a0 ModuleI, that all modules or interfaces will inherit; CompositeI, that all composites will inherit; and TemplateI, that all templates will inherit. This package also contains the Console module and its ConsoleProviderI interface \u2013 supporting printf statements innate to the language. Finally, this package houses common C/C++ and JavaScript code fragments interpolated during the EM program build-flow.

Using EM will take a more detailed look at the source code of specific\u2009.em files found in the first three of these packages.

"},{"location":"intro/to-4/#target-specific-content","title":"Target-specific content","text":"

Complementing em.core and its portable packages, the ti.cc23xx bundle delivers support for the Texas Instruments CC2340R5 wireless MCU. While specifically targeting a particular MCU family, the organization of the packages found within the ti.cc23xx bundle follows a pattern generally seen within any EM distro.

ti.distro.cc23xx

This package (and in fact the entire ti.cc23xx distro bundle) revolves around a single composite conventionally named BoardC \u2013 responsible for configuring parameters as well as binding proxies exposed by elements of em.core. This package also contains two other conventionally named units found in any EM distro:\u00a0 the McuC composite, which (in this case) focuses on the ti.mcu.cc23xx package; and the special host BoardMeta module, which effectively defines the schema of the board-specific YAML file mentioned earlier in the context of configuration and pre-configuration.

ti.mcu.cc23xx

Many of the modules in this package provide MCU-specific implementations of abstract interfaces found in em.hal \u2013 ConsoleUart0, Idle, OneShotGpt3, and others. Likewise, this package features templates such as GpioT and InterruptT whose em$generateUnit intrinsics synthesize MCU-specific implementations of other HAL interfaces at program build-time. Finally, this package contains even lower-level auxiliary modules (eg, Regs and Rtc) whose clients typically remain within the distro itself.

ti.build.cc23xx

This package contains host modules that control the compiling\u2009/\u2009linking of target EM programs using a particular C/C++ toolchain. The modules typically pass target-specific information such as memory maps or register declarations to generic modules found in a special em.build bundle, which we'll discuss in a later document.

Porting EM will dive into virtually all of the\u2009.em source files found in these three packages, as well as explore the em.build bundle mentioned above.

"},{"location":"intro/to-4/#elementary-programs","title":"Elementary programs","text":"

The em.examples.basic package within the em.docs bundle contains a curated set of programs described at length in Using EM. A live sequence of \"guided tours\" that view\u2009/\u2009build\u2009/\u2009load these programs revolve around the following modules:

HelloP hello world Tour 00 BlinkerP basic blinker Tour 01 BlinkerDbgP real-time debug Tour 02 FiberP threading with fibers Tour 03 Button1P button handlers Tour 04 Button2P button fibers Tour 05 Button3P button objects Tour 06 OneShot1P timer handlers Tour 07 OneShot2P timer fibers Tour 08 PollerP timer service Tour 09 Alarm1P wakeup alarms Tour 10 Alarm2P aligned wakeups Tour 11 TickerP cyclic tickers Tour 12

To ensure their portability, none of these programs explicitly reference the \"current\" EM distro package [\u2009ti.distro.cc23xx\u2009] by name; rather, these programs use a special language intrinsic [\u2009em$distro\u2009] as a logical name which you will bind to a particular distro package.

"},{"location":"intro/to-4/#learning-more-em","title":"Learning more EM","text":"

If you want to learn more about EM \u2013 but continue to fly at 10,000' for now \u2013 we strongly recommend reading through Using EM to get a sense for the platform's tooling and runtime from a ground-level perspective; a quick pass through the other documents at this site should prove informative as well.

When you want to hit the ground running and start coding, however, you'll definitely need to first work through Installing EM before proceeding onward to Using EM. Both of these documents also accomodate a special **\u2009FAST-TRACK\u2009** option, which enables you to rapidly experience the EM development environment as well as learn more about em.core.

The Porting EM document continues on the ground, exploring the ti.cc23xx bundle in greater detail as well as outlining the steps required to create new EM distros that support other MCUs. Over time, we expect Porting EM will draw upon a broader set of distro bundles to further reinforce the EM platform's architecture for encapsulating target-specific content.

Finally, Advancing EM contains an ever-growing collection of standalone articles addressing a wide-range of topics about EM. While many of these articles expect that you've already spent time on the ground coding, others presume just a 10,000' understanding of Using EM.

Case in point:\u00a0\u00a0 we strongly recommend the Energy Consumption article, which presents further evidence supporting a hypothesis about EM put forth earlier.

Happy coding\u2009!!! \u2002

"},{"location":"porting/","title":"Managing hardware diversity in EM","text":"

Under Construction \u2014 estimated completion in 1Q24 \u2009

"},{"location":"using/","title":"Writing portable applications in EM","text":"

If you've made it this far, let's hit the ground running and starting coding\u2009!!!\u00a0\u00a0 This document will first familiarize you with the mechanics of viewing, editing, building, and loading EM programs and their constituent units using the EM Builder extension for VS Code. If you haven't worked with VS Code, the web abounds with tutorials\u2009+\u2009references for this ever-popular IDE.

The main portion of this document comprises a series of tours that visit some basic programming examples \u2013 curated to introduce elements of the EM runtime environment, as well as to reinforce common coding idioms of the EM language(1). To support these documentation resources, EM Builder includes a \"tour guide\" utility that walks you through this material in a somewhat specialized fashion.

  1. consult Language Syntax as a reference

If you've chosen to bypass Installing EM for now, a quick read through this document would still have benefit \u2013 even if you can't execute real software on real hardware.

If you have elected to install EM Builder \u2013 but haven't received your hardware or else prefer the **\u2009FAST-TRACK\u2009** option \u2013 you can still build the programs featured in any of the tours. Until your board arrives and you can actually load these programs, studying the logic capture(s) associated with each example should help bridge the gap.

These captures in fact reveal subtle timing details otherwise invisible to the naked eye.

We've generated all of the captures presented later in this document using a Saleae Logic Analyzer \u2013 in our opinion, the single most valuable tool for \"debugging\" real-time embedded software running on target MCU hardware. At a minimum, you should download the (free) Saleae Logic 2 software and explore these logic capture files off-line.

If you can't see the problem, you can't fix it\u2009!!!

Software debuggers have traditionally focused upon a rich presentation of program state (variables, call stacks, peripherals) \u2013 but only after program execution halts (say) upon reaching a breakpoint. Given the general nature of embedded software, however, a dynamic presentation depicting state-changes over time proves far more helpful for troubleshooting real-world problems.

While modern debuggers attempt to address this need, they often do so by introducing significant amounts of hardware\u2009/\u2009software overhead \u2013 limiting their utility to software development rather than system deployment. These approaches may also preclude the underlying MCU from entering its \"deep-sleep\" mode \u2013 a serious limitation that can obscure real-world, real-time wakeup issues.

But armed with no more than a basic logic analyzer, the EM language provides intrinsic \"real-time debug\" capabilities that enable us to dynamically capture program state without incurring excessive program overhead. In the spirit of \"test what you fly, fly what you test\", these capabilities prove equally valuable during development in the factory and well as during deployment in the field.

At the same time, we also want you to experience the joy of blinking LEDs\u2009!!!\u00a0\u00a0 With that, let's first skill-up on EM Builder and then tour the EM runtime.\u00a0

When finished, circle back to Learning more EM and plan your next adventure.

"},{"location":"using/using-01/","title":"Working with EM Builder","text":"

To flatten your learning curve, we'll work exclusively within the VS Code environment \u2013 using the EM Builder extension which you've already installed. Besides introducing some core capabilities of the extension, the material that follows will also verify the integrity of your installation.

But what about the command line\u2009???

Strictly speaking, we don't need VS Code to develop EM software:\u00a0 you can create folders\u2009/\u2009files as you always have; you can create\u2009/\u2009modify\u2009.em sources in your favorite text editor; and you can build\u2009/\u2009load executable EM programs using the em-cli command-line interface.\u00a0 The implementation of EM Builder and em-cli, in fact, share quite a bit of common code \u2013 with the former often invoking the latter. The Command-line inteface reference material describes the em-cli tool in greater detail.

"},{"location":"using/using-01/#workspace-organization","title":"Workspace organization","text":"

The following animation illustrates the overall organization of your workspace folder when using the EM Builder extension, and picks up from where we left off when Installing EM.\u2009 We also encourage you to launch VS Code by entering code workspace from your PC's shell, and to simultaneously explore this environment at your own pace.

VS Code Screen Layout

VS Code Screen Layout"},{"location":"using/using-01/#building-em-programs","title":"Building EM programs","text":"

The following animation illustrates how to build HelloP.em using the EM - Build command, selected from this file's (right-click) context menu. Since this program contains a main em$run function, the EM translator produces a corresponding executable image; see the OUTPUT panel for details.

EM - Build

EM - Build"},{"location":"using/using-01/#loading-em-programs","title":"Loading EM programs","text":"

The following animation illustrates how to load the previously-built HelloP.em program using the EM - Load command \u2013 also selected from a context menu. Should loading the executable image fail for some reason (eg, you don't even have a target board), an error message would appear in the OUTPUT panel.

EM - Load

EM - Load"},{"location":"using/using-01/#monitoring-em-programs","title":"Monitoring EM programs","text":"

The following animation illustrates how to monitor any printf output from the currently loaded program image, by invoking EM - Open Console within the VS Code Command Palette\u2009. Once the special TERMINAL panel has launched, press the RESET button on your target board and enjoy the show\u2009!!!

EM - Open Console

EM - Open Console"},{"location":"using/using-01/#creating-em-artifacts","title":"Creating EM artifacts","text":"

The following animation illustrates how to create a workspace bundle using the EM - New Bundle command, likewise found in the Command Palette\u2009. In this case, we've named the new artifact as my.bundle; the remainder of this document will often refer to this folder as your \"personal\" bundle.

EM - New Bundle

EM - New Bundle

The following animation illustrates how to populate your personal bundle folder with other EM artifacts \u2013 packages, modules, interfaces, etc \u2013 created using commands selected from the (right-click) context menu of the containing folder. In this case, we'll invoke EM - New Package followed by EM - New Test Program to create a unit named my.pkg/Test.

EM - New Package | EM - New Test Program

EM - New Package | EM - New Test Program"},{"location":"using/using-01/#cloning-em-cargo","title":"Cloning EM cargo","text":"

The following animation illustrates the EM - Clone command, used to populate personal bundles with runtime content delivered by the EM Builder extension and housed under the special\u2009.em-cargo folder. In this case, we'll first locate em.examples.basic/FiberP and em.utils/FiberMgr under\u2009.em-cargo and then clone these units into my.bundle.

EM - Clone

EM - Clone"},{"location":"using/using-01/#exploring-em-sources","title":"Exploring EM sources","text":"

The following animation illustrates a few of the VS Code language features supported by the EM Builder extension. In this case, we'll hover over EM identifiers and jump between\u2009.em source files; we'll also use the OUTLINE panel to navigate amongst the declarations\u2009/\u2009definitions contained within individual EM units.

VS Code Language Support

VS Code Language Support

While these capabilities prove helpful when exploring EM source code, the EM Builder extension also provides support for \"smart completion\" (IntelliSense) \u2013 even more helpful when editing your code.\u00a0 At the same time, VS Code language support remains a never-ending journey of incremental improvement.

Help wanted \u2013 VS Code programmer

"},{"location":"using/using-02/","title":"Programming with EM","text":"

Turning now to the EM runtime, a series of curated \"guided tours\" will incrementally introduce components of the em.core bundle \u2013 many of which you may have browsed in your reading of Introducing EM.\u2009 By convention, each tour revolves around a specific EM program found in the em.examples.basic package \u2013 with each of these small programming examples motivating us to visit key elements of the EM runtime.

In the material that follows, we'll reference a number of logical MCU \"pins\" configured by the current EM distro and generally accessible through headers on your target board:

\u2003\u2003\u2003\u2003\u2003appBut application button pin \u2003\u2003\u2003\u2003\u2003appLed application LED pin (usually green) \u2003\u2003\u2003\u2003\u2003appOut application console TX pin \u2003\u2003\u2003\u2003\u2003sysDbgA system debug pin A \u2003\u2003\u2003\u2003\u2003sysDbgB system debug pin B \u2003\u2003\u2003\u2003\u2003sysDbgC system debug pin C \u2003\u2003\u2003\u2003\u2003sysDbgD system debug pin D \u2003\u2003\u2003\u2003\u2003sysLed system LED pin (usually red)

A special YAML file named em-boards found the em$distro package folder binds these logical pin names to physical pin numbers of your target board. Porting EM will have more to say about em-boards, as well as explain the special setup-*.properties files located in the root of your distro bundle.

"},{"location":"using/using-02/#tour-00-guided-tours","title":"Tour 00 \u2013 guided tours","text":"

The following animation illustrates the EM - Start Tour command, which you'll use to view each of the tours described in the remainder of this document. You'll find these tours in appropriately named\u2009.emtour files, located inside the\u2009.tours/101_Using_EM folder delivered with the em.docs bundle.

EM - Start Tour

EM - Start Tour

With that, go ahead and actually take tour 00_HelloP.emtour within your VS Code environment. Before proceeding to take Tour 01\u2009\u2013\u2009Tour 12\u2009, however, you should feel comfortable with the UI presented in Tour 00\u2009; and do retake any of these tours whenever necessary.

"},{"location":"using/using-02/#tour-01-basic-blinker","title":"Tour 01 \u2013 basic blinker","text":"

This tour centers around the BlinkerP program, which toggles the appLed pin on your target board \u2013 typically connected to a green LED. This tour also visits the BusyWaitI and LedI interfaces, as well as presents the Common module and its constituent proxies.

Tour 01 \u2013 Logic Capture

\u00a0 The EM runtime quickly blinks your board's sysLed at startup.

\u00a0 The BlinkerP program toggles appLed every ~0.5\u2009s.

\u00a0 The EM runtime turns on sysLed upon normal program termination.

\u00a0 The next capture zooms into the appOut signal.

Tour 01 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

\u00a0 The EM runtime outputs this sequence of (non-printable) bytes at startup, after blinking sysLed.

\u00a0 The EM runtime output this single byte upon normal program termination, before turning on sysLed.

"},{"location":"using/using-02/#tour-02-real-time-debug","title":"Tour 02 \u2013 real-time debug","text":"

This tour focuses upon the BlinkerDbgP program, which also toggles the appLed pin on your target board. This tour highlights a number of capabilities within EM for visualizing and troubleshooting program execution in real-time.

Tour 02 \u2013 Logic Capture

\u00a0 The busy-wait bracketed by %%[d+] and %%[d-] measures ~498 ms.

\u00a0 Executing a fail statement causes sysLed to blink rapidly.

Tour 02 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

\u00a0 The %%[>cnt] statement outputs the (non-printable) 0x82 control byte followed by 2 bytes of payload.

\u00a0 The %%[>bits11] statement outputs the (non-printable) 0x81 control byte followed by 1 byte of payload.

\u00a0 The %%[c:bits11] statement causes the dbgC pin to rapidly toggle 2 times \u2013 since (bits11\u2009==\u20090x1)

\u00a0 The ASCII character output of printf begins here \u2013 0x63('c'), 0x6E('n'), and so on.

"},{"location":"using/using-02/#tour-03-threading-with-fibers","title":"Tour 03 \u2013 threading with fibers","text":"

This tour centers around the FiberP program, which introduces a very lightweight threading construct termed a fiber. This tour also visits the EM runtime's (portable) implementation of fibers found in the FiberMgr module.

Tour 03 \u2013 Logic Capture

\u00a0 The %%[d] statement in blinkFB marks each point in time where the blinkF fiber begins execution.

\u00a0 The ~200 ms between blinkF cycles includes appLed on\u2009/\u2009off time plus FiberMgr dispatch overhead.

"},{"location":"using/using-02/#tour-04-button-handlers","title":"Tour 04 \u2013 button handlers","text":"

This tour centers around the Button1P program, which handles incoming events generated when pressing appBut on your board. This tour also visits the GpioEdgeDetectMinI interface that in turn extends the GpioI abstraction.

Tour 04 \u2013 Logic Capture

\u00a0 The EM runtime uses dbgB to mirror the MCU's execution mode [\u2009L \u2013 actively running, H \u2013 awaiting wakeup\u2009]

\u00a0 Pressing your board's button drives the appBut pin low; appLed then blinks shortly thereafter.

\u00a0 A 125\u2009ns \"glitch\" on the appBut signal fired another event at this time \u2013 causing an extra appLed blink.

Tour 04 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

\u00a0 You've pressed appBut at this time, which then begins awakening the MCU from its low-power sleep.

\u00a0 Requiring 34.2\u2009\u03bcs to fully power the MCU, dbgB's falling edge marks when Button1P starts actively running.

\u00a0 Control enters handler within 3.4\u2009\u03bcs, whose initial %%[c] statement toggles dbgC for 1.2\u2009\u03bcs

\u00a0 After some housekeeping, Button1P finally turns-on appLed \u2013 5.9\u2009\u03bcs since actively running.

"},{"location":"using/using-02/#tour-05-button-fibers","title":"Tour 05 \u2013 button fibers","text":"

This tour centers around the Button2P program, which uses a Fiber object to better handle incoming events. This tour also analyzes the performance impact of this approach compared with the earlier Button1P program.

Tour 05 \u2013 Logic Capture

dbgB shows that Button2P awoke exactly twice in response to pressing appBut \u2013 no glitches this time\u2009!!!

Tour 05 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

Button2P resumes execution in 35.2\u2009\u03bcs; keep in mind that low-power MCU wakeup times can vary slightly.

\u00a0 Control then enters handler 3.4\u2009\u03bcs later \u2013 consistent with the Button1P capture seen above.

\u00a0 Unlike Button1P, the Button2P handler readies the blinkF fiber which then gains control 5.3\u2009\u03bcs later.

\u00a0 Finally, the blinkFB function turns-on appLed \u2013 with only ~5\u2009\u03bcs of FiberMgr scheduling overhead.

"},{"location":"using/using-02/#tour-06-button-objects","title":"Tour 06 \u2013 button objects","text":"

This tour centers around the Button3P program, which debounces button input signals in a portable fashion. This tour also visits the ButtonI interface along with a module implementing this interface \u2013 the latter generated by the ButtonT template at build-time.

Tour 06 \u2013 Logic Capture

\u00a0 Once triggered by pressing your board's button, the EM runtime polls the state of appBut every 100\u2009ms.

\u00a0 If pressed for \u2265\u2009100\u2009ms but \u2264\u20094\u2009s, Button3P will blink appLed within 100\u2009ms of releasing the button.

\u00a0 Hitting the 4\u2009s mark, Button3P immediately blinks sysLed\u2013 regardless of how long appBut remains low.

Tour 06 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

\u00a0 After polling appBut for 4\u2009s, the EM runtime invokes Button3P.onPressedCB which leaves a %%[c] mark.

\u00a0 Discovering that appBut remains pressed [\u2009=\u2009L\u2009], onPressedCB then blinks sysLed for 40\u2009ms.

\u00a0 Only 7.5\u2009\u03bcs elapses from dbgB falling to sysLed rising, which includes scheduling fibers plus 1.2\u2009\u03bcs for %%[c].

"},{"location":"using/using-02/#tour-07-timer-handlers","title":"Tour 07 \u2013 timer handlers","text":"

This tour centers around the OneShot1P program, which handles timer events that awaken the MCU. This tour also visits the OneShotMilliI interface, which abstracts the functionality of a short-term timer with millisecond resolution.

Tour 07 \u2013 Logic Capture

\u00a0 The dbgB signal shows that OneShot1P awakens from low-power sleep every 500\u2009ms.

\u00a0 Once awake, OneShot1P toggles dbgC and dbgD before blinking appLed \u2013 like our earlier Button1P capture

\u00a0 The 7.5\u2009\u03bcs \"wakeup-to-blink\" latency seen here includes the overhead of servicing an on-chip MCU timer.

"},{"location":"using/using-02/#tour-08-timer-fibers","title":"Tour 08 \u2013 timer fibers","text":"

This tour centers around the OneShot2P program, which now uses Fiber objects to enhance robustness when handing timer events. This tour also invites performance comparision with the earlier OneShot1P program.

Tour 08 \u2013 Logic Capture

\u00a0 Fiber scheduling adds the extra 1.1\u2009\u03bcs of latency seen here, compared with our previous OneShot1P capture.

"},{"location":"using/using-02/#tour-09-timer-service","title":"Tour 09 \u2013 timer service","text":"

This tour centers around the PollerP program, which introduces a portable function for pausing execution at run-time. This tour also visits the top-level Poller module as well as the lower-level PollerAux module \u2013 both implementing the PollerI interface.

Tour 09 \u2013 Logic Capture

\u00a0 Without %%[c] and %%[d] marks, PollerP further reduces latency compared to OneShot1P and OneShot2P.

Tour 09 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

\u00a0 The [L] dbgB signal indicates that the PollerP program has awoken.

PollerP then calls AppLed.wink within 2.5\u2009\u03bcs, which then asserts the appLed pin

\u00a0 Calling AppLed.wink 2.5\u2009\u03bcs later asserts the appLed pin and then internally invokes Poller.pause.

Poller.pause proceeds to suspend program execution for 5\u2009ms \u2013 the duration of the wink.

\u00a0 The EM runtime toggles dbgB once before awaiting the next wakeup [H]\u2009; we'll explain more in a later tour.

\u00a0 An MCU timer event will eventually awaken the program 5\u2009ms later, with dbgB now signalling [L]\u2009.

\u00a0 Control unwinds from Poller.pause back to AppLed.wink, which will now lower the appLed pin.

em$run finally regains control, and then suspends execution for 500\u2009ms by calling Poller.pause directly.

"},{"location":"using/using-02/#tour-10-wakeup-alarms","title":"Tour 10 \u2013 wakeup alarms","text":"

This tour centers around the Alarm1P program, which uses Alarm objects to schedule longer-term wakeups with (sub-)second resolution. This tour also visits the AlarmMgr module, which internally uses a proxy implementing the WakeupTimerI interface.

Tour 10 \u2013 Logic Capture

\u00a0 The Alarm1P program alternately awakens from a low-power deep-sleep of 2\u2009s or else 750\u2009ms in duration.

\u00a0 The program's blinkFB function winks appLed for 100\u2009ms, with the MCU idling in the interim.

\u00a0 Once AppLed.wink returns, Alarm1P calls alarm.wakeup to re-enter an extended period of deep-sleep.

Tour 10 \u2013 Logic Capture\u2002[\u2009zoom\u2009]

\u00a0 The single dbgB mark indicates the MCU has entered its \"lite-sleep\" mode, after Alarm1P calls AppLed.wink

\u00a0 The MCU awakens from its lite-sleep within 100\u2009ms, returning to wink which then turns-off appLed.

\u00a0 The double dbgB mark indicates the MCU has entered its \"deep-sleep\" mode, after calling alarm.wakeup

"},{"location":"using/using-02/#tour-11-aligned-wakeups","title":"Tour 11 \u2013 aligned wakeups","text":"

This tour centers around the Alarm2P program, which now aligns Alarm wakeups with a given time-window. This tour also re-visits the AlarmMgr implementation, seeing how it schedules the next wakeup event as well as the role played by the EpochTime module.

Tour 11 \u2013 Logic Capture

\u00a0 Note how the wakeups from deep-sleep align with a series of 1.5\u2009s windows along the time-line.

\u00a0 Due to startup overhead, the first alarm.wakeup call deep-sleeps the MCU for only 1.250\u2009s to stay aligned.

\u00a0 After a 5\u2009ms appLed wink, this alarm.wakeup call deep-sleeps the MCU for 1.495\u2009s to stay aligned.

\u00a0 But after a 100\u2009ms wink, this alarm.wakeup call deep-sleeps the MCU for just 1.400\u2009s to stay aligned.

"},{"location":"using/using-02/#tour-12-cyclic-tickers","title":"Tour 12 \u2013 cyclic tickers","text":"

This tour centers around the TickerP program, which takes duty-cycled functions to a higher level. This tour also visits the TickerMgr module, whose implementation of Ticker objects emulates as well as builds upon the AlarmMgr and FiberMgr studied earlier.

Tour 12 \u2013 Logic Capture

\u00a0 The appTicker.start call by the TickerP program initiates a train of 100\u2009ms appLed winks, spaced 1\u2009s apart.

\u00a0 The sysTicker.start call by TickerP then initiates a train of 100\u2009ms sydLed winks, but spaced 1.5\u2009s apart.

\u00a0 When appTicker and sysTicker wakeups coincide, their callbacks run on a first-come, first-served basis.

"}]} \ No newline at end of file diff --git a/site/sitemap.xml.gz b/site/sitemap.xml.gz index 7b82a83..de44b28 100644 Binary files a/site/sitemap.xml.gz and b/site/sitemap.xml.gz differ diff --git a/site/using/index.html b/site/using/index.html index 2aaf746..0fe7d2d 100644 --- a/site/using/index.html +++ b/site/using/index.html @@ -866,7 +866,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/using/using-01/index.html b/site/using/using-01/index.html index 37c76f1..41849f3 100644 --- a/site/using/using-01/index.html +++ b/site/using/using-01/index.html @@ -969,7 +969,7 @@ - EM&•Mark Results + EM•Mark Results diff --git a/site/using/using-02/index.html b/site/using/using-02/index.html index 86ccc58..a488b21 100644 --- a/site/using/using-02/index.html +++ b/site/using/using-02/index.html @@ -1023,7 +1023,7 @@ - EM&•Mark Results + EM•Mark Results