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 */ arch_busy_wait(uint32_t usec_to_wait)37void arch_busy_wait(uint32_t usec_to_wait) 38 { 39 uint64_t time_end = nsi_hws_get_time() + usec_to_wait; 40 41 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 hwtimer_wake_in_time(time_end); 47 posix_halt_cpu(); 48 } 49 } 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 */ posix_cpu_hold(uint32_t usec_to_waste)61void posix_cpu_hold(uint32_t usec_to_waste) 62 { 63 uint64_t time_start; 64 int64_t to_wait = usec_to_waste; 65 66 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 time_start = nsi_hws_get_time(); 72 hwtimer_wake_in_time(time_start + to_wait); 73 posix_change_cpu_state_and_wait(true); 74 to_wait -= nsi_hws_get_time() - time_start; 75 76 posix_irq_handler(); 77 } 78 } 79