]> begriffs open source - cmsis/blob - CMSIS/CoreValidation/Source/CV_CoreFunc.c
Core(M): Aligned PSPLIM and MSPLIM access functions among compilers and device variants.
[cmsis] / CMSIS / CoreValidation / Source / CV_CoreFunc.c
1 /*-----------------------------------------------------------------------------
2  *      Name:         CV_CoreFunc.c
3  *      Purpose:      CMSIS CORE validation tests implementation
4  *-----------------------------------------------------------------------------
5  *      Copyright (c) 2017 ARM Limited. All rights reserved.
6  *----------------------------------------------------------------------------*/
7
8 #include "CV_Framework.h"
9 #include "cmsis_cv.h"
10
11 /*-----------------------------------------------------------------------------
12  *      Test implementation
13  *----------------------------------------------------------------------------*/
14
15 static volatile uint32_t irqTaken = 0U;
16
17 static void TC_CoreFunc_EnDisIRQIRQHandler(void) {
18   ++irqTaken;
19 }
20
21 static volatile uint32_t irqIPSR = 0U;
22 static volatile uint32_t irqXPSR = 0U;
23
24 static void TC_CoreFunc_IPSR_IRQHandler(void) {
25   irqIPSR = __get_IPSR();
26   irqXPSR = __get_xPSR();
27 }
28
29 /*-----------------------------------------------------------------------------
30  *      Test cases
31  *----------------------------------------------------------------------------*/
32
33 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
34 /**
35 \brief Test case: TC_CoreFunc_EnDisIRQ
36 \details
37 - Check if __disable_irq() and __enable_irq() have expected behaviour.
38 */
39 void TC_CoreFunc_EnDisIRQ (void)
40 {
41   __disable_irq();
42
43   NVIC_EnableIRQ(WDT_IRQn);
44   NVIC_ClearPendingIRQ(WDT_IRQn);
45
46   TST_IRQHandler = TC_CoreFunc_EnDisIRQIRQHandler;
47   irqTaken = 0U;
48
49   NVIC_SetPendingIRQ(WDT_IRQn);
50   for(uint32_t i = 10U; i > 0U; --i) {}
51
52   // Interrupt is not taken
53   ASSERT_TRUE(irqTaken == 0U);
54
55   __enable_irq();
56
57   for(uint32_t i = 10U; i > 0U; --i) {}
58
59   // Interrupt was taken
60   ASSERT_TRUE(irqTaken == 1U);
61
62   __disable_irq();
63   NVIC_DisableIRQ(WDT_IRQn);
64 }
65
66 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
67 /**
68 \brief Test case: TC_CoreFunc_GetCtrl
69 \details
70 - Check if __set_CONTROL and __get_CONTROL() sets/gets control register
71 */
72 void TC_CoreFunc_Control (void) {
73   // don't use stack for this variables
74   static uint32_t orig;
75   static uint32_t ctrl;
76   static uint32_t result;
77
78   orig = __get_CONTROL();
79   ctrl = orig;
80   result = UINT32_MAX;
81
82 #ifdef CONTROL_SPSEL_Msk
83   // toggle SPSEL
84   ctrl = (ctrl & ~CONTROL_SPSEL_Msk) | (~ctrl & CONTROL_SPSEL_Msk);
85 #endif
86
87   __set_CONTROL(ctrl);
88   __ISB();
89
90   result = __get_CONTROL();
91
92   __set_CONTROL(orig);
93   __ISB();
94
95   ASSERT_TRUE(result == ctrl);
96   ASSERT_TRUE(__get_CONTROL() == orig);
97 }
98
99 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
100 /**
101 \brief Test case: TC_CoreFunc_IPSR
102 \details
103 - Check if __get_IPSR instrinsic is available
104 - Check if __get_xPSR instrinsic is available
105 - Result differentiates between thread and exception modes
106 */
107 void TC_CoreFunc_IPSR (void) {
108   uint32_t result = __get_IPSR();
109   ASSERT_TRUE(result == 0U); // Thread Mode
110
111   result = __get_xPSR();
112   ASSERT_TRUE((result & xPSR_ISR_Msk) == 0U); // Thread Mode
113
114   TST_IRQHandler = TC_CoreFunc_IPSR_IRQHandler;
115   irqIPSR = 0U;
116   irqXPSR = 0U;
117
118   NVIC_ClearPendingIRQ(WDT_IRQn);
119   NVIC_EnableIRQ(WDT_IRQn);
120   __enable_irq();
121
122   NVIC_SetPendingIRQ(WDT_IRQn);
123   for(uint32_t i = 10U; i > 0U; --i) {}
124
125   __disable_irq();
126   NVIC_DisableIRQ(WDT_IRQn);
127
128   ASSERT_TRUE(irqIPSR != 0U); // Exception Mode
129   ASSERT_TRUE((irqXPSR & xPSR_ISR_Msk) != 0U); // Exception Mode
130 }
131
132 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
133
134 #if defined(__CC_ARM)
135 #define SUBS(Rd, Rm, Rn) __ASM("SUBS " # Rd ", " # Rm ", " # Rn)
136 #define ADDS(Rd, Rm, Rn) __ASM("ADDS " # Rd ", " # Rm ", " # Rn)
137 #elif defined( __GNUC__ )  && (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__))
138 #define SUBS(Rd, Rm, Rn) __ASM("SUB %0, %1, %2" : "=r"(Rd) : "r"(Rm), "r"(Rn) : "cc")
139 #define ADDS(Rd, Rm, Rn) __ASM("ADD %0, %1, %2" : "=r"(Rd) : "r"(Rm), "r"(Rn) : "cc")
140 #elif defined(_lint)
141 //lint -save -e(9026) allow function-like macro
142 #define SUBS(Rd, Rm, Rn) ((Rd) = (Rm) - (Rn))
143 #define ADDS(Rd, Rm, Rn) ((Rd) = (Rm) + (Rn))
144 //lint -restore
145 #else
146 #define SUBS(Rd, Rm, Rn) __ASM("SUBS %0, %1, %2" : "=r"(Rd) : "r"(Rm), "r"(Rn) : "cc")
147 #define ADDS(Rd, Rm, Rn) __ASM("ADDS %0, %1, %2" : "=r"(Rd) : "r"(Rm), "r"(Rn) : "cc")
148 #endif
149
150 /**
151 \brief Test case: TC_CoreFunc_APSR
152 \details
153 - Check if __get_APSR instrinsic is available
154 - Check if __get_xPSR instrinsic is available
155 - Check negative, zero and overflow flags
156 */
157 void TC_CoreFunc_APSR (void) {
158   uint32_t result;
159   //lint -esym(838, Rm) unused values
160   //lint -esym(438, Rm) unused values
161
162   // Check negative flag
163   int32_t Rm = 5;
164   int32_t Rn = 7;
165   SUBS(Rm, Rm, Rn);
166   result  = __get_APSR();
167   ASSERT_TRUE((result & APSR_N_Msk) == APSR_N_Msk);
168
169   Rm = 5;
170   Rn = 7;
171   SUBS(Rm, Rm, Rn);
172   result  = __get_xPSR();
173   ASSERT_TRUE((result & xPSR_N_Msk) == xPSR_N_Msk);
174
175   // Check zero and compare flag
176   Rm = 5;
177   SUBS(Rm, Rm, Rm);
178   result  = __get_APSR();
179   ASSERT_TRUE((result & APSR_Z_Msk) == APSR_Z_Msk);
180   ASSERT_TRUE((result & APSR_C_Msk) == APSR_C_Msk);
181
182   Rm = 5;
183   SUBS(Rm, Rm, Rm);
184   result  = __get_xPSR();
185   ASSERT_TRUE((result & xPSR_Z_Msk) == xPSR_Z_Msk);
186   ASSERT_TRUE((result & APSR_C_Msk) == APSR_C_Msk);
187
188   // Check overflow flag
189   Rm = 5;
190   Rn = INT32_MAX;
191   ADDS(Rm, Rm, Rn);
192   result  = __get_APSR();
193   ASSERT_TRUE((result & APSR_V_Msk) == APSR_V_Msk);
194
195   Rm = 5;
196   Rn = INT32_MAX;
197   ADDS(Rm, Rm, Rn);
198   result  = __get_xPSR();
199   ASSERT_TRUE((result & xPSR_V_Msk) == xPSR_V_Msk);
200 }
201
202 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
203 /**
204 \brief Test case: TC_CoreFunc_PSP
205 \details
206 - Check if __get_PSP and __set_PSP instrinsic can be used to manipulate process stack pointer.
207 */
208 void TC_CoreFunc_PSP (void) {
209   // don't use stack for this variables
210   static uint32_t orig;
211   static uint32_t psp;
212   static uint32_t result;
213
214   orig = __get_PSP();
215
216   psp = orig + 0x12345678U;
217   __set_PSP(psp);
218
219   result = __get_PSP();
220
221   __set_PSP(orig);
222
223   ASSERT_TRUE(result == psp);
224 }
225
226 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
227 /**
228 \brief Test case: TC_CoreFunc_MSP
229 \details
230 - Check if __get_MSP and __set_MSP instrinsic can be used to manipulate main stack pointer.
231 */
232 void TC_CoreFunc_MSP (void) {
233   // don't use stack for this variables
234   static uint32_t orig;
235   static uint32_t msp;
236   static uint32_t result;
237   static uint32_t ctrl;
238
239   ctrl = __get_CONTROL();
240   __set_CONTROL(ctrl | CONTROL_SPSEL_Msk); // switch to PSP
241
242   orig = __get_MSP();
243
244   msp = orig + 0x12345678U;
245   __set_MSP(msp);
246
247   result = __get_MSP();
248
249   __set_MSP(orig);
250
251   __set_CONTROL(ctrl);
252
253   ASSERT_TRUE(result == msp);
254 }
255
256 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
257 #if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \
258      (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1))    )
259
260 /**
261 \brief Test case: TC_CoreFunc_PSPLIM
262 \details
263 - Check if __get_PSPLIM and __set_PSPLIM instrinsic can be used to manipulate process stack pointer limit.
264 */
265 void TC_CoreFunc_PSPLIM (void) {
266   // don't use stack for this variables
267   static uint32_t orig;
268   static uint32_t psplim;
269   static uint32_t result;
270
271   orig = __get_PSPLIM();
272
273   psplim = orig + 0x12345678U;
274   __set_PSPLIM(psplim);
275
276   result = __get_PSPLIM();
277
278   __set_PSPLIM(orig);
279
280 #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \
281      (!defined (__ARM_FEATURE_CMSE  ) || (__ARM_FEATURE_CMSE   < 3)))
282   // without main extensions, the non-secure PSPLIM is RAZ/WI
283   ASSERT_TRUE(result == 0U);
284 #else
285   ASSERT_TRUE(result == psplim);
286 #endif
287 }
288
289 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
290 /**
291 \brief Test case: TC_CoreFunc_PSPLIM_NS
292 \details
293 - Check if __TZ_get_PSPLIM_NS and __TZ_set_PSPLIM_NS instrinsic can be used to manipulate process stack pointer limit.
294 */
295 void TC_CoreFunc_PSPLIM_NS (void) {
296 #if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3))
297   uint32_t orig;
298   uint32_t psplim;
299   uint32_t result;
300
301   orig = __TZ_get_PSPLIM_NS();
302
303   psplim = orig + 0x12345678U;
304   __TZ_set_PSPLIM_NS(psplim);
305
306   result = __TZ_get_PSPLIM_NS();
307
308   __TZ_set_PSPLIM_NS(orig);
309
310 #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)))
311   // without main extensions, the non-secure PSPLIM is RAZ/WI
312   ASSERT_TRUE(result == 0U);
313 #else
314   ASSERT_TRUE(result == psplim);
315 #endif
316 #endif
317 }
318
319 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
320 /**
321 \brief Test case: TC_CoreFunc_MSPLIM
322 \details
323 - Check if __get_MSPLIM and __set_MSPLIM instrinsic can be used to manipulate main stack pointer limit.
324 */
325 void TC_CoreFunc_MSPLIM (void) {
326   // don't use stack for this variables
327   static uint32_t orig;
328   static uint32_t msplim;
329   static uint32_t result;
330   static uint32_t ctrl;
331
332   ctrl = __get_CONTROL();
333   __set_CONTROL(ctrl | CONTROL_SPSEL_Msk); // switch to PSP
334
335   orig = __get_MSPLIM();
336
337   msplim = orig + 0x12345678U;
338   __set_MSPLIM(msplim);
339
340   result = __get_MSPLIM();
341
342   __set_MSPLIM(orig);
343   
344   __set_CONTROL(ctrl);
345
346 #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \
347      (!defined (__ARM_FEATURE_CMSE  ) || (__ARM_FEATURE_CMSE   < 3)))
348   // without main extensions, the non-secure MSPLIM is RAZ/WI
349   ASSERT_TRUE(result == 0U);
350 #else
351   ASSERT_TRUE(result == msplim);
352 #endif
353 }
354
355 #endif
356
357 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
358 /**
359 \brief Test case: TC_CoreFunc_MSPLIM_NS
360 \details
361 - Check if __TZ_get_MSPLIM_NS and __TZ_set_MSPLIM_NS instrinsic can be used to manipulate process stack pointer limit.
362 */
363 void TC_CoreFunc_MSPLIM_NS (void) {
364 #if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3))
365   uint32_t orig;
366   uint32_t msplim;
367   uint32_t result;
368
369   orig = __TZ_get_MSPLIM_NS();
370
371   msplim = orig + 0x12345678U;
372   __TZ_set_MSPLIM_NS(msplim);
373
374   result = __TZ_get_MSPLIM_NS();
375
376   __TZ_set_MSPLIM_NS(orig);
377
378 #if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)))
379   // without main extensions, the non-secure PSPLIM is RAZ/WI
380   ASSERT_TRUE(result == 0U);
381 #else
382   ASSERT_TRUE(result == msplim);
383 #endif
384 #endif
385 }
386
387 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
388 /**
389 \brief Test case: TC_CoreFunc_PRIMASK
390 \details
391 - Check if __get_PRIMASK and __set_PRIMASK instrinsic can be used to manipulate PRIMASK.
392 - Check if __enable_irq and __disable_irq are reflected in PRIMASK.
393 */
394 void TC_CoreFunc_PRIMASK (void) {
395   uint32_t orig = __get_PRIMASK();
396
397   // toggle primask
398   uint32_t primask = (orig & ~0x01U) | (~orig & 0x01U);
399
400   __set_PRIMASK(primask);
401   uint32_t result = __get_PRIMASK();
402
403   ASSERT_TRUE(result == primask);
404
405   __disable_irq();
406   result = __get_PRIMASK();
407   ASSERT_TRUE((result & 0x01U) == 1U);
408
409   __enable_irq();
410   result = __get_PRIMASK();
411   ASSERT_TRUE((result & 0x01U) == 0U);
412
413   __disable_irq();
414   result = __get_PRIMASK();
415   ASSERT_TRUE((result & 0x01U) == 1U);
416
417   __set_PRIMASK(orig);
418 }
419
420 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
421 #if ((defined (__ARM_ARCH_7M__      ) && (__ARM_ARCH_7M__      == 1)) || \
422      (defined (__ARM_ARCH_7EM__     ) && (__ARM_ARCH_7EM__     == 1)) || \
423      (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))    )
424
425 /**
426 \brief Test case: TC_CoreFunc_FAULTMASK
427 \details
428 - Check if __get_FAULTMASK and __set_FAULTMASK instrinsic can be used to manipulate FAULTMASK.
429 - Check if __enable_fault_irq and __disable_fault_irq are reflected in FAULTMASK.
430 */
431 void TC_CoreFunc_FAULTMASK (void) {
432   uint32_t orig = __get_FAULTMASK();
433
434   // toggle faultmask
435   uint32_t faultmask = (orig & ~0x01U) | (~orig & 0x01U);
436
437   __set_FAULTMASK(faultmask);
438   uint32_t result = __get_FAULTMASK();
439
440   ASSERT_TRUE(result == faultmask);
441
442   __disable_fault_irq();
443   result = __get_FAULTMASK();
444   ASSERT_TRUE((result & 0x01U) == 1U);
445
446   __enable_fault_irq();
447   result = __get_FAULTMASK();
448   ASSERT_TRUE((result & 0x01U) == 0U);
449
450   __disable_fault_irq();
451   result = __get_FAULTMASK();
452   ASSERT_TRUE((result & 0x01U) == 1U);
453
454   __set_FAULTMASK(orig);
455 }
456
457 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
458 /**
459 \brief Test case: TC_CoreFunc_BASEPRI
460 \details
461 - Check if __get_BASEPRI and __set_BASEPRI instrinsic can be used to manipulate BASEPRI.
462 - Check if __set_BASEPRI_MAX instrinsic can be used to manipulate BASEPRI.
463 */
464 void TC_CoreFunc_BASEPRI(void) {
465   uint32_t orig = __get_BASEPRI();
466
467   uint32_t basepri = ~orig & 0x80U;
468   __set_BASEPRI(basepri);
469   uint32_t result = __get_BASEPRI();
470
471   ASSERT_TRUE(result == basepri);
472
473   __set_BASEPRI(orig);
474
475   __set_BASEPRI_MAX(basepri);
476   result = __get_BASEPRI();
477
478   ASSERT_TRUE(result == basepri);
479 }
480 #endif
481
482 /*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
483 #if ((defined (__ARM_ARCH_7EM__     ) && (__ARM_ARCH_7EM__     == 1)) || \
484      (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))    )
485
486 /**
487 \brief Test case: TC_CoreFunc_BASEPRI
488 \details
489 - Check if __get_FPSCR and __set_FPSCR intrinsics can be used
490 */
491 void TC_CoreFunc_FPSCR(void) {
492   uint32_t fpscr = __get_FPSCR();
493   __ISB();
494   __DSB();
495
496   __set_FPSCR(~fpscr);
497   __ISB();
498   __DSB();
499
500   uint32_t result = __get_FPSCR();
501
502   __set_FPSCR(fpscr);
503
504 #if (defined (__FPU_USED   ) && (__FPU_USED    == 1U))
505   ASSERT_TRUE(result != fpscr);
506 #else
507   (void)result;
508 #endif
509 }
510 #endif