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