1 /*
2  * Trace Recorder for Tracealyzer v4.8.1.hotfix1
3  * Copyright 2023 Percepio AB
4  * www.percepio.com
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  * The hardware abstraction layer for the trace recorder.
9  */
10 
11 #include <trcRecorder.h>
12 
13 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
14 
15 /* If using DWT timestamping (default on ARM Cortex-M3, M4 and M7), make sure the DWT unit is initialized. */
16 #if (((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) || (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M_NRF_SD)) && (defined (__CORTEX_M) && (__CORTEX_M >= 0x03)))
17 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
18 #ifndef TRC_CFG_ARM_CM_USE_SYSTICK
19 
xTraceHardwarePortInitCortexM(void)20 void xTraceHardwarePortInitCortexM(void)
21 {
22 	/* Make sure the DWT registers are unlocked, in case the debugger doesn't do this. */
23 	TRC_REG_ITM_LOCKACCESS = TRC_ITM_LOCKACCESS_UNLOCK;
24 
25 	/* Make sure DWT is enabled is enabled, if supported */
26 	TRC_REG_DEMCR |= TRC_DEMCR_TRCENA;
27 
28 	do
29 	{
30 		/* Verify that DWT is supported */
31 		if (TRC_REG_DEMCR == 0)
32 		{
33 			/* This function is called on Cortex-M3, M4 and M7 devices to initialize
34 			the DWT unit, assumed present. The DWT cycle counter is used for timestamping.
35 
36 			If the below error is produced, the DWT unit does not seem to be available.
37 
38 			In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build
39 			to use SysTick timestamping instead, or define your own timestamping by
40 			setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED
41 			and make the necessary definitions, as explained in trcHardwarePort.h.*/
42 
43 			xTraceError(TRC_ERROR_DWT_NOT_SUPPORTED);
44 			break;
45 		}
46 
47 		/* Verify that DWT_CYCCNT is supported */
48 		if (TRC_REG_DWT_CTRL & TRC_DWT_CTRL_NOCYCCNT)
49 		{
50 			/* This function is called on Cortex-M3, M4 and M7 devices to initialize
51 			the DWT unit, assumed present. The DWT cycle counter is used for timestamping.
52 
53 			If the below error is produced, the cycle counter does not seem to be available.
54 
55 			In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build
56 			to use SysTick timestamping instead, or define your own timestamping by
57 			setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED
58 			and make the necessary definitions, as explained in trcHardwarePort.h.*/
59 
60 			xTraceError(TRC_ERROR_DWT_CYCCNT_NOT_SUPPORTED);
61 			break;
62 		}
63 
64 		/* Reset the cycle counter */
65 		TRC_REG_DWT_CYCCNT = 0;
66 
67 		/* Enable the cycle counter */
68 		TRC_REG_DWT_CTRL |= TRC_DWT_CTRL_CYCCNTENA;
69 
70 	} while (0);	/* breaks above jump here */
71 }
72 #endif /* TRC_CFG_ARM_CM_USE_SYSTICK */
73 
74 #endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) */
75 #endif /* (((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) || (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M_NRF_SD)) && (defined (__CORTEX_M) && (__CORTEX_M >= 0x03))) */
76 
77 #if ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_CORTEX_A9) || (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_XILINX_ZyncUltraScaleR5) || (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_CYCLONE_V_HPS) || (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARMv8AR_A32))
78 
79 #define CS_TYPE_NONE 0
80 #define CS_TYPE_TASK 1
81 #define CS_TYPE_ISR_MASK_CHANGED 2
82 #define CS_TYPE_ISR_MASK_NOT_CHANGED 3
83 
84 #define CS_TYPE_INVALID 0xFFFFFFFF
85 
cortex_a9_r5_enter_critical(void)86 TraceUnsignedBaseType_t cortex_a9_r5_enter_critical(void)
87 {
88 	TraceUnsignedBaseType_t cs_type = CS_TYPE_INVALID;
89 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
90 	TraceunsignedBaseType_t uxTraceSystemState;
91 
92 	xTraceStateGet(&uxTraceSystemState);
93 #endif
94 
95     if ((prvGetCPSR() & 0x001F) == 0x13) // CSPR (ASPR) mode = SVC
96     {
97     	/* Executing in an ISR other than the context-switch (where interrupts might have been enabled, motivating a critical section). */
98     	if (ulPortSetInterruptMask() == pdTRUE)
99     	{
100     		cs_type = CS_TYPE_ISR_MASK_NOT_CHANGED;
101     	}
102     	else
103     	{
104     		cs_type = CS_TYPE_ISR_MASK_CHANGED;
105     	}
106     }
107 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
108     else if (uxTraceSystemState == TRC_STATE_IN_TASKSWITCH)
109 #else
110 	else if (uiTraceSystemState == TRC_STATE_IN_TASKSWITCH)
111 #endif
112     {
113     	// In the context-switch code. All interrupts are already masked here, so don't modify the mask.
114     	cs_type = CS_TYPE_NONE;
115     }
116 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
117     else if (uxTraceSystemState != TRC_STATE_IN_TASKSWITCH)
118 #else
119 	else if (uiTraceSystemState != TRC_STATE_IN_TASKSWITCH)
120 #endif
121     {
122     	// Not within ISR or task-switch context, use a regular critical section.
123     	vPortEnterCritical();
124     	cs_type = CS_TYPE_TASK;
125     }
126 
127 	return cs_type;
128 }
129 
cortex_a9_r5_exit_critical(TraceUnsignedBaseType_t cs_type)130 void cortex_a9_r5_exit_critical(TraceUnsignedBaseType_t cs_type)
131 {
132 	switch (cs_type)
133 	{
134 		case CS_TYPE_TASK:
135 			vPortExitCritical();
136 			break;
137 
138 		case CS_TYPE_ISR_MASK_CHANGED:
139 			vPortClearInterruptMask(pdFALSE);	// pdFALSE means it will reset the IRQ mask.
140 			break;
141 
142 		case CS_TYPE_ISR_MASK_NOT_CHANGED:
143 		case CS_TYPE_NONE:
144 			// No action in these two cases.
145 			break;
146 
147 		default:
148 			// Error, should not be possible;
149 			for (;;);
150 	}
151 }
152 #endif /* ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_CORTEX_A9) || (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_XILINX_ZyncUltraScaleR5)) */
153 
154 #endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */
155