1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 * Copyright (c) 2020 Oticon A/S
4 * Copyright (c) 2009-2017 ARM Limited. All rights reserved.
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 /**
10 * This header defines replacements for inline
11 * ARM Cortex-M CMSIS intrinsics.
12 */
13
14 #ifndef BOARDS_POSIX_NRF52_BSIM_CMSIS_INSTR_H
15 #define BOARDS_POSIX_NRF52_BSIM_CMSIS_INSTR_H
16
17 /* Implement the following ARM intrinsics as no-op:
18 * - ARM Data Synchronization Barrier
19 * - ARM Data Memory Synchronization Barrier
20 * - ARM Instruction Synchronization Barrier
21 * - ARM No Operation
22 */
23 #ifndef __DMB
24 #define __DMB()
25 #endif
26
27 #ifndef __DSB
28 #define __DSB()
29 #endif
30
31 #ifndef __ISB
32 #define __ISB()
33 #endif
34
35 #ifndef __NOP
36 #define __NOP()
37 #endif
38
39 void __WFE(void);
40 void __WFI(void);
41 void __SEV(void);
42
43 /*
44 * Implement the following ARM intrinsics as non-exclusive accesses
45 *
46 * - STR Exclusive(8,16 & 32bit) (__STREX{B,H,W})
47 * - LDR Exclusive(8,16 & 32bit) (__LDREX{B,H,W})
48 * - CLREX : Exclusive lock removal (__CLREX) - no-op
49 *
50 * Description:
51 * These accesses always succeed, and do NOT set any kind of internal
52 * exclusive access flag;
53 * There is no local/global memory monitors, MPU control of what are
54 * shareable regions, exclusive reservations granules, automatic clearing
55 * on context switch, or so.
56 *
57 * This should be enough for the expected uses of LDR/STREXB
58 * (locking mutexes or guarding other atomic operations, inside a few lines
59 * of code in the same function): As the POSIX arch will not make an embedded
60 * thread lose context while just executing its own code, and it does not
61 * allow parallel embedded SW threads to execute at the same exact time,
62 * there is no actual need to protect atomicity.
63 *
64 * But as this ARM exclusive access monitor mechanism can in principle be
65 * used for other, unexpected, purposes, this simple replacement may not be
66 * enough.
67 */
68
69 /**
70 * \brief Pretend to execute a STR Exclusive (8 bit)
71 * \details Executes a ~exclusive~ STR instruction for 8 bit values.
72 * \param [in] value Value to store
73 * \param [in] ptr Pointer to location
74 * \return 0 Function succeeded (always)
75 */
__STREXB(uint8_t value,volatile uint8_t * ptr)76 static inline uint32_t __STREXB(uint8_t value, volatile uint8_t *ptr)
77 {
78 *ptr = value;
79 return 0;
80 }
81
82 /**
83 * \brief Pretend to execute a STR Exclusive (16 bit)
84 * \details Executes a ~exclusive~ STR instruction for 16 bit values.
85 * \param [in] value Value to store
86 * \param [in] ptr Pointer to location
87 * \return 0 Function succeeded (always)
88 */
__STREXH(uint16_t value,volatile uint16_t * ptr)89 static inline uint32_t __STREXH(uint16_t value, volatile uint16_t *ptr)
90 {
91 *ptr = value;
92 return 0;
93 }
94
95 /**
96 * \brief Pretend to execute a STR Exclusive (32 bit)
97 * \details Executes a ~exclusive~ STR instruction for 32 bit values.
98 * \param [in] value Value to store
99 * \param [in] ptr Pointer to location
100 * \return 0 Function succeeded (always)
101 */
__STREXW(uint32_t value,volatile uint32_t * ptr)102 static inline uint32_t __STREXW(uint32_t value, volatile uint32_t *ptr)
103 {
104 *ptr = value;
105 return 0;
106 }
107
108 /**
109 * \brief Pretend to execute a LDR Exclusive (8 bit)
110 * \details Executes an ~exclusive~ LDR instruction for 8 bit value.
111 * Meaning, it does not set a exclusive lock,
112 * instead just loads the stored value
113 * \param [in] ptr Pointer to data
114 * \return value of type uint8_t at (*ptr)
115 */
__LDREXB(volatile uint8_t * ptr)116 static inline uint8_t __LDREXB(volatile uint8_t *ptr)
117 {
118 return *ptr;
119 }
120
121 /**
122 * \brief Pretend to execute a LDR Exclusive (16 bit)
123 * \details Executes an ~exclusive~ LDR instruction for 16 bit value.
124 * Meaning, it does not set a exclusive lock,
125 * instead just loads the stored value
126 * \param [in] ptr Pointer to data
127 * \return value of type uint8_t at (*ptr)
128 */
__LDREXH(volatile uint16_t * ptr)129 static inline uint16_t __LDREXH(volatile uint16_t *ptr)
130 {
131 return *ptr;
132 }
133
134 /**
135 * \brief Pretend to execute a LDR Exclusive (32 bit)
136 * \details Executes an ~exclusive~ LDR instruction for 32 bit value.
137 * Meaning, it does not set a exclusive lock,
138 * instead just loads the stored value
139 * \param [in] ptr Pointer to data
140 * \return value of type uint8_t at (*ptr)
141 */
__LDREXW(volatile uint32_t * ptr)142 static inline uint32_t __LDREXW(volatile uint32_t *ptr)
143 {
144 return *ptr;
145 }
146
147 /**
148 * \brief Pretend to remove the exclusive lock
149 * \details The real function would removes the exclusive lock which is created
150 * by LDREX, this one does nothing
151 */
__CLREX(void)152 static inline void __CLREX(void) { /* Nothing to be done */ }
153
154 /**
155 * \brief Model of an ARM CLZ instruction
156 */
__CLZ(uint32_t value)157 static inline unsigned char __CLZ(uint32_t value)
158 {
159 if (value == 0) {
160 return 32;
161 } else {
162 return __builtin_clz(value);
163 }
164 }
165
166 #endif /* BOARDS_POSIX_NRF52_BSIM_CMSIS_INSTR_H */
167