1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 */
7
8 #include "nrfx.h"
9 #if defined(NRF52833_XXAA)
10 #include "hal/nrf_ccm.h"
11 #include "hal/nrf_rtc.h"
12 #include "hal/nrf_gpio.h"
13 #include "hal/nrf_gpiote.h"
14 #include "hal/nrf_temp.h"
15 #include "hal/nrf_radio.h"
16 #include "hal/nrf_egu.h"
17 #include "hal/nrf_timer.h"
18 #include "hal/nrf_clock.h"
19 #include "hal/nrf_rng.h"
20 #include "hal/nrf_aar.h"
21 #include "hal/nrf_ppi.h"
22 #include "hal/nrf_ecb.h"
23 #include "hal/nrf_uart.h"
24 #include "hal/nrf_uarte.h"
25 #elif defined(NRF5340_XXAA_NETWORK)
26 #include "hal/nrf_aar.h"
27 #include "hal/nrf_ccm.h"
28 #include "hal/nrf_ecb.h"
29 #include "hal/nrf_ipc.h"
30 #include "hal/nrf_radio.h"
31 #include "hal/nrf_rng.h"
32 #include "hal/nrf_temp.h"
33
34 #include "hal/nrf_clock.h"
35 #include "hal/nrf_dppi.h"
36 #include "hal/nrf_egu.h"
37 #include "hal/nrf_gpiote.h"
38 #include "hal/nrf_ipc.h"
39 #include "hal/nrf_rtc.h"
40 #include "hal/nrf_timer.h"
41 #include "hal/nrf_uarte.h"
42 #elif defined(NRF5340_XXAA_APPLICATION)
43 #include "hal/nrf_clock.h"
44 #include "hal/nrf_dppi.h"
45 #include "hal/nrf_egu.h"
46 #include "hal/nrf_gpiote.h"
47 #include "hal/nrf_ipc.h"
48 #include "hal/nrf_rtc.h"
49 #include "hal/nrf_timer.h"
50 #include "hal/nrf_uarte.h"
51 #elif defined(NRF54L15_XXAA)
52 #include "hal/nrf_aar.h"
53 #include "hal/nrf_ccm.h"
54 #include "hal/nrf_clock.h"
55 #include "hal/nrf_ecb.h"
56 #include "hal/nrf_egu.h"
57 #include "hal/nrf_dppi.h"
58 #include "hal/nrf_gpiote.h"
59 #include "hal/nrf_grtc.h"
60 //#include "hal/nrf_pdm.h" //Pending support in real HAL
61 #include "hal/nrf_ppib.h"
62 #include "hal/nrf_pwm.h"
63 #include "hal/nrf_radio.h"
64 #include "hal/nrf_timer.h"
65 #include "hal/nrf_temp.h"
66 #include "hal/nrf_uarte.h"
67 #endif
68
69 #include "bs_tracing.h"
70
71 #define PERIPHERAL_REG_BASE(per, nbr, post) \
72 (void*)NRF_##per##nbr##post##_BASE
73
74 #define IS_PERIPHERAL_REG(p, per, nbr, post) \
75 (p >= PERIPHERAL_REG_BASE(per, nbr, post)) && \
76 ((uintptr_t)p < (uintptr_t)PERIPHERAL_REG_BASE(per, nbr, post) + sizeof(NRF_##per##_Type))
77
78 typedef void (*subscribe_set_f)(void *, int , uint8_t);
79 typedef void (*subscribe_clear_f)(void *, int);
80 typedef void (*task_trigger_f)(void *, int);
81
82 /*
83 * Given a peripheral task/event (task_event) value (A value of a nrf_<peri>_task_t or nrf_<peri>_event_t)
84 * return true if it is a task, or false if it is an event
85 */
nrf_hack_is_task(int task_event)86 static bool nrf_hack_is_task(int task_event) {
87 /*
88 * In the NRF peripherals:
89 * [0x000..0x080) are tasks
90 * [0x080..0x100) are subscribe registers
91 * [0x100..0x180) are events
92 * [0x180..0x200) are publish registers
93 * Note: For the nrf54 RADIO, each group is twice as big, but tasks are still < 0x100
94 */
95 if (task_event < 0x100) {
96 return true;
97 } else {
98 return false;
99 }
100 }
101
102 /*
103 * Given a pointer to a task or event register in an unknown peripheral
104 * Get
105 * **p_reg: A pointer to the register base address
106 * *set_f/clear_f: pointers to the HAL subscribe set and clear functions that correspond to that peripheral
107 * *trigger_f: pointer to the HAL task trigger function corresponding to that peripheral
108 * The task/event *offset* corresponding to that subscribe register (input to most nrf HAL functions)
109 */
nrf_hack_get_task_from_ptr(void * task_reg,void ** p_reg,subscribe_set_f * set_f,subscribe_clear_f * clear_f,task_trigger_f * trigger_f,int * task)110 static void nrf_hack_get_task_from_ptr(void *task_reg,
111 void **p_reg,
112 subscribe_set_f *set_f,
113 subscribe_clear_f *clear_f,
114 task_trigger_f *trigger_f,
115 int *task) {
116
117 #if defined(DPPI_PRESENT)
118 #define IF_PER(per, nbr, post, lname) \
119 if (IS_PERIPHERAL_REG(task_reg, per, nbr, post)) { \
120 *p_reg = PERIPHERAL_REG_BASE(per, nbr, post); \
121 *task = (intptr_t)task_reg - (intptr_t)*p_reg; \
122 *set_f = (subscribe_set_f)nrf_##lname##_subscribe_set; \
123 *clear_f = (subscribe_clear_f)nrf_##lname##_subscribe_clear; \
124 *trigger_f = (task_trigger_f)nrf_##lname##_task_trigger;\
125 return;
126 #else
127 #define IF_PER(per, nbr, post, lname) \
128 if (IS_PERIPHERAL_REG(task_reg, per, nbr, post)) { \
129 *p_reg = PERIPHERAL_REG_BASE(per, nbr, post); \
130 *task = (intptr_t)task_reg - (intptr_t)*p_reg; \
131 *set_f = NULL; \
132 *clear_f = NULL; \
133 *trigger_f = (task_trigger_f)nrf_##lname##_task_trigger;\
134 return;
135 #endif
136
137 #if defined(NRF52833_XXAA)
138 IF_PER(CLOCK, , , clock)
139 } else IF_PER(RADIO, , , radio)
140 } else IF_PER(UART, 0, , uart)
141 } else IF_PER(UARTE, 0, , uarte)
142 } else IF_PER(UARTE, 1, , uarte)
143 } else IF_PER(RNG, , , rng)
144 } else IF_PER(GPIOTE, , , gpiote)
145 } else IF_PER(TIMER, 0, , timer)
146 } else IF_PER(TIMER, 1, , timer)
147 } else IF_PER(TIMER, 2, , timer)
148 } else IF_PER(TIMER, 3, , timer)
149 } else IF_PER(TIMER, 4, , timer)
150 } else IF_PER(ECB, , , ecb)
151 } else IF_PER(AAR, , , aar)
152 } else IF_PER(CCM, , , ccm)
153 } else IF_PER(PPI, , , ppi)
154 } else IF_PER(EGU, 0, , egu)
155 } else IF_PER(EGU, 1, , egu)
156 } else IF_PER(EGU, 2, , egu)
157 } else IF_PER(EGU, 3, , egu)
158 } else IF_PER(EGU, 4, , egu)
159 } else IF_PER(EGU, 5, , egu)
160 } else IF_PER(RTC, 0, , rtc)
161 } else IF_PER(RTC, 1, , rtc)
162 } else IF_PER(RTC, 2, , rtc)
163 } else IF_PER(TEMP, , , temp)
164 } else {
165 bs_trace_error_time_line("Tried to look for a task register not known to these HW models\n");
166 return; /* unreachable */
167 }
168 #elif defined(NRF5340_XXAA_NETWORK)
169 /*IF_PER(POWER, , _NS, power)
170 } else*/ IF_PER(CLOCK, , _NS, clock)
171 } else IF_PER(RADIO, , _NS, radio)
172 } else IF_PER(RNG, , _NS, rng)
173 } else IF_PER(GPIOTE, , _NS, gpiote)
174 /* 11 WDT */
175 } else IF_PER(TIMER, 0, _NS, timer)
176 } else IF_PER(ECB, , _NS, ecb)
177 } else IF_PER(AAR, , _NS, aar)
178 } else IF_PER(CCM, , _NS, ccm)
179 } else IF_PER(DPPIC, , _NS, dppi)
180 } else IF_PER(TEMP, , _NS, temp)
181 } else IF_PER(RTC, 0, _NS, rtc)
182 } else IF_PER(IPC, , _NS, ipc)
183 } else IF_PER(UARTE, 0, _NS, uarte)
184 } else IF_PER(EGU, 0, _NS, egu)
185 } else IF_PER(RTC, 1, _NS, rtc)
186 } else IF_PER(TIMER, 1, _NS, timer)
187 } else IF_PER(TIMER, 2, _NS, timer)
188 } else {
189 bs_trace_error_time_line("Tried to look for a task register not known to these HW models\n");
190 return; /* unreachable */
191 }
192 #elif defined(NRF5340_XXAA_APPLICATION)
193 /*IF_PER(DCNF, , _NS, dcnf)
194 } else IF_PER(FPU, , _NS, fpu)
195 } else IF_PER(CACHE, , _NS, cache)
196 } else IF_PER(SPU, , _NS, spu)
197 } else IF_PER(OSCILLARTORS, , _NS, oscillators)
198 } else IF_PER(REGULATORS, , _NS, regulators)
199 } else */ IF_PER(CLOCK, , _NS, clock)
200 /*} else IF_PER(POWER, , _NS, power)
201 } else IF_PER(RESET, , _NS, reset)
202 } else IF_PER(CTRLAP, , _NS, ctrlap)
203 } else IF_PER(SPIM, 0, _NS, spi) */
204 } else IF_PER(UARTE, 0, _NS, uarte)
205 /*} else IF_PER(SPIM, 1, _NS, spi)*/
206 } else IF_PER(UARTE, 1, _NS, uarte)
207 /*} else IF_PER(SPIM, 4, _NS, spi)
208 } else IF_PER(SPIM, 2, _NS, spi)*/
209 } else IF_PER(UARTE, 2, _NS, uarte)
210 /*} else IF_PER(SPIM, 3, _NS, spi) */
211 } else IF_PER(UARTE, 3, _NS, uarte)
212 } else IF_PER(GPIOTE, 0, _S, gpiote)
213 /*} else IF_PER(SAADC, , _NS, saadc)*/
214 } else IF_PER(TIMER, 0, _NS, timer)
215 } else IF_PER(TIMER, 1, _NS, timer)
216 } else IF_PER(TIMER, 2, _NS, timer)
217 } else IF_PER(RTC, 0, _NS, rtc)
218 } else IF_PER(RTC, 1, _NS, rtc)
219 } else IF_PER(DPPIC, , _NS, dppi)
220 /*} else IF_PER(WDT0, , _NS, dppi)
221 } else IF_PER(WDT1, , _NS, dppi)
222 } else IF_PER(COMP, , _NS, dppi)*/
223 } else IF_PER(EGU, 0, _NS, egu)
224 } else IF_PER(EGU, 1, _NS, egu)
225 } else IF_PER(EGU, 2, _NS, egu)
226 } else IF_PER(EGU, 3, _NS, egu)
227 } else IF_PER(EGU, 4, _NS, egu)
228 } else IF_PER(EGU, 5, _NS, egu)
229 /*} else IF_PER(PWM0, , _NS, dppi)
230 } else IF_PER(PWM1, , _NS, dppi)
231 } else IF_PER(PWM2, , _NS, dppi)
232 } else IF_PER(PWM3, , _NS, dppi)
233 } else IF_PER(PDM0, , _NS, dppi)
234 } else IF_PER(I2S0, , _NS, dppi)*/
235 } else IF_PER(IPC, , _NS, ipc)
236 /* QSPI, NFCT */
237 } else {
238 bs_trace_error_time_line("Tried to look for a task register not known to these HW models\n");
239 return; /* unreachable */
240 }
241 #elif defined(NRF54L15_XXAA)
242 /*IF_PER(SPU, 00, _S, spu)
243 } else IF_PER(MPC, 00, _S, mpc)
244 } else*/ IF_PER(DPPIC, 00, _S, dppi)
245 //} else IF_PER(PPIB, 00, _S, ppib)
246 //} else IF_PER(KMU, , _S, kmu)
247 } else IF_PER(AAR, 00, _S, aar)
248 } else IF_PER(CCM, 00, _S, ccm)
249 } else IF_PER(ECB, 00, _S, ecb)
250 //} else IF_PER(CRCEN, , _S, cracen)
251 //} else IF_PER(SPIM, 00, _S, spi)
252 } else IF_PER(UARTE, 00, _S, uarte)
253 //} else IF_PER(GLITCHDET, , _S, glitchdet)
254 //} else IF_PER(RRAMC, , _S, rramc)
255 //} else IF_PER(VPR, 00 , _S, vpr)
256 //} else IF_PER(CTRLAP, , _S, ctrlap)
257 } else IF_PER(TIMER, 00, _S, timer)
258 //} else IF_PER(SPU, 10, _S, spu)
259 } else IF_PER(DPPIC, 10, _S, dppi)
260 //} else IF_PER(PPIB, 10, _S, ppib)
261 //} else IF_PER(PPIB, 11, _S, ppib)
262 } else IF_PER(TIMER, 10, _S, timer)
263 } else IF_PER(EGU, 10, _S, egu)
264 } else IF_PER(RADIO, , _S, radio)
265 //} else IF_PER(SPU, 20, _S, spu)
266 } else IF_PER(DPPIC, 20, _S, dppi)
267 //} else IF_PER(PPIB, 20, _S, ppib)
268 //} else IF_PER(PPIB, 21, _S, ppib)
269 //} else IF_PER(PPIB, 22, _S, ppib)
270 //} else IF_PER(SPIM, 20, _S, spi)
271 //} else IF_PER(TWIM, 20, _S, twi)
272 } else IF_PER(UARTE, 20, _S, uarte)
273 //} else IF_PER(SPIM, 21, _S, spi)
274 //} else IF_PER(TWIM, 21, _S, twi)
275 } else IF_PER(UARTE, 21, _S, uarte)
276 //} else IF_PER(SPIM, 22, _S, spi)
277 //} else IF_PER(TWIM, 22, _S, twi)
278 } else IF_PER(UARTE, 22, _S, uarte)
279 } else IF_PER(EGU, 20, _S, egu)
280 } else IF_PER(TIMER, 20, _S, timer)
281 } else IF_PER(TIMER, 21, _S, timer)
282 } else IF_PER(TIMER, 22, _S, timer)
283 } else IF_PER(TIMER, 23, _S, timer)
284 } else IF_PER(TIMER, 24, _S, timer)
285 //} else IF_PER(MEMCONF, , _S, memconf)
286 //} else IF_PER(PDM, 20, _S, pdm)
287 //} else IF_PER(PDM, 21, _S, pdm)
288 //} else IF_PER(PWM, 20, _S, pwm)
289 //} else IF_PER(PWM, 21, _S, pwm)
290 //} else IF_PER(PWM, 22, _S, pwm)
291 //} else IF_PER(SAADC, , _S, saadc)
292 //} else IF_PER(NFCT, , _S, nfct)
293 } else IF_PER(TEMP, , _S, temp)
294 } else IF_PER(GPIOTE, 20, _S, gpiote)
295 //} else IF_PER(TAMPC, , _S, tamp)
296 //} else IF_PER(I2S, 20, _S, i2s)
297 //} else IF_PER(QDEC, 20, _S, qdec)
298 //} else IF_PER(QDEC, 21, _S, qdec)
299 } else IF_PER(GRTC, , _S, grtc)
300 //} else IF_PER(SPU, 30, _S, spu)
301 } else IF_PER(DPPIC, 30, _S, dppi)
302 //} else IF_PER(PPIB, 30, _S, ppib)
303 //} else IF_PER(SPIM, 30, _S, spi)
304 //} else IF_PER(TWIM, 30, _S, twi)
305 } else IF_PER(UARTE, 30, _S, uarte)
306 //} else IF_PER(COMP, , _S, comp)
307 //} else IF_PER(LPCOMP, , _S, lpcomp)
308 //} else IF_PER(WDT, 30, _S, wdt)
309 //} else IF_PER(WDT, 31, _S, wdt)
310 } else IF_PER(GPIOTE, 30, _S, gpiote)
311 } else IF_PER(CLOCK, , _NS, clock)
312 //} else IF_PER(POWER, , _NS, power)
313 //} else IF_PER(RESET, , _NS, reset)
314 //} else IF_PER(OSCILLARTORS, , _NS, oscillators)
315 //} else IF_PER(REGULATORS, , _NS, regulators)
316 } else {
317 bs_trace_error_time_line("Tried to look for a task register not known to these HW models\n");
318 return; /* unreachable */
319 }
320 #endif
321
322 #undef IF_PER
323 }
324
325 #if defined(DPPI_PRESENT)
326 /*
327 * Given a *<subscribe>* register (NOT a task register),
328 * set it to be enabled and connected to <channel>, by calling the appropriate
329 * HAL set replacement function.
330 *
331 * This function provides the backend for the NRF_DPPI_ENDPOINT_SETUP HAL macro
332 * for simulation.
333 *
334 * Note: This function also accepts publish registers, but ignores them
335 * (so as to be callable from NRF_DPPI_ENDPOINT_SETUP() without any check)
336 */
337 void nrf_dppi_hack_subscribe_set(void *sub_reg, unsigned int channel)
338 {
339 void *p_reg;
340 int task;
341 subscribe_set_f set_f;
342 subscribe_clear_f clear_f;
343 task_trigger_f task_trigger_f;
344
345 intptr_t task_reg_pr = (intptr_t)sub_reg - NRF_SUBSCRIBE_PUBLISH_OFFSET((uintptr_t)sub_reg);
346
347 nrf_hack_get_task_from_ptr((void *)task_reg_pr, &p_reg, &set_f, &clear_f, &task_trigger_f, &task);
348 if (nrf_hack_is_task(task)) {
349 set_f(p_reg, task, channel);
350 }
351 }
352
353 /*
354 * Given a *<subscribe>* register (NOT a task register),
355 * clear it/set it to be disabled, by calling the appropriate
356 * HAL clear replacement function.
357 *
358 * This function provides the backend for the NRF_DPPI_ENDPOINT_CLEAR HAL macro
359 * for simulation.
360 *
361 * Note: This function also accepts publish registers, but ignores them
362 * (so as to be callable from NRF_DPPI_ENDPOINT_SETUP() without any check)
363 */
364 void nrf_dppi_hack_subscribe_clear(void *sub_reg)
365 {
366 void *p_reg;
367 int task;
368 subscribe_set_f set_f;
369 subscribe_clear_f clear_f;
370 task_trigger_f trigger_f;
371
372 intptr_t task_reg_pr = (intptr_t)sub_reg - NRF_SUBSCRIBE_PUBLISH_OFFSET((uintptr_t)sub_reg);
373
374 nrf_hack_get_task_from_ptr((void *)task_reg_pr, &p_reg, &set_f, &clear_f, &trigger_f, &task);
375 if (nrf_hack_is_task(task)) {
376 clear_f(p_reg, task);
377 }
378 }
379
380 #endif /* DPPI_PRESENT */
381
382 /*
383 * Given a task register address for an unspecified peripheral,
384 * trigger the corresponding task in the hardware model.
385 */
386 void nrf_hack_trigger_task_address(void *task_reg)
387 {
388 void *p_reg;
389 int task;
390 subscribe_set_f set_f;
391 subscribe_clear_f clear_f;
392 task_trigger_f trigger_f;
393
394 nrf_hack_get_task_from_ptr(task_reg, &p_reg, &set_f, &clear_f, &trigger_f, &task);
395
396 if (nrf_hack_is_task(task)) {
397 trigger_f(p_reg, task);
398 }
399 }
400