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 */ 36 #if !defined DWT_LSR_Present_Msk 37 #define DWT_LSR_Present_Msk ITM_LSR_Present_Msk 38 #endif 39 #if !defined DWT_LSR_Access_Msk 40 #define DWT_LSR_Access_Msk ITM_LSR_Access_Msk 41 #endif 42 dwt_access(bool ena)43static inline void dwt_access(bool ena) 44 { 45 #if defined(CONFIG_CPU_CORTEX_M7) 46 /* 47 * In case of Cortex M7, we need to check the optional presence of 48 * Lock Access Register (LAR) which is indicated in Lock Status 49 * Register (LSR). When present, a special access token must be written 50 * to unlock DWT registers. 51 */ 52 uint32_t lsr = DWT->LSR; 53 54 if ((lsr & DWT_LSR_Present_Msk) != 0) { 55 if (ena) { 56 if ((lsr & DWT_LSR_Access_Msk) != 0) { 57 /* Access is locked. unlock it */ 58 DWT->LAR = 0xC5ACCE55; 59 } 60 } else { 61 if ((lsr & DWT_LSR_Access_Msk) == 0) { 62 /* Access is unlocked. Lock it */ 63 DWT->LAR = 0; 64 } 65 } 66 } 67 #else /* CONFIG_CPU_CORTEX_M7 */ 68 ARG_UNUSED(ena); 69 #endif /* CONFIG_CPU_CORTEX_M7 */ 70 } 71 72 /** 73 * @brief Enable DWT 74 * 75 * This routine enables the DWT unit. 76 * 77 * @return 0 78 */ z_arm_dwt_init(void)79static inline int z_arm_dwt_init(void) 80 { 81 /* Enable tracing */ 82 CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; 83 84 /* Unlock DWT access if any */ 85 dwt_access(true); 86 87 return 0; 88 } 89 90 /** 91 * @brief Initialize and Enable the DWT cycle counter 92 * 93 * This routine enables the cycle counter and initializes its value to zero. 94 * 95 * @return 0 96 */ z_arm_dwt_init_cycle_counter(void)97static inline int z_arm_dwt_init_cycle_counter(void) 98 { 99 /* Clear and enable the cycle counter */ 100 DWT->CYCCNT = 0; 101 DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; 102 103 /* Assert that the cycle counter is indeed implemented. 104 * The field is called NOCYCCNT. So 1 means there is no cycle counter. 105 */ 106 __ASSERT((DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk) == 0, 107 "DWT implements no cycle counter. " 108 "Cannot be used for cycle counting\n"); 109 110 return 0; 111 } 112 113 /** 114 * @brief Return the current value of the cycle counter 115 * 116 * This routine returns the current value of the DWT Cycle Counter (DWT.CYCCNT) 117 * 118 * @return the cycle counter value 119 */ z_arm_dwt_get_cycles(void)120static inline uint32_t z_arm_dwt_get_cycles(void) 121 { 122 return DWT->CYCCNT; 123 } 124 125 /** 126 * @brief Reset and start the DWT cycle counter 127 * 128 * This routine starts the cycle counter and resets its value to zero. 129 */ z_arm_dwt_cycle_count_start(void)130static inline void z_arm_dwt_cycle_count_start(void) 131 { 132 DWT->CYCCNT = 0; 133 DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; 134 } 135 136 /** 137 * @brief Enable the debug monitor handler 138 * 139 * This routine enables the DebugMonitor handler to service 140 * data watchpoint events coming from DWT. The routine sets 141 * the DebugMonitor exception priority to highest possible. 142 */ z_arm_dwt_enable_debug_monitor(void)143static inline void z_arm_dwt_enable_debug_monitor(void) 144 { 145 /* 146 * In case the CPU is left in Debug mode, the behavior will be 147 * unpredictable if the DebugMonitor exception is triggered. We 148 * assert that the CPU is in normal mode. 149 */ 150 __ASSERT((CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) == 0, 151 "Cannot enable DBM when CPU is in Debug mode\n"); 152 153 #if defined(CONFIG_ARMV8_M_SE) && !defined(CONFIG_ARM_NONSECURE_FIRMWARE) 154 /* 155 * By design, the DebugMonitor exception is only employed 156 * for null-pointer dereferencing detection, and enabling 157 * that feature is not supported in Non-Secure builds. So 158 * when enabling the DebugMonitor exception, assert that 159 * it is not targeting the Non Secure domain. 160 */ 161 __ASSERT((CoreDebug->DEMCR & DCB_DEMCR_SDME_Msk) != 0, 162 "DebugMonitor targets Non-Secure\n"); 163 #endif 164 165 /* The DebugMonitor handler priority is set already 166 * to the highest value (_EXC_FAULT_PRIO) during 167 * system initialization. 168 */ 169 170 /* Enable debug monitor exception triggered on debug events */ 171 CoreDebug->DEMCR |= CoreDebug_DEMCR_MON_EN_Msk; 172 } 173 174 #endif /* CONFIG_CORTEX_M_DWT */ 175 176 #ifdef __cplusplus 177 } 178 #endif 179 180 #endif /* _ASMLANGUAGE */ 181 182 #endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_DWT_H_ */ 183