Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2020 Oticon A/S
3 : : * Copyright (c) 2023 Nordic Semiconductor ASA
4 : : *
5 : : * SPDX-License-Identifier: Apache-2.0
6 : : */
7 : :
8 : : #include <stdbool.h>
9 : : #include <stdint.h>
10 : : #include <zephyr/arch/posix/posix_soc_if.h>
11 : : #include <posix_board_if.h>
12 : : #include <posix_soc.h>
13 : : #include "nsi_hw_scheduler.h"
14 : : #include "nsi_timer_model.h"
15 : :
16 : : /**
17 : : * Replacement to the kernel k_busy_wait()
18 : : * Will block this thread (and therefore the whole Zephyr) during usec_to_wait
19 : : *
20 : : * Note that interrupts may be received in the meanwhile and that therefore this
21 : : * thread may lose context.
22 : : * Therefore the wait time may be considerably longer.
23 : : *
24 : : * All this function ensures is that it will return after usec_to_wait or later.
25 : : *
26 : : * This special arch_busy_wait() is necessary due to how the POSIX arch/SOC INF
27 : : * models a CPU. Conceptually it could be thought as if the MCU was running
28 : : * at an infinitely high clock, and therefore no simulated time passes while
29 : : * executing instructions(*1).
30 : : * Therefore to be able to busy wait this function does the equivalent of
31 : : * programming a dedicated timer which will raise a non-maskable interrupt,
32 : : * and halting the CPU.
33 : : *
34 : : * (*1) In reality simulated time is simply not advanced just due to the "MCU"
35 : : * running. Meaning, the SW running on the MCU is assumed to take 0 time.
36 : : */
37 : 0 : void arch_busy_wait(uint32_t usec_to_wait)
38 : : {
39 : 0 : uint64_t time_end = nsi_hws_get_time() + usec_to_wait;
40 : :
41 [ # # ]: 0 : while (nsi_hws_get_time() < time_end) {
42 : : /*
43 : : * There may be wakes due to other interrupts including
44 : : * other threads calling arch_busy_wait
45 : : */
46 : 0 : hwtimer_wake_in_time(time_end);
47 : 0 : posix_halt_cpu();
48 : : }
49 : 0 : }
50 : :
51 : : /**
52 : : * Will block this thread (and therefore the whole Zephyr) during usec_to_waste
53 : : *
54 : : * Very similar to arch_busy_wait(), but if an interrupt or context switch
55 : : * occurs this function will continue waiting after, ensuring that
56 : : * usec_to_waste are spent in this context, irrespectively of how much more
57 : : * time would be spent on interrupt handling or possible switched-in tasks.
58 : : *
59 : : * Can be used to emulate code execution time.
60 : : */
61 : 0 : void posix_cpu_hold(uint32_t usec_to_waste)
62 : : {
63 : 0 : uint64_t time_start;
64 : 0 : int64_t to_wait = usec_to_waste;
65 : :
66 [ # # ]: 0 : while (to_wait > 0) {
67 : : /*
68 : : * There may be wakes due to other interrupts or nested calls to
69 : : * cpu_hold in interrupt handlers
70 : : */
71 : 0 : time_start = nsi_hws_get_time();
72 : 0 : hwtimer_wake_in_time(time_start + to_wait);
73 : 0 : posix_change_cpu_state_and_wait(true);
74 : 0 : to_wait -= nsi_hws_get_time() - time_start;
75 : :
76 : 0 : posix_irq_handler();
77 : : }
78 : 0 : }
|