| /* |
| * 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); |
| } |