You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
78 lines
2.4 KiB
78 lines
2.4 KiB
/* |
|
* Copyright (c) 2020 Oticon A/S |
|
* Copyright (c) 2023 Nordic Semiconductor ASA |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <stdbool.h> |
|
#include <stdint.h> |
|
#include <zephyr/arch/posix/posix_soc_if.h> |
|
#include <posix_board_if.h> |
|
#include <posix_soc.h> |
|
#include "nsi_hw_scheduler.h" |
|
#include "nsi_timer_model.h" |
|
|
|
/** |
|
* Replacement to the kernel k_busy_wait() |
|
* Will block this thread (and therefore the whole Zephyr) during usec_to_wait |
|
* |
|
* Note that interrupts may be received in the meanwhile and that therefore this |
|
* thread may lose context. |
|
* Therefore the wait time may be considerably longer. |
|
* |
|
* All this function ensures is that it will return after usec_to_wait or later. |
|
* |
|
* This special arch_busy_wait() is necessary due to how the POSIX arch/SOC INF |
|
* models a CPU. Conceptually it could be thought as if the MCU was running |
|
* at an infinitely high clock, and therefore no simulated time passes while |
|
* executing instructions(*1). |
|
* Therefore to be able to busy wait this function does the equivalent of |
|
* programming a dedicated timer which will raise a non-maskable interrupt, |
|
* and halting the CPU. |
|
* |
|
* (*1) In reality simulated time is simply not advanced just due to the "MCU" |
|
* running. Meaning, the SW running on the MCU is assumed to take 0 time. |
|
*/ |
|
void arch_busy_wait(uint32_t usec_to_wait) |
|
{ |
|
uint64_t time_end = nsi_hws_get_time() + usec_to_wait; |
|
|
|
while (nsi_hws_get_time() < time_end) { |
|
/* |
|
* There may be wakes due to other interrupts including |
|
* other threads calling arch_busy_wait |
|
*/ |
|
hwtimer_wake_in_time(time_end); |
|
posix_halt_cpu(); |
|
} |
|
} |
|
|
|
/** |
|
* Will block this thread (and therefore the whole Zephyr) during usec_to_waste |
|
* |
|
* Very similar to arch_busy_wait(), but if an interrupt or context switch |
|
* occurs this function will continue waiting after, ensuring that |
|
* usec_to_waste are spent in this context, irrespectively of how much more |
|
* time would be spent on interrupt handling or possible switched-in tasks. |
|
* |
|
* Can be used to emulate code execution time. |
|
*/ |
|
void posix_cpu_hold(uint32_t usec_to_waste) |
|
{ |
|
uint64_t time_start; |
|
int64_t to_wait = usec_to_waste; |
|
|
|
while (to_wait > 0) { |
|
/* |
|
* There may be wakes due to other interrupts or nested calls to |
|
* cpu_hold in interrupt handlers |
|
*/ |
|
time_start = nsi_hws_get_time(); |
|
hwtimer_wake_in_time(time_start + to_wait); |
|
posix_change_cpu_state_and_wait(true); |
|
to_wait -= nsi_hws_get_time() - time_start; |
|
|
|
posix_irq_handler(); |
|
} |
|
}
|
|
|