blob: c6464bcf7ead6b4a844d81020f35702d254848c7 [file] [log] [blame]
/*
* Copyright (c) 2020 Oticon A/S
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "timer_model.h"
#include <zephyr/arch/posix/posix_soc_if.h>
#include <posix_board_if.h>
#include <posix_soc.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 = hwm_get_time() + usec_to_wait;
while (hwm_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 = hwm_get_time();
hwtimer_wake_in_time(time_start + to_wait);
posix_change_cpu_state_and_wait(true);
to_wait -= hwm_get_time() - time_start;
posix_irq_handler();
}
}