@@ -97,3 +97,156 @@ void __SEV(void)
9797{
9898 nrfbsim_SEV_model ();
9999}
100+
101+ /*
102+ * Implement the following ARM instructions
103+ *
104+ * - STR Exclusive(8,16 & 32bit) (__STREX{B,H,W})
105+ * - LDR Exclusive(8,16 & 32bit) (__LDREX{B,H,W})
106+ * - CLREX : Exclusive lock removal (__CLREX)
107+ *
108+ * Description:
109+ * From ARMs description it is relatively unclear how the LDREX/STREX/CLREX
110+ * are really implemented in M4/M33 devices.
111+ *
112+ * The current model simply sets a local monitor (local to the processor)
113+ * exclusive lock for the current MCU when a LDREX is executed.
114+ * STREX check this lock, and succeeds if set, fails otherwise.
115+ * The lock is cleared whenever STREX or CLREX are run, or when we return
116+ * from an interrupt handler.
117+ * See Arm v8-M Architecture Reference Manual: "B9.2 The local monitors" and
118+ * "B9.4 Exclusive access instructions and the monitors".
119+ *
120+ * The address is ignored, and we do not model a "system/global" monitor.
121+ * The access width is ignored from the locking point of view.
122+ * In principle this model would seem to fulfill the functionality described
123+ * by ARM.
124+ *
125+ * Note that as the POSIX arch will not make an embedded
126+ * thread lose context while just executing its own code, and it does not
127+ * allow parallel embedded SW threads to execute at the same exact time,
128+ * there is no real need to protect atomicity.
129+ * But, some embedded code may use this instructions in between busy waits,
130+ * and expect that an interrupt in the meanwhile will indeed cause a
131+ * following STREX to fail.
132+ *
133+ * As this ARM exclusive access monitor mechanism can in principle be
134+ * used for other, unexpected, purposes, this simple replacement may not be
135+ * enough.
136+ */
137+
138+ static bool ex_lock ; /* LDREX/STREX/CLREX lock state */
139+
140+ bool nrfbsim_STREXlock_model (void )
141+ {
142+ if (ex_lock == false) {
143+ return true;
144+ }
145+
146+ ex_lock = false;
147+ return false;
148+ }
149+
150+ void nrfbsim_clear_excl_access (void )
151+ {
152+ ex_lock = false;
153+ }
154+
155+ /**
156+ * \brief Pretend to execute a STR Exclusive (8 bit)
157+ * \details Executes an exclusive STR instruction for 8 bit values.
158+ * \param [in] value Value to store
159+ * \param [in] ptr Pointer to location
160+ * \return 0 Function succeeded
161+ * \return 1 Function did not succeeded (value not changed)
162+ */
163+ uint32_t __STREXB (uint8_t value , volatile uint8_t * ptr )
164+ {
165+ if (nrfbsim_STREXlock_model ()) {
166+ return 1 ;
167+ }
168+ * ptr = value ;
169+ return 0 ;
170+ }
171+
172+ /**
173+ * \brief Pretend to execute a STR Exclusive (16 bit)
174+ * \details Executes a exclusive STR instruction for 16 bit values.
175+ * \param [in] value Value to store
176+ * \param [in] ptr Pointer to location
177+ * \return 0 Function succeeded
178+ * \return 1 Function did not succeeded (value not changed)
179+ */
180+ uint32_t __STREXH (uint16_t value , volatile uint16_t * ptr )
181+ {
182+ if (nrfbsim_STREXlock_model ()) {
183+ return 1 ;
184+ }
185+ * ptr = value ;
186+ return 0 ;
187+ }
188+
189+ /**
190+ * \brief Pretend to execute a STR Exclusive (32 bit)
191+ * \details Executes a exclusive~ STR instruction for 32 bit values.
192+ * \param [in] value Value to store
193+ * \param [in] ptr Pointer to location
194+ * \return 0 Function succeeded
195+ * \return 1 Function did not succeeded (value not changed)
196+ */
197+ uint32_t __STREXW (uint32_t value , volatile uint32_t * ptr )
198+ {
199+ if (nrfbsim_STREXlock_model ()) {
200+ return 1 ;
201+ }
202+ * ptr = value ;
203+ return 0 ;
204+ }
205+
206+ /**
207+ * \brief Pretend to execute a LDR Exclusive (8 bit)
208+ * \details Executes an exclusive LDR instruction for 8 bit value.
209+ * Meaning, set an exclusive lock, and load the stored value
210+ * \param [in] ptr Pointer to data
211+ * \return value of type uint8_t at (*ptr)
212+ */
213+ uint8_t __LDREXB (volatile uint8_t * ptr )
214+ {
215+ ex_lock = true;
216+ return * ptr ;
217+ }
218+
219+ /**
220+ * \brief Pretend to execute a LDR Exclusive (16 bit)
221+ * \details Executes an ~exclusive~ LDR instruction for 16 bit value.
222+ * Meaning, set an exclusive lock, and load the stored value
223+ * \param [in] ptr Pointer to data
224+ * \return value of type uint8_t at (*ptr)
225+ */
226+ uint16_t __LDREXH (volatile uint16_t * ptr )
227+ {
228+ ex_lock = true;
229+ return * ptr ;
230+ }
231+
232+ /**
233+ * \brief Execute a LDR Exclusive (32 bit)
234+ * \details Executes an exclusive LDR instruction for 32 bit value.
235+ * Meaning, set an exclusive lock, and load the stored value
236+ * \param [in] ptr Pointer to data
237+ * \return value of type uint8_t at (*ptr)
238+ */
239+ uint32_t __LDREXW (volatile uint32_t * ptr )
240+ {
241+ ex_lock = true;
242+ return * ptr ;
243+ }
244+
245+ /**
246+ * \brief Remove the exclusive lock
247+ * \details Removes the exclusive lock which is created by LDREX
248+ */
249+ void __CLREX (void )
250+ {
251+ ex_lock = false;
252+ }
0 commit comments