zephyr/boards/posix/native_posix/hw_models_top.c

212 lines
4.4 KiB
C
Raw Normal View History

/*
* Copyright (c) 2017 Oticon A/S
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* Reduced set of HW models sufficient to run some of the sample apps
* and regression tests
*/
#include <stdint.h>
#include <signal.h>
#include <stddef.h>
#include <stdlib.h>
#include <pthread.h>
#include "hw_models_top.h"
#include "timer_model.h"
#include "irq_ctrl.h"
#include "posix_board_if.h"
headers: Refactor kernel and arch headers. This commit refactors kernel and arch headers to establish a boundary between private and public interface headers. The refactoring strategy used in this commit is detailed in the issue This commit introduces the following major changes: 1. Establish a clear boundary between private and public headers by removing "kernel/include" and "arch/*/include" from the global include paths. Ideally, only kernel/ and arch/*/ source files should reference the headers in these directories. If these headers must be used by a component, these include paths shall be manually added to the CMakeLists.txt file of the component. This is intended to discourage applications from including private kernel and arch headers either knowingly and unknowingly. - kernel/include/ (PRIVATE) This directory contains the private headers that provide private kernel definitions which should not be visible outside the kernel and arch source code. All public kernel definitions must be added to an appropriate header located under include/. - arch/*/include/ (PRIVATE) This directory contains the private headers that provide private architecture-specific definitions which should not be visible outside the arch and kernel source code. All public architecture- specific definitions must be added to an appropriate header located under include/arch/*/. - include/ AND include/sys/ (PUBLIC) This directory contains the public headers that provide public kernel definitions which can be referenced by both kernel and application code. - include/arch/*/ (PUBLIC) This directory contains the public headers that provide public architecture-specific definitions which can be referenced by both kernel and application code. 2. Split arch_interface.h into "kernel-to-arch interface" and "public arch interface" divisions. - kernel/include/kernel_arch_interface.h * provides private "kernel-to-arch interface" definition. * includes arch/*/include/kernel_arch_func.h to ensure that the interface function implementations are always available. * includes sys/arch_interface.h so that public arch interface definitions are automatically included when including this file. - arch/*/include/kernel_arch_func.h * provides architecture-specific "kernel-to-arch interface" implementation. * only the functions that will be used in kernel and arch source files are defined here. - include/sys/arch_interface.h * provides "public arch interface" definition. * includes include/arch/arch_inlines.h to ensure that the architecture-specific public inline interface function implementations are always available. - include/arch/arch_inlines.h * includes architecture-specific arch_inlines.h in include/arch/*/arch_inline.h. - include/arch/*/arch_inline.h * provides architecture-specific "public arch interface" inline function implementation. * supersedes include/sys/arch_inline.h. 3. Refactor kernel and the existing architecture implementations. - Remove circular dependency of kernel and arch headers. The following general rules should be observed: * Never include any private headers from public headers * Never include kernel_internal.h in kernel_arch_data.h * Always include kernel_arch_data.h from kernel_arch_func.h * Never include kernel.h from kernel_struct.h either directly or indirectly. Only add the kernel structures that must be referenced from public arch headers in this file. - Relocate syscall_handler.h to include/ so it can be used in the public code. This is necessary because many user-mode public codes reference the functions defined in this header. - Relocate kernel_arch_thread.h to include/arch/*/thread.h. This is necessary to provide architecture-specific thread definition for 'struct k_thread' in kernel.h. - Remove any private header dependencies from public headers using the following methods: * If dependency is not required, simply omit * If dependency is required, - Relocate a portion of the required dependencies from the private header to an appropriate public header OR - Relocate the required private header to make it public. This commit supersedes #20047, addresses #19666, and fixes #3056. Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
2019-10-25 00:08:21 +09:00
#include <arch/posix/posix_soc_if.h>
#include "posix_arch_internal.h"
#include "sdl_events.h"
#include <sys/util.h>
static uint64_t simu_time; /* The actual time as known by the HW models */
static uint64_t end_of_time = NEVER; /* When will this device stop */
/* List of HW model timers: */
extern uint64_t hw_timer_timer; /* When should this timer_model be called */
extern uint64_t irq_ctrl_timer;
#ifdef CONFIG_HAS_SDL
extern uint64_t sdl_event_timer;
#endif
static enum {
HWTIMER = 0,
IRQCNT,
#ifdef CONFIG_HAS_SDL
SDLEVENTTIMER,
#endif
NUMBER_OF_TIMERS,
NONE
} next_timer_index = NONE;
static uint64_t *Timer_list[NUMBER_OF_TIMERS] = {
&hw_timer_timer,
&irq_ctrl_timer,
#ifdef CONFIG_HAS_SDL
&sdl_event_timer,
#endif
};
static uint64_t next_timer_time;
/* Have we received a SIGTERM or SIGINT */
static volatile sig_atomic_t signaled_end;
/**
* Handler for SIGTERM and SIGINT
*/
void hwm_signal_end_handler(int sig)
{
signaled_end = 1;
}
/**
* Set the handler for SIGTERM and SIGINT which will cause the
* program to exit gracefully when they are received the 1st time
*
* Note that our handler only sets a variable indicating the signal was
* received, and in each iteration of the hw main loop this variable is
* evaluated.
* If for some reason (the program is stuck) we never evaluate it, the program
* would never exit.
* Therefore we set SA_RESETHAND: This way, the 2nd time the signal is received
* the default handler would be called to terminate the program no matter what.
*
* Note that SA_RESETHAND requires either _POSIX_C_SOURCE>=200809 or
* _XOPEN_SOURCE>=500
*/
void hwm_set_sig_handler(void)
{
struct sigaction act;
act.sa_handler = hwm_signal_end_handler;
PC_SAFE_CALL(sigemptyset(&act.sa_mask));
act.sa_flags = SA_RESETHAND;
PC_SAFE_CALL(sigaction(SIGTERM, &act, NULL));
PC_SAFE_CALL(sigaction(SIGINT, &act, NULL));
}
static void hwm_sleep_until_next_timer(void)
{
if (next_timer_time >= simu_time) { /* LCOV_EXCL_BR_LINE */
simu_time = next_timer_time;
} else {
/* LCOV_EXCL_START */
posix_print_warning("next_timer_time corrupted (%"PRIu64"<= %"
PRIu64", timer idx=%i)\n",
(uint64_t)next_timer_time,
(uint64_t)simu_time,
next_timer_index);
/* LCOV_EXCL_STOP */
}
if (signaled_end || (simu_time > end_of_time)) {
posix_print_trace("\nStopped at %.3Lfs\n",
((long double)simu_time)/1.0e6);
posix_exit(0);
}
}
/**
* Find in between all timers which is the next one
* and update next_timer_* accordingly
*/
void hwm_find_next_timer(void)
{
next_timer_index = 0;
next_timer_time = *Timer_list[0];
for (unsigned int i = 1; i < NUMBER_OF_TIMERS ; i++) {
if (next_timer_time > *Timer_list[i]) {
next_timer_index = i;
next_timer_time = *Timer_list[i];
}
}
}
/**
* Entry point for the HW models
* The HW models execute in an infinite loop until terminated
*/
void hwm_main_loop(void)
{
while (1) {
hwm_sleep_until_next_timer();
switch (next_timer_index) { /* LCOV_EXCL_BR_LINE */
case HWTIMER:
hwtimer_timer_reached();
break;
case IRQCNT:
hw_irq_ctrl_timer_triggered();
break;
#ifdef CONFIG_HAS_SDL
case SDLEVENTTIMER:
sdl_handle_events();
break;
#endif
default:
/* LCOV_EXCL_START */
posix_print_error_and_exit(
"next_timer_index corrupted\n");
break;
/* LCOV_EXCL_STOP */
}
hwm_find_next_timer();
}
}
/**
* Set the simulated time when the process will stop
*/
void hwm_set_end_of_time(uint64_t new_end_of_time)
{
end_of_time = new_end_of_time;
}
/**
* Return the current time as known by the device
*/
uint64_t hwm_get_time(void)
{
return simu_time;
}
uint64_t posix_get_hw_cycle(void)
{
return hwm_get_time();
}
/**
* Function to initialize the HW models
*/
void hwm_init(void)
{
hwm_set_sig_handler();
hwtimer_init();
hw_irq_ctrl_init();
hwm_find_next_timer();
}
/**
* Function to free any resources allocated by the HW models
* Note that this function needs to be designed so it is possible
* to call it more than once during cleanup
*/
void hwm_cleanup(void)
{
hwtimer_cleanup();
hw_irq_ctrl_cleanup();
}