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