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.
139 lines
3.6 KiB
139 lines
3.6 KiB
/* |
|
* Copyright (c) 2017 Oticon A/S |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
/** |
|
* For all purposes, Zephyr threads see a CPU running at an infinitely high |
|
* clock. |
|
* |
|
* Therefore, the code will always run until completion after each interrupt, |
|
* after which arch_cpu_idle() will be called releasing the execution back to |
|
* the HW models. |
|
* |
|
* The HW models raising an interrupt will "awake the cpu" by calling |
|
* posix_interrupt_raised() which will transfer control to the irq handler, |
|
* which will run inside SW/Zephyr context. After which a arch_swap() to |
|
* whatever Zephyr thread may follow. Again, once Zephyr is done, control is |
|
* given back to the HW models. |
|
* |
|
* The Zephyr OS+APP code and the HW models are gated by a mutex + |
|
* condition as there is no reason to let the zephyr threads run while the |
|
* HW models run or vice versa |
|
* |
|
*/ |
|
|
|
#include <zephyr/arch/posix/posix_soc_if.h> |
|
#include "posix_soc.h" |
|
#include "posix_board_if.h" |
|
#include "posix_core.h" |
|
#include "posix_arch_internal.h" |
|
#include "kernel_internal.h" |
|
#include "soc.h" |
|
#include "nce_if.h" |
|
|
|
static void *nce_st; |
|
|
|
int posix_is_cpu_running(void) |
|
{ |
|
return nce_is_cpu_running(nce_st); |
|
} |
|
|
|
/** |
|
* Helper function which changes the status of the CPU (halted or running) |
|
* and waits until somebody else changes it to the opposite |
|
* |
|
* Both HW and SW threads will use this function to transfer control to the |
|
* other side. |
|
* |
|
* This is how the idle thread halts the CPU and gets halted until the HW models |
|
* raise a new interrupt; and how the HW models awake the CPU, and wait for it |
|
* to complete and go to idle. |
|
*/ |
|
void posix_change_cpu_state_and_wait(bool halted) |
|
{ |
|
if (halted) { |
|
nce_halt_cpu(nce_st); |
|
} else { |
|
nce_wake_cpu(nce_st); |
|
} |
|
} |
|
|
|
/** |
|
* HW models shall call this function to "awake the CPU" |
|
* when they are raising an interrupt |
|
*/ |
|
void posix_interrupt_raised(void) |
|
{ |
|
/* We change the CPU to running state (we awake it), and block this |
|
* thread until the CPU is halted again |
|
*/ |
|
nce_wake_cpu(nce_st); |
|
} |
|
|
|
|
|
/** |
|
* Normally called from arch_cpu_idle(): |
|
* the idle loop will call this function to set the CPU to "sleep". |
|
* Others may also call this function with care. The CPU will be set to sleep |
|
* until some interrupt awakes it. |
|
* Interrupts should be enabled before calling. |
|
*/ |
|
void posix_halt_cpu(void) |
|
{ |
|
/* |
|
* We set the CPU in the halted state (this blocks this pthread |
|
* until the CPU is awoken again by the HW models) |
|
*/ |
|
nce_halt_cpu(nce_st); |
|
|
|
/* We are awoken, normally that means some interrupt has just come |
|
* => let the "irq handler" check if/what interrupt was raised |
|
* and call the appropriate irq handler. |
|
* |
|
* Note that, the interrupt handling may trigger a arch_swap() to |
|
* another Zephyr thread. When posix_irq_handler() returns, the Zephyr |
|
* kernel has swapped back to this thread again |
|
*/ |
|
posix_irq_handler(); |
|
|
|
/* |
|
* And we go back to whatever Zephyr thread called us. |
|
*/ |
|
} |
|
|
|
|
|
/** |
|
* Implementation of arch_cpu_atomic_idle() for this SOC |
|
*/ |
|
void posix_atomic_halt_cpu(unsigned int imask) |
|
{ |
|
posix_irq_full_unlock(); |
|
posix_halt_cpu(); |
|
posix_irq_unlock(imask); |
|
} |
|
|
|
/** |
|
* The HW models will call this function to "boot" the CPU |
|
* == spawn the Zephyr init thread, which will then spawn |
|
* anything it wants, and run until the CPU is set back to idle again |
|
*/ |
|
void posix_boot_cpu(void) |
|
{ |
|
nce_st = nce_init(); |
|
posix_arch_init(); |
|
nce_boot_cpu(nce_st, &z_cstart); |
|
} |
|
|
|
/** |
|
* Clean up all memory allocated by the SOC and POSIX core |
|
* |
|
* This function can be called from both HW and SW threads |
|
*/ |
|
void posix_soc_clean_up(void) |
|
{ |
|
nce_terminate(nce_st); |
|
posix_arch_clean_up(); |
|
run_native_tasks(_NATIVE_ON_EXIT_LEVEL); |
|
}
|
|
|