1 /* 2 * Copyright (c) 2021 Nordic Semiconductor ASA 3 * Copyright (c) 2020 STMicroelectronics 4 * 5 * SPDX-License-Identifier: Apache-2.0 6 */ 7 8 /** 9 * @file 10 * @brief DWT utility functions for Cortex-M CPUs 11 * 12 */ 13 14 #ifndef ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_DWT_H_ 15 #define ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_DWT_H_ 16 17 #ifdef _ASMLANGUAGE 18 19 /* nothing */ 20 21 #else 22 23 #include <cmsis_core.h> 24 #include <zephyr/sys/__assert.h> 25 26 #ifdef __cplusplus 27 extern "C" { 28 #endif 29 30 #if defined(CONFIG_CORTEX_M_DWT) 31 32 /* Define DWT LSR masks which are currently not defined by the CMSIS V5.1.2. 33 * (LSR register is defined but not its bitfields). 34 * Reuse ITM LSR mask as it is the same offset than DWT LSR one. 35 * TODO: update these to use only CMSIS_6 when all of zephyr and modules have 36 * update to CMSIS_6. 37 */ 38 #if !defined DWT_LSR_Present_Msk 39 #define DWT_LSR_Present_Msk ITM_LSR_PRESENT_Msk 40 #endif 41 42 #if !defined DWT_LSR_Access_Msk 43 #define DWT_LSR_Access_Msk ITM_LSR_ACCESS_Msk 44 #endif 45 dwt_access(bool ena)46static inline void dwt_access(bool ena) 47 { 48 #if defined(CONFIG_CPU_CORTEX_M7) 49 /* 50 * In case of Cortex M7, we need to check the optional presence of 51 * Lock Access Register (LAR) which is indicated in Lock Status 52 * Register (LSR). When present, a special access token must be written 53 * to unlock DWT registers. 54 */ 55 uint32_t lsr = DWT->LSR; 56 57 if ((lsr & DWT_LSR_Present_Msk) != 0) { 58 if (ena) { 59 if ((lsr & DWT_LSR_Access_Msk) != 0) { 60 /* Access is locked. unlock it */ 61 DWT->LAR = 0xC5ACCE55; 62 } 63 } else { 64 if ((lsr & DWT_LSR_Access_Msk) == 0) { 65 /* Access is unlocked. Lock it */ 66 DWT->LAR = 0; 67 } 68 } 69 } 70 #else /* CONFIG_CPU_CORTEX_M7 */ 71 ARG_UNUSED(ena); 72 #endif /* CONFIG_CPU_CORTEX_M7 */ 73 } 74 75 /** 76 * @brief Enable DWT 77 * 78 * This routine enables the DWT unit. 79 * 80 * @return 0 81 */ z_arm_dwt_init(void)82static inline int z_arm_dwt_init(void) 83 { 84 /* Enable tracing */ 85 CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; 86 87 /* Unlock DWT access if any */ 88 dwt_access(true); 89 90 return 0; 91 } 92 93 /** 94 * @brief Initialize and Enable the DWT cycle counter 95 * 96 * This routine enables the cycle counter and initializes its value to zero. 97 * 98 * @return 0 99 */ z_arm_dwt_init_cycle_counter(void)100static inline int z_arm_dwt_init_cycle_counter(void) 101 { 102 /* Clear and enable the cycle counter */ 103 DWT->CYCCNT = 0; 104 DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; 105 106 /* Assert that the cycle counter is indeed implemented. 107 * The field is called NOCYCCNT. So 1 means there is no cycle counter. 108 */ 109 __ASSERT((DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk) == 0, "DWT implements no cycle counter. " 110 "Cannot be used for cycle counting\n"); 111 112 return 0; 113 } 114 115 /** 116 * @brief Return the current value of the cycle counter 117 * 118 * This routine returns the current value of the DWT Cycle Counter (DWT.CYCCNT) 119 * 120 * @return the cycle counter value 121 */ z_arm_dwt_get_cycles(void)122static inline uint32_t z_arm_dwt_get_cycles(void) 123 { 124 return DWT->CYCCNT; 125 } 126 127 /** 128 * @brief Reset and start the DWT cycle counter 129 * 130 * This routine starts the cycle counter and resets its value to zero. 131 */ z_arm_dwt_cycle_count_start(void)132static inline void z_arm_dwt_cycle_count_start(void) 133 { 134 DWT->CYCCNT = 0; 135 DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; 136 } 137 138 /** 139 * @brief Enable the debug monitor handler 140 * 141 * This routine enables the DebugMonitor handler to service 142 * data watchpoint events coming from DWT. The routine sets 143 * the DebugMonitor exception priority to highest possible. 144 */ z_arm_dwt_enable_debug_monitor(void)145static inline void z_arm_dwt_enable_debug_monitor(void) 146 { 147 /* 148 * In case the CPU is left in Debug mode, the behavior will be 149 * unpredictable if the DebugMonitor exception is triggered. We 150 * assert that the CPU is in normal mode. 151 */ 152 __ASSERT((CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) == 0, 153 "Cannot enable DBM when CPU is in Debug mode\n"); 154 155 #if defined(CONFIG_ARMV8_M_SE) && !defined(CONFIG_ARM_NONSECURE_FIRMWARE) 156 /* 157 * By design, the DebugMonitor exception is only employed 158 * for null-pointer dereferencing detection, and enabling 159 * that feature is not supported in Non-Secure builds. So 160 * when enabling the DebugMonitor exception, assert that 161 * it is not targeting the Non Secure domain. 162 */ 163 __ASSERT((CoreDebug->DEMCR & DCB_DEMCR_SDME_Msk) != 0, "DebugMonitor targets Non-Secure\n"); 164 #endif 165 166 /* The DebugMonitor handler priority is set already 167 * to the highest value (_EXC_FAULT_PRIO) during 168 * system initialization. 169 */ 170 171 /* Enable debug monitor exception triggered on debug events */ 172 CoreDebug->DEMCR |= CoreDebug_DEMCR_MON_EN_Msk; 173 } 174 175 #endif /* CONFIG_CORTEX_M_DWT */ 176 177 #ifdef __cplusplus 178 } 179 #endif 180 181 #endif /* _ASMLANGUAGE */ 182 183 #endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_DWT_H_ */ 184