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, "DWT implements no cycle counter. " 107 "Cannot be used for cycle counting\n"); 108 109 return 0; 110 } 111 112 /** 113 * @brief Return the current value of the cycle counter 114 * 115 * This routine returns the current value of the DWT Cycle Counter (DWT.CYCCNT) 116 * 117 * @return the cycle counter value 118 */ z_arm_dwt_get_cycles(void)119static inline uint32_t z_arm_dwt_get_cycles(void) 120 { 121 return DWT->CYCCNT; 122 } 123 124 /** 125 * @brief Reset and start the DWT cycle counter 126 * 127 * This routine starts the cycle counter and resets its value to zero. 128 */ z_arm_dwt_cycle_count_start(void)129static inline void z_arm_dwt_cycle_count_start(void) 130 { 131 DWT->CYCCNT = 0; 132 DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; 133 } 134 135 /** 136 * @brief Enable the debug monitor handler 137 * 138 * This routine enables the DebugMonitor handler to service 139 * data watchpoint events coming from DWT. The routine sets 140 * the DebugMonitor exception priority to highest possible. 141 */ z_arm_dwt_enable_debug_monitor(void)142static inline void z_arm_dwt_enable_debug_monitor(void) 143 { 144 /* 145 * In case the CPU is left in Debug mode, the behavior will be 146 * unpredictable if the DebugMonitor exception is triggered. We 147 * assert that the CPU is in normal mode. 148 */ 149 __ASSERT((CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) == 0, 150 "Cannot enable DBM when CPU is in Debug mode\n"); 151 152 #if defined(CONFIG_ARMV8_M_SE) && !defined(CONFIG_ARM_NONSECURE_FIRMWARE) 153 /* 154 * By design, the DebugMonitor exception is only employed 155 * for null-pointer dereferencing detection, and enabling 156 * that feature is not supported in Non-Secure builds. So 157 * when enabling the DebugMonitor exception, assert that 158 * it is not targeting the Non Secure domain. 159 */ 160 __ASSERT((CoreDebug->DEMCR & DCB_DEMCR_SDME_Msk) != 0, "DebugMonitor targets Non-Secure\n"); 161 #endif 162 163 /* The DebugMonitor handler priority is set already 164 * to the highest value (_EXC_FAULT_PRIO) during 165 * system initialization. 166 */ 167 168 /* Enable debug monitor exception triggered on debug events */ 169 CoreDebug->DEMCR |= CoreDebug_DEMCR_MON_EN_Msk; 170 } 171 172 #endif /* CONFIG_CORTEX_M_DWT */ 173 174 #ifdef __cplusplus 175 } 176 #endif 177 178 #endif /* _ASMLANGUAGE */ 179 180 #endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_DWT_H_ */ 181