native_sim: Update native simulator to latest and align with it

Align with the latest upstream native simulator
4c595794588f9d7f67fcf0fe05c3db02892a00f9
including:

* 4c59579 Makefile: Add option to build native part
* 910f934 Makefile: NSI_EXTRA_INCLUDES option and lots of commentary
* d9bf489 cmd line parsin: Minor header refactoring
* 02f3555 cmd line cleanup: Run as NSI_TASK instead of calling expl.
* 2c88173 Split exit call in two
* 2b989b4 CPU IF change: nsif_cpu0_cleanup() to return int
* e696228 HW scheduler: Add API to get next event time
* ae0e9e8 native irq ctrl: Miscellaneous fixes and improvements
* 3fd84cd NSI_TASK: Add compile check of valid priority
* 7e09fb8 HW events: Change internal storage

And two minor updates to the native_sim board,
to align with this updated version:
* nsif_cpu0_cleanup(void) now must return an int
* We need to explicitly tell the native simulator build we want
  the native components built

Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
This commit is contained in:
Alberto Escolar Piedras 2023-08-04 16:17:10 +02:00 committed by Carles Cufí
parent 451c4779c8
commit 732b03ced6
15 changed files with 179 additions and 81 deletions

View file

@ -40,6 +40,7 @@ set(nsi_config_content
"NSI_EXTRA_SRCS:=$<JOIN:$<TARGET_PROPERTY:native_simulator,INTERFACE_SOURCES>,\ >"
"NSI_LINK_OPTIONS:=$<JOIN:$<TARGET_PROPERTY:native_simulator,INTERFACE_LINK_OPTIONS>,\ >"
"NSI_PATH:=${NSI_DIR}/"
"NSI_NATIVE=1"
)
string(REPLACE ";" "\n" nsi_config_content "${nsi_config_content}")

View file

@ -25,9 +25,14 @@ void nsif_cpu0_boot(void)
run_native_tasks(_NATIVE_FIRST_SLEEP_LEVEL);
}
void nsif_cpu0_cleanup(void)
int nsif_cpu0_cleanup(void)
{
/*
* Note posix_soc_clean_up() may not return, but in that case,
* nsif_cpu0_cleanup() will be called again
*/
posix_soc_clean_up();
return 0;
}
void nsif_cpu0_irq_raised(void)

View file

@ -7,52 +7,84 @@
# By default all the build output is placed under the _build folder, but the user can override it
# setting the NSI_BUILD_PATH
#
# The caller can provide an optional configuration file and point to it with NSI_CONFIG_FILE
# See "Configurable/user overridible variables" below.
#
# By default only the core of the runner will be built, but the caller can set NSI_NATIVE
# to also build the components in native/src/
NSI_CONFIG_FILE?=nsi_config
-include ${NSI_CONFIG_FILE}
#If the file does not exist, we don't use it as a build dependency
NSI_CONFIG_FILE:=$(wildcard ${NSI_CONFIG_FILE})
# Configurable/user overridible variables:
# Path to the native_simulator (this folder):
NSI_PATH?=./
# Folder where the build output will be placed
NSI_BUILD_PATH?=$(abspath _build/)
EXE_NAME?=native_simulator.exe
# Final executable path/file_name which will be produced
NSI_EXE?=${NSI_BUILD_PATH}/${EXE_NAME}
# Path to the embedded SW which will be linked with the final executable
NSI_EMBEDDED_CPU_SW?=
# Host architecture configuration switch
NSI_ARCH?=-m32
# Coverage switch (GCOV coverage is enabled by default)
NSI_COVERAGE?=--coverage
NSI_BUILD_OPTIONS?=${NSI_ARCH} ${NSI_COVERAGE}
NSI_LINK_OPTIONS?=${NSI_ARCH} ${NSI_COVERAGE}
# Extra source files to be built in the runner context
NSI_EXTRA_SRCS?=
# Extra include directories to be used while building in the runner context
NSI_EXTRA_INCLUDES?=
# Extra libraries to be linked to the final executable
NSI_EXTRA_LIBS?=
SHELL?=bash
# Compiler
NSI_CC?=gcc
# Archive program (it is unlikely you'll need to change this)
NSI_AR?=ar
# Objcopy program (it is unlikely you'll need to change this)
NSI_OBJCOPY?=objcopy
no_default:
@echo "There is no default rule, please specify what you want to build,\
or run make help for more info"
# Build debug switch (by default enabled)
NSI_DEBUG?=-g
# Build optimization level (by default disabled to ease debugging)
NSI_OPT?=-O0
# Warnings swtiches (for the runner itself)
NSI_WARNINGS?=-Wall -Wpedantic
# Preprocessor flags
NSI_CPPFLAGS?=-D_POSIX_C_SOURCE=200809 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED
NO_PIE_CO:=-fno-pie -fno-pic
DEPENDFLAGS:=-MMD -MP
CFLAGS:=${NSI_DEBUG} ${NSI_WARNINGS} ${NSI_OPT} ${NO_PIE_CO} \
-ffunction-sections -fdata-sections ${DEPENDFLAGS} -std=c11 ${NSI_BUILD_OPTIONS}
FINALLINK_FLAGS:=${NO_PIE_CO} -no-pie ${NSI_WARNINGS} \
-Wl,--gc-sections -lm -ldl -pthread \
${NSI_LINK_OPTIONS}
-Wl,--gc-sections -ldl -pthread \
${NSI_LINK_OPTIONS} -lm
no_default:
@echo "There is no default rule, please specify what you want to build,\
or run make help for more info"
RUNNER_LIB:=runner.a
SRCS:=$(shell ls ${NSI_PATH}common/src/*.c ${NSI_PATH}native/src/*.c )
SRCS:=$(shell ls ${NSI_PATH}common/src/*.c)
ifdef NSI_NATIVE
SRCS+=$(shell ls ${NSI_PATH}native/src/*.c)
endif
INCLUDES:=-I${NSI_PATH}common/src/include/ \
-I${NSI_PATH}native/src/include/ \
-I${NSI_PATH}common/src
-I${NSI_PATH}common/src \
${NSI_EXTRA_INCLUDES}
ifdef NSI_NATIVE
INCLUDES+=-I${NSI_PATH}native/src/include/
endif
EXTRA_OBJS:=$(abspath $(addprefix $(NSI_BUILD_PATH)/,$(sort ${NSI_EXTRA_SRCS:%.c=%.o})))
OBJS:=$(abspath $(addprefix $(NSI_BUILD_PATH)/,${SRCS:${NSI_PATH}%.c=%.o})) ${EXTRA_OBJS}

View file

@ -32,16 +32,11 @@ SECTIONS
nsi_hw_events :
{
__nsi_hw_events_callbacks_start = .;
KEEP(*(SORT(.nsi_hw_event[0-9]_callback))); \
KEEP(*(SORT(.nsi_hw_event[1-9][0-9]_callback))); \
KEEP(*(SORT(.nsi_hw_event[1-9][0-9][0-9]_callback)));
__nsi_hw_events_callbacks_end = .;
__nsi_hw_events_timers_start = .;
KEEP(*(SORT(.nsi_hw_event[0-9]_timer))); \
KEEP(*(SORT(.nsi_hw_event[1-9][0-9]_timer))); \
KEEP(*(SORT(.nsi_hw_event[1-9][0-9][0-9]_timer)));
__nsi_hw_events_timers_end = .;
__nsi_hw_events_start = .;
KEEP(*(SORT(.nsi_hw_event_[0-9]))); \
KEEP(*(SORT(.nsi_hw_event_[1-9][0-9]))); \
KEEP(*(SORT(.nsi_hw_event_[1-9][0-9][0-9])));
__nsi_hw_events_end = .;
}
} INSERT AFTER .data;

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief API to the native simulator expects any integrating program has for handling
* command line argument parsing
*/
#ifndef NATIVE_SIMULATOR_COMMON_SRC_NSI_CMDLINE_MAIN_IF_H
#define NATIVE_SIMULATOR_COMMON_SRC_NSI_CMDLINE_MAIN_IF_H
#ifdef __cplusplus
extern "C" {
#endif
void nsi_handle_cmd_line(int argc, char *argv[]);
#ifdef __cplusplus
}
#endif
#endif /* NATIVE_SIMULATOR_COMMON_SRC_NSI_CMDLINE_MAIN_IF_H */

View file

@ -74,7 +74,7 @@ NATIVE_SIMULATOR_IF void nsif_cpu0_boot(void);
* The embedded SW library may provide this function.
* to do any cleanup it needs.
*/
NATIVE_SIMULATOR_IF void nsif_cpu0_cleanup(void);
NATIVE_SIMULATOR_IF int nsif_cpu0_cleanup(void);
/*
* Called by the runner each time an interrupt is raised by the HW

View file

@ -24,6 +24,7 @@ void nsi_hws_cleanup(void);
void nsi_hws_one_event(void);
void nsi_hws_set_end_of_time(uint64_t new_end_of_time);
void nsi_hws_find_next_event(void);
uint64_t nsi_hws_get_next_event_time(void);
#ifdef __cplusplus
}

View file

@ -15,26 +15,32 @@
extern "C" {
#endif
/* Internal structure used to link HW events */
struct nsi_hw_event_st {
void (*const callback)(void);
uint64_t *timer;
};
/**
* Register an event timer and event callback
*
* The HW scheduler will keep track of this event, and call its callback whenever its
* timer is reached.
* The ordering of events in the same microsecond is given by prio (lowest first),
* and if also in the same priority by alphabetical order of the callback.
* The ordering of events in the same microsecond is given by prio (lowest first).
* (Normally HW models will not care about the event ordering, and will simply set a prio like 100)
*
* Only very particular models will need to execute before or after others.
*
* Priority can be a number between 0 and 999.
*/
#define NSI_HW_EVENT(timer, fn, prio) \
static void (* const NSI_CONCAT(__nsi_hw_event_cb_, fn))(void) \
__attribute__((__used__)) \
__attribute__((__section__(".nsi_hw_event" NSI_STRINGIFY(prio) "_callback")))\
= fn; \
static uint64_t * const NSI_CONCAT(__nsi_hw_event_ti_, fn) \
__attribute__((__used__)) \
__attribute__((__section__(".nsi_hw_event" NSI_STRINGIFY(prio) "_timer")))\
= &timer
#define NSI_HW_EVENT(t, fn, prio) \
static const struct nsi_hw_event_st NSI_CONCAT(NSI_CONCAT(__nsi_hw_event_, fn), t) \
__attribute__((__used__)) \
__attribute__((__section__(".nsi_hw_event_" NSI_STRINGIFY(prio)))) \
= { \
.callback = fn, \
.timer = &t, \
}
#ifdef __cplusplus
}

View file

@ -11,10 +11,23 @@
extern "C" {
#endif
/**
* @brief Like nsi_exit(), do all cleanup required to terminate the
* execution of the native_simulator, but instead of exiting,
* return to the caller what would have been passed to exit()
*
* @param[in] exit_code: Requested exit code to the shell
* Note that other components may have requested a different
* exit code which may have precedence if it was !=0
*
* @returns Code which would have been passed to exit()
*/
int nsi_exit_inner(int exit_code);
/**
* @brief Terminate the execution of the native simulator
*
* exit_code: Requested exit code to the shell
* @param[in] exit_code: Requested exit code to the shell
* Note that other components may have requested a different
* exit code which may have precedence if it was !=0
*/

View file

@ -13,14 +13,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "nsi_cpu_if.h"
#include "nsi_tasks.h"
#include "nsi_cmdline.h"
#include "nsi_cmdline_main_if.h"
#include "nsi_utils.h"
#include "nsi_hw_scheduler.h"
void nsi_exit(int exit_code)
int nsi_exit_inner(int exit_code)
{
static int max_exit_code;
@ -30,12 +30,19 @@ void nsi_exit(int exit_code)
* but instead it would get nsi_exit() recalled again
* ASAP from the HW thread
*/
nsif_cpu0_cleanup();
int cpu_0_ret = nsif_cpu0_cleanup();
max_exit_code = NSI_MAX(cpu_0_ret, max_exit_code);
nsi_run_tasks(NSITASK_ON_EXIT_PRE_LEVEL);
nsi_hws_cleanup();
nsi_cleanup_cmd_line();
nsi_run_tasks(NSITASK_ON_EXIT_POST_LEVEL);
exit(max_exit_code);
return max_exit_code;
}
void nsi_exit(int exit_code)
{
exit(nsi_exit_inner(exit_code));
}
/**

View file

@ -19,18 +19,15 @@
#include "nsi_main.h"
#include "nsi_safe_call.h"
#include "nsi_hw_scheduler.h"
#include "nsi_hws_models_if.h"
static uint64_t simu_time; /* The actual time as known by the HW models */
static uint64_t end_of_time = NSI_NEVER; /* When will this device stop */
extern uint64_t *__nsi_hw_events_timers_start[];
extern uint64_t *__nsi_hw_events_timers_end[];
extern struct nsi_hw_event_st __nsi_hw_events_start[];
extern struct nsi_hw_event_st __nsi_hw_events_end[];
extern void (*__nsi_hw_events_callbacks_start[])(void);
extern void (*__nsi_hw_events_callbacks_end[])(void);
static unsigned int number_of_timers;
static unsigned int number_of_callbacks;
static unsigned int number_of_events;
static unsigned int next_timer_index;
static uint64_t next_timer_time;
@ -104,16 +101,21 @@ static void nsi_hws_sleep_until_next_event(void)
void nsi_hws_find_next_event(void)
{
next_timer_index = 0;
next_timer_time = *__nsi_hw_events_timers_start[0];
next_timer_time = *__nsi_hw_events_start[0].timer;
for (unsigned int i = 1; i < number_of_timers ; i++) {
if (next_timer_time > *__nsi_hw_events_timers_start[i]) {
for (unsigned int i = 1; i < number_of_events ; i++) {
if (next_timer_time > *__nsi_hw_events_start[i].timer) {
next_timer_index = i;
next_timer_time = *__nsi_hw_events_timers_start[i];
next_timer_time = *__nsi_hw_events_start[i].timer;
}
}
}
uint64_t nsi_hws_get_next_event_time(void)
{
return next_timer_time;
}
/**
* Execute the next scheduled HW event
* (advancing time until that event would trigger)
@ -122,8 +124,8 @@ void nsi_hws_one_event(void)
{
nsi_hws_sleep_until_next_event();
if (next_timer_index < number_of_timers) { /* LCOV_EXCL_BR_LINE */
__nsi_hw_events_callbacks_start[next_timer_index]();
if (next_timer_index < number_of_events) { /* LCOV_EXCL_BR_LINE */
__nsi_hw_events_start[next_timer_index].callback();
} else {
nsi_print_error_and_exit("next_timer_index corrupted\n"); /* LCOV_EXCL_LINE */
}
@ -155,16 +157,7 @@ uint64_t nsi_hws_get_time(void)
*/
void nsi_hws_init(void)
{
number_of_timers =
(__nsi_hw_events_timers_end - __nsi_hw_events_timers_start);
number_of_callbacks =
(__nsi_hw_events_callbacks_end - __nsi_hw_events_callbacks_start);
/* LCOV_EXCL_START */
if (number_of_timers != number_of_callbacks || number_of_timers == 0) {
nsi_print_error_and_exit("number_of_timers corrupted\n");
}
/* LCOV_EXCL_STOP */
number_of_events = __nsi_hw_events_end - __nsi_hw_events_start;
nsi_hws_set_sig_handler();
nsi_hws_find_next_event();

View file

@ -13,6 +13,14 @@
extern "C" {
#endif
#define NSITASK_PRE_BOOT_1_LEVEL 0
#define NSITASK_PRE_BOOT_2_LEVEL 1
#define NSITASK_HW_INIT_LEVEL 2
#define NSITASK_PRE_BOOT_3_LEVEL 3
#define NSITASK_FIRST_SLEEP_LEVEL 4
#define NSITASK_ON_EXIT_PRE_LEVEL 5
#define NSITASK_ON_EXIT_POST_LEVEL 6
/**
* NSI_TASK
*
@ -45,15 +53,10 @@ extern "C" {
static void (* const NSI_CONCAT(__nsi_task_, fn))(void) \
__attribute__((__used__)) \
__attribute__((__section__(".nsi_" #level NSI_STRINGIFY(prio) "_task")))\
= fn
#define NSITASK_PRE_BOOT_1_LEVEL 0
#define NSITASK_PRE_BOOT_2_LEVEL 1
#define NSITASK_HW_INIT_LEVEL 2
#define NSITASK_PRE_BOOT_3_LEVEL 3
#define NSITASK_FIRST_SLEEP_LEVEL 4
#define NSITASK_ON_EXIT_PRE_LEVEL 5
#define NSITASK_ON_EXIT_POST_LEVEL 6
= fn; \
/* Let's cross-check the macro level is a valid one, so we don't silently drop it */ \
_Static_assert(NSITASK_##level##_LEVEL >= 0, \
"Using a non pre-defined level, it will be dropped")
/**
* @brief Run the set of special native tasks corresponding to the given level

View file

@ -19,6 +19,7 @@
#include <stdbool.h>
#include <stddef.h>
#include "nsi_cmdline_main_if.h"
#ifdef __cplusplus
extern "C" {
@ -68,11 +69,9 @@ struct args_struct_t {
#define ARG_TABLE_ENDMARKER \
{false, false, false, NULL, NULL, 0, NULL, NULL, NULL}
void nsi_handle_cmd_line(int argc, char *argv[]);
void nsi_get_cmd_line_args(int *argc, char ***argv);
void nsi_get_test_cmd_line_args(int *argc, char ***argv);
void nsi_add_command_line_opts(struct args_struct_t *args);
void nsi_cleanup_cmd_line(void);
#ifdef __cplusplus
}

View file

@ -113,6 +113,11 @@ uint32_t hw_irq_ctrl_get_current_lock(void)
return irqs_locked;
}
/*
* Change the overall interrupt controller "interrupt lock"
* The interrupt lock is a flag that provisionally disables all interrupts
* without affecting their status or their ability to be pended in the meanwhile
*/
uint32_t hw_irq_ctrl_change_lock(uint32_t new_lock)
{
uint32_t previous_lock = irqs_locked;
@ -154,11 +159,20 @@ int hw_irq_ctrl_is_irq_enabled(unsigned int irq)
return (irq_mask & ((uint64_t)1 << irq))?1:0;
}
/**
* Get the current interrupt enable mask
*/
uint64_t hw_irq_ctrl_get_irq_mask(void)
{
return irq_mask;
}
/*
* Un-pend an interrupt from the interrupt controller.
*
* This is an API between the MCU model/IRQ handling side and the IRQ controller
* model
*/
void hw_irq_ctrl_clear_irq(unsigned int irq)
{
irq_status &= ~((uint64_t)1<<irq);
@ -177,18 +191,17 @@ void hw_irq_ctrl_clear_irq(unsigned int irq)
void hw_irq_ctrl_enable_irq(unsigned int irq)
{
irq_mask |= ((uint64_t)1<<irq);
if (irq_premask & ((uint64_t)1<<irq)) { /* if IRQ is pending */
if (irq_premask & ((uint64_t)1<<irq)) { /* if the interrupt is pending */
hw_irq_ctrl_raise_im_from_sw(irq);
}
}
static inline void hw_irq_ctrl_irq_raise_prefix(unsigned int irq)
{
if (irq < N_IRQS) {
irq_premask |= ((uint64_t)1<<irq);
if (irq_mask & (1 << irq)) {
if (irq_mask & ((uint64_t)1 << irq)) {
irq_status |= ((uint64_t)1<<irq);
}
} else if (irq == PHONY_HARD_IRQ) {
@ -197,7 +210,7 @@ static inline void hw_irq_ctrl_irq_raise_prefix(unsigned int irq)
}
/**
* Set/Raise an interrupt
* Set/Raise/Pend an interrupt
*
* This function is meant to be used by either the SW manual IRQ raising
* or by HW which wants the IRQ to be raised in one delta cycle from now
@ -233,11 +246,11 @@ static void irq_raising_from_hw_now(void)
}
/**
* Set/Raise an interrupt immediately.
* Set/Raise/Pend an interrupt immediately.
* Like hw_irq_ctrl_set_irq() but awake immediately the CPU instead of in
* 1 delta cycle
*
* Call only from HW threads
* Call only from HW threads; Should be used with care
*/
void hw_irq_ctrl_raise_im(unsigned int irq)
{
@ -248,7 +261,7 @@ void hw_irq_ctrl_raise_im(unsigned int irq)
/**
* Like hw_irq_ctrl_raise_im() but for SW threads
*
* Call only from SW threads
* Call only from SW threads; Should be used with care
*/
void hw_irq_ctrl_raise_im_from_sw(unsigned int irq)
{
@ -263,6 +276,7 @@ static void hw_irq_ctrl_timer_triggered(void)
{
irq_ctrl_timer = NSI_NEVER;
irq_raising_from_hw_now();
nsi_hws_find_next_event();
}
NSI_HW_EVENT(irq_ctrl_timer, hw_irq_ctrl_timer_triggered, 900);

View file

@ -13,6 +13,7 @@
#include "nsi_tracing.h"
#include "nsi_timer_model.h"
#include "nsi_hw_scheduler.h"
#include "nsi_tasks.h"
static int s_argc, test_argc;
static char **s_argv, **test_argv;
@ -22,7 +23,7 @@ static int used_args;
static int args_aval;
#define ARGS_ALLOC_CHUNK_SIZE 20
void nsi_cleanup_cmd_line(void)
static void nsi_cleanup_cmd_line(void)
{
if (args_struct != NULL) { /* LCOV_EXCL_BR_LINE */
free(args_struct);
@ -30,6 +31,8 @@ void nsi_cleanup_cmd_line(void)
}
}
NSI_TASK(nsi_cleanup_cmd_line, ON_EXIT_POST, 0);
/**
* Add a set of command line options to the program.
*