nrf52_bsim: Convert to use the native simulator
Convert the nrf52_bsim board, to use the native simulator as its engine. This means some of the functionality the board included before is now handled by the native simulator, including the overall program main and CPU/HW scheduling. Note that this board remains separate from the native_sim board, even if both use the native simulator. Also update the nRF HW models component to a new version which has been converted into an extension for the native simulator. After this change, it becames also possible to build the nrf52_bsim with an embedded C library, and to use with it the Zephyr POSIX API shim. Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
This commit is contained in:
parent
232b4b0a7a
commit
3a4bebacb1
27 changed files with 826 additions and 700 deletions
|
@ -1,29 +1,44 @@
|
|||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
# Copyright (c) 2018 Oticon A/S
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
find_package(BabbleSim)
|
||||
|
||||
zephyr_library()
|
||||
zephyr_library_compile_definitions(NO_POSIX_CHEATS)
|
||||
|
||||
#Due to the BLE controller assumption about enum size
|
||||
# Due to the BLE controller assumption about enum size
|
||||
zephyr_compile_options(
|
||||
-fshort-enums
|
||||
)
|
||||
# Structures layouts needs to match in the interface between the runner and the embedded SW
|
||||
# The nrfx HAL uses enums in its definitions,so they need to have the same size in both,
|
||||
# as both the HW models and embedded SW use them.
|
||||
target_compile_options(native_simulator INTERFACE -fshort-enums)
|
||||
|
||||
zephyr_library_sources(
|
||||
irq_handler.c
|
||||
cpu_wait.c
|
||||
bstests_entry.c
|
||||
argparse.c
|
||||
main.c
|
||||
time_machine.c
|
||||
trace_hook.c
|
||||
cmsis/cmsis.c
|
||||
nsi_if.c
|
||||
soc/nrfx_coredep.c
|
||||
common/bstests_entry.c
|
||||
common/cmsis/cmsis.c
|
||||
)
|
||||
|
||||
zephyr_include_directories(soc)
|
||||
zephyr_include_directories(cmsis)
|
||||
target_sources(native_simulator INTERFACE
|
||||
common/bsim_args_runner.c
|
||||
common/phy_sync_ctrl.c
|
||||
common/runner_hooks.c
|
||||
common/posix_arch_if.c
|
||||
common/trace_hook.c
|
||||
)
|
||||
|
||||
zephyr_include_directories(
|
||||
soc
|
||||
common
|
||||
common/cmsis
|
||||
${NSI_DIR}/common/src/include
|
||||
)
|
||||
|
||||
zephyr_library_include_directories(
|
||||
${BSIM_COMPONENTS_PATH}/libUtilv1/src/
|
||||
|
@ -31,14 +46,32 @@ zephyr_library_include_directories(
|
|||
${BSIM_COMPONENTS_PATH}/libRandv2/src/
|
||||
${ZEPHYR_BASE}/kernel/include
|
||||
${ZEPHYR_BASE}/arch/posix/include
|
||||
)
|
||||
|
||||
zephyr_ld_options(
|
||||
-lm
|
||||
common/
|
||||
)
|
||||
|
||||
set(libpath ${BSIM_OUT_PATH}/lib)
|
||||
zephyr_library_import(bsim_libUtilv1 ${libpath}/libUtilv1.32.a)
|
||||
zephyr_library_import(bsim_libPhyComv1 ${libpath}/libPhyComv1.32.a)
|
||||
zephyr_library_import(bsim_lib2G4PhyComv1 ${libpath}/lib2G4PhyComv1.32.a)
|
||||
zephyr_library_import(bsim_libRandv2 ${libpath}/libRandv2.32.a)
|
||||
target_link_options(native_simulator INTERFACE
|
||||
${libpath}/libUtilv1.32.a
|
||||
${libpath}/libPhyComv1.32.a
|
||||
${libpath}/lib2G4PhyComv1.32.a
|
||||
${libpath}/libRandv2.32.a
|
||||
)
|
||||
|
||||
set(zephyr_build_path ${CMAKE_BINARY_DIR}/zephyr)
|
||||
|
||||
set(nsi_config_content
|
||||
"NSI_BUILD_OPTIONS:=$<JOIN:$<TARGET_PROPERTY:native_simulator,INTERFACE_COMPILE_OPTIONS>,\ >"
|
||||
"NSI_BUILD_PATH:=${zephyr_build_path}/NSI"
|
||||
"NSI_CC:=${CMAKE_C_COMPILER}"
|
||||
"NSI_EMBEDDED_CPU_SW:=${zephyr_build_path}/${KERNEL_ELF_NAME}"
|
||||
"NSI_EXE:=${zephyr_build_path}/${KERNEL_EXE_NAME}"
|
||||
"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}/"
|
||||
)
|
||||
|
||||
string(REPLACE ";" "\n" nsi_config_content "${nsi_config_content}")
|
||||
|
||||
file(GENERATE OUTPUT "${zephyr_build_path}/NSI/nsi_config"
|
||||
CONTENT "${nsi_config_content}"
|
||||
)
|
||||
|
|
|
@ -11,7 +11,7 @@ config BOARD_NRF52_BSIM
|
|||
select CLOCK_CONTROL
|
||||
select HAS_NRFX
|
||||
select HAS_NORDIC_DRIVERS
|
||||
select NATIVE_APPLICATION
|
||||
select NATIVE_LIBRARY
|
||||
help
|
||||
Will produce a console Linux process which can be executed natively.
|
||||
It needs the BabbleSim simulator both in compile time and to execute
|
||||
|
|
|
@ -1,46 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include "soc.h"
|
||||
#include "bs_tracing.h"
|
||||
#include "bs_oswrap.h"
|
||||
#include "bs_dump_files.h"
|
||||
#include "argparse.h"
|
||||
#include "bstests.h"
|
||||
#include "NRF_hw_args.h"
|
||||
#include "bs_cmd_line.h"
|
||||
#include "bs_dynargs.h"
|
||||
#include "bs_cmd_line_typical.h"
|
||||
#include "NRF_HWLowL.h"
|
||||
#include "time_machine.h"
|
||||
#include "posix_native_task.h"
|
||||
#include "nsi_tracing.h"
|
||||
#include "nsi_main.h"
|
||||
|
||||
static bs_args_struct_t *args_struct;
|
||||
char executable_name[] = "bs_nrf52_bsim_..";
|
||||
static const char exe_name[] = "nrf52_bsim options:";
|
||||
|
||||
void component_print_post_help(void)
|
||||
{
|
||||
fprintf(stdout, "\nZephyr and a given app compiled with models of the "
|
||||
"NRF52 HW\n\n");
|
||||
}
|
||||
|
||||
static struct NRF_bsim_args_t arg;
|
||||
static char *testid;
|
||||
const char *bogus_sim_id = "bogus";
|
||||
|
||||
static void cmd_trace_lvl_found(char *argv, int offset)
|
||||
{
|
||||
bs_trace_set_level(arg.verb);
|
||||
}
|
||||
|
||||
static void cmd_gdev_nbr_found(char *argv, int offset)
|
||||
{
|
||||
bs_trace_set_prefix_dev(arg.global_device_nbr);
|
||||
}
|
||||
|
||||
static void cmd_testid_found(char *argv, int offset)
|
||||
{
|
||||
|
@ -50,252 +26,32 @@ static void cmd_testid_found(char *argv, int offset)
|
|||
static void cmd_testlist_found(char *argv, int offset)
|
||||
{
|
||||
bst_print_testslist();
|
||||
exit(0);
|
||||
nsi_exit(0);
|
||||
}
|
||||
|
||||
static bool nosim;
|
||||
static void cmd_nosim_found(char *argv, int offset)
|
||||
static void nrfbsim_register_args(void)
|
||||
{
|
||||
hwll_set_nosim(true);
|
||||
}
|
||||
|
||||
static void cmd_no_delay_init_found(char *argv, int offset)
|
||||
{
|
||||
arg.delay_init = false;
|
||||
}
|
||||
|
||||
static void cmd_no_sync_preinit_found(char *argv, int offset)
|
||||
{
|
||||
arg.sync_preinit = false;
|
||||
}
|
||||
|
||||
static void cmd_no_sync_preboot_found(char *argv, int offset)
|
||||
{
|
||||
arg.sync_preboot = false;
|
||||
}
|
||||
|
||||
static void cmd_max_resync_offset_found(char *argv, int offset)
|
||||
{
|
||||
tm_set_phy_max_resync_offset(arg.max_resync_offset);
|
||||
}
|
||||
|
||||
static void save_test_arg(struct NRF_bsim_args_t *args, char *argv)
|
||||
{
|
||||
if (args->test_case_argc >= MAXPARAMS_TESTCASES) {
|
||||
bs_trace_error_line("Too many testcase arguments (at '%s'), "
|
||||
"maximum is %i\n", argv,
|
||||
MAXPARAMS_TESTCASES);
|
||||
} else {
|
||||
bs_trace_raw(9, "cmdarg: adding '%s' to testcase args[%i]\n",
|
||||
argv, args->test_case_argc);
|
||||
args->test_case_argv[args->test_case_argc++] = argv;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_no_sim_warning(void)
|
||||
{
|
||||
bs_trace_warning("Neither simulation id or the device number "
|
||||
"have been set. I assume you want to run "
|
||||
"without a BabbleSim phy (-nosim)\n");
|
||||
bs_trace_warning("If this is not what you wanted, check with "
|
||||
"--help how to set them\n");
|
||||
bs_trace_raw(3, "setting sim_id to 'bogus', device number to 0 "
|
||||
"and nosim\n");
|
||||
}
|
||||
|
||||
void nrfbsim_register_args(void)
|
||||
{
|
||||
#define args (&arg)
|
||||
/* This define is quite ugly, but allows reusing the definitions
|
||||
* provided by the utils library
|
||||
*/
|
||||
static bs_args_struct_t args_struct_toadd[] = {
|
||||
ARG_TABLE_S_ID,
|
||||
ARG_TABLE_P_ID_2G4,
|
||||
ARG_TABLE_DEV_NBR,
|
||||
ARG_TABLE_GDEV_NBR,
|
||||
ARG_TABLE_VERB,
|
||||
ARG_TABLE_SEED,
|
||||
ARG_TABLE_COLOR,
|
||||
ARG_TABLE_NOCOLOR,
|
||||
ARG_TABLE_FORCECOLOR,
|
||||
_NRF_HW_SUB_CMD_ARG_STRUCT,
|
||||
/*
|
||||
* Fields:
|
||||
* manual, mandatory, switch,
|
||||
* option_name, var_name, type,
|
||||
* destination, callback,
|
||||
* description
|
||||
*/
|
||||
{false, false, true,
|
||||
"nosim", "", 'b',
|
||||
(void *)&nosim, cmd_nosim_found,
|
||||
"(debug feature) Do not connect to the phy"},
|
||||
{ false, false, true,
|
||||
"sync_preinit", "", 'b',
|
||||
(void *)&arg.sync_preinit, NULL,
|
||||
"Postpone pre-initialization and boot "
|
||||
"until the phy has reached time 0 (or start_offset) (by default not set)"
|
||||
{
|
||||
.option = "testid",
|
||||
.name = "testid",
|
||||
.type = 's',
|
||||
.dest = (void *)&testid,
|
||||
.call_when_found = cmd_testid_found,
|
||||
.descript = "Which of the bs tests shall be run. Run -testslist for more info"
|
||||
},
|
||||
{ false, false, true,
|
||||
"no_sync_preinit", "", 'b',
|
||||
NULL, cmd_no_sync_preinit_found,
|
||||
"Clear sync_preinit. Note that by default sync_preinit is not set"
|
||||
{
|
||||
.is_switch = true,
|
||||
.option = "testslist",
|
||||
.type = 'b',
|
||||
.call_when_found = cmd_testlist_found,
|
||||
.descript = "Print information about the available bs application tests"
|
||||
},
|
||||
{ false, false, true,
|
||||
"sync_preboot", "", 'b',
|
||||
(void *)&arg.sync_preboot, NULL,
|
||||
"Postpone CPU boot "
|
||||
"until the phy has reached time 0 (or start_offset) (by default not set)"
|
||||
"If sync_preinit is set, this option has no effect."
|
||||
},
|
||||
{ false, false, true,
|
||||
"no_sync_preboot", "", 'b',
|
||||
NULL, cmd_no_sync_preboot_found,
|
||||
"Clear sync_preboot. Note that by default sync_preboot is not set"
|
||||
},
|
||||
{ false, false, true,
|
||||
"delay_init", "", 'b',
|
||||
(void *)&arg.delay_init, NULL,
|
||||
"If start_offset is used, postpone initialization and startup "
|
||||
"until start_offset is reached (by default not set)"
|
||||
},
|
||||
{ false, false, true,
|
||||
"no_delay_init", "", 'b',
|
||||
NULL, cmd_no_delay_init_found,
|
||||
"Clear delay_init. Note that by default delay_init is not set"},
|
||||
{ false, false, false,
|
||||
"mro", "max_resync_offset", 'd',
|
||||
(void *)&arg.max_resync_offset, cmd_max_resync_offset_found,
|
||||
"Set the max Phy synchronization offset, that is, how far the device time can be "
|
||||
"from the Phy time before it resynchronizes with the Phy again "
|
||||
"(by default 1e6, 1s). Note that this value may be changed programmatically by "
|
||||
"tests"},
|
||||
BS_DUMP_FILES_ARGS,
|
||||
{false, false, false,
|
||||
"testid", "testid", 's',
|
||||
(void *)&testid, cmd_testid_found,
|
||||
"Which of the tests shall be run. Run -testslist for more info"
|
||||
},
|
||||
{false, false, true,
|
||||
"testslist", "", 'b',
|
||||
NULL, cmd_testlist_found,
|
||||
"Print information about the available FW application tests"},
|
||||
{true, false, false,
|
||||
"argstest", "arg", 'l',
|
||||
NULL, NULL,
|
||||
"The arguments that follow will be passed straight to the "
|
||||
"testcase init function"},
|
||||
{true, false, false,
|
||||
"argsmain", "arg", 'l',
|
||||
NULL, NULL,
|
||||
"The arguments that follow will be passed to main (default)"},
|
||||
ARG_TABLE_ENDMARKER
|
||||
};
|
||||
#undef args
|
||||
|
||||
bs_add_dynargs(&args_struct, args_struct_toadd);
|
||||
bs_add_extra_dynargs(args_struct_toadd);
|
||||
bs_args_override_exe_name((char *)exe_name);
|
||||
}
|
||||
|
||||
|
||||
void bs_add_extra_dynargs(bs_args_struct_t *args_struct_toadd)
|
||||
{
|
||||
bs_add_dynargs(&args_struct, args_struct_toadd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the arguments provided in the command line: set args based on it or
|
||||
* defaults, and check they are correct
|
||||
*/
|
||||
struct NRF_bsim_args_t *nrfbsim_argsparse(int argc, char *argv[])
|
||||
{
|
||||
bs_args_set_defaults(args_struct);
|
||||
arg.verb = 2;
|
||||
bs_trace_set_level(arg.verb);
|
||||
arg.test_case_argv[0] = 0;
|
||||
arg.test_case_argc = 0;
|
||||
nrf_hw_sub_cmline_set_defaults(&arg.nrf_hw);
|
||||
static const char default_phy[] = "2G4";
|
||||
|
||||
enum {Main = 0, Test = 1} parsing = Main;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (bs_is_option(argv[i], "argstest", 0)) {
|
||||
parsing = Test;
|
||||
continue;
|
||||
} else if (bs_is_option(argv[i], "argsmain", 0)) {
|
||||
parsing = Main;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parsing == Main) {
|
||||
if (!bs_args_parse_one_arg(argv[i], args_struct)) {
|
||||
bs_args_print_switches_help(args_struct);
|
||||
bs_trace_error_line("Incorrect option %s\n",
|
||||
argv[i]);
|
||||
}
|
||||
} else if (parsing == Test) {
|
||||
save_test_arg(&arg, argv[i]);
|
||||
} else {
|
||||
bs_trace_error_line("Bad error\n");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* If the user did not set the simulation id or device number
|
||||
* we assume he wanted to run with nosim (but warn him)
|
||||
*/
|
||||
if ((!nosim) && (arg.s_id == NULL) && (arg.device_nbr == UINT_MAX)) {
|
||||
print_no_sim_warning();
|
||||
nosim = true;
|
||||
hwll_set_nosim(true);
|
||||
}
|
||||
if (nosim) {
|
||||
if (arg.s_id == NULL) {
|
||||
arg.s_id = (char *)bogus_sim_id;
|
||||
}
|
||||
if (arg.device_nbr == UINT_MAX) {
|
||||
arg.device_nbr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg.device_nbr == UINT_MAX) {
|
||||
bs_args_print_switches_help(args_struct);
|
||||
bs_trace_error_line("The command line option <device number> "
|
||||
"needs to be set\n");
|
||||
}
|
||||
if (arg.global_device_nbr == UINT_MAX) {
|
||||
arg.global_device_nbr = arg.device_nbr;
|
||||
bs_trace_set_prefix_dev(arg.global_device_nbr);
|
||||
}
|
||||
if (!arg.s_id) {
|
||||
bs_args_print_switches_help(args_struct);
|
||||
bs_trace_error_line("The command line option <simulation ID> "
|
||||
"needs to be set\n");
|
||||
}
|
||||
if (!arg.p_id) {
|
||||
arg.p_id = (char *)default_phy;
|
||||
}
|
||||
|
||||
if (arg.rseed == UINT_MAX) {
|
||||
arg.rseed = 0x1000 + arg.device_nbr;
|
||||
}
|
||||
return &arg;
|
||||
}
|
||||
|
||||
void nrfbsim_cleanup_args(void)
|
||||
{
|
||||
bs_cleanup_dynargs(&args_struct);
|
||||
}
|
||||
|
||||
char *get_simid(void)
|
||||
{
|
||||
return arg.s_id;
|
||||
}
|
||||
|
||||
unsigned int get_device_nbr(void)
|
||||
{
|
||||
return arg.global_device_nbr;
|
||||
}
|
||||
|
||||
NATIVE_TASK(nrfbsim_register_args, PRE_BOOT_1, 0);
|
||||
NATIVE_TASK(nrfbsim_cleanup_args, ON_EXIT, 10);
|
||||
NATIVE_TASK(nrfbsim_register_args, PRE_BOOT_1, 100);
|
||||
|
|
|
@ -6,35 +6,8 @@
|
|||
#ifndef BSIM_NRF_ARGS_H
|
||||
#define BSIM_NRF_ARGS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "NRF_hw_args.h"
|
||||
#include "bs_cmd_line.h"
|
||||
#include "bs_cmd_line_typical.h"
|
||||
#include "bsim_args_runner.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAXPARAMS_TESTCASES 1024
|
||||
|
||||
struct NRF_bsim_args_t {
|
||||
BS_BASIC_DEVICE_OPTIONS_FIELDS
|
||||
char *test_case_argv[MAXPARAMS_TESTCASES];
|
||||
int test_case_argc;
|
||||
bool delay_init;
|
||||
bool sync_preinit;
|
||||
bool sync_preboot;
|
||||
double max_resync_offset;
|
||||
nrf_hw_sub_args_t nrf_hw;
|
||||
};
|
||||
|
||||
struct NRF_bsim_args_t *nrfbsim_argsparse(int argc, char *argv[]);
|
||||
void bs_add_extra_dynargs(bs_args_struct_t *args_struct_toadd);
|
||||
char *get_simid(void);
|
||||
unsigned int get_device_nbr(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* This header is present to avoid breaking backwards compatibility with old bsim tests */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "zephyr/types.h"
|
||||
#include "../common/irq/board_irq.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
4
boards/posix/nrf52_bsim/common/README.txt
Normal file
4
boards/posix/nrf52_bsim/common/README.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
This folder contains components that could be
|
||||
common & reused between several babblesim boards.
|
||||
As at this point there is only one bsim board
|
||||
in tree, this folder is kept inside it.
|
245
boards/posix/nrf52_bsim/common/bsim_args_runner.c
Normal file
245
boards/posix/nrf52_bsim/common/bsim_args_runner.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Common command line arguments and overall command line argument handling
|
||||
* for Zephyr Babblesim boards.
|
||||
*
|
||||
* Note that this is code runs in the native simulator runner context,
|
||||
* and not in any embedded CPU context.
|
||||
* This file should therefore only be built once for all CPUs.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include "bs_cmd_line.h"
|
||||
#include "bs_cmd_line_typical.h"
|
||||
#include "bs_dynargs.h"
|
||||
#include "bs_tracing.h"
|
||||
#include "bs_dump_files.h"
|
||||
#include "bs_rand_main.h"
|
||||
#include "nsi_tasks.h"
|
||||
#include "nsi_main.h"
|
||||
#include "NRF_HWLowL.h"
|
||||
|
||||
static bs_args_struct_t *args_struct;
|
||||
/* Direct use of this global is deprecated, use bsim_args_get_global_device_nbr() instead */
|
||||
uint global_device_nbr;
|
||||
|
||||
#define MAXPARAMS_TESTCASES 1024
|
||||
|
||||
static struct bsim_global_args_t {
|
||||
BS_BASIC_DEVICE_OPTIONS_FIELDS
|
||||
} global_args;
|
||||
|
||||
static bool nosim;
|
||||
|
||||
static void cmd_trace_lvl_found(char *argv, int offset)
|
||||
{
|
||||
bs_trace_set_level(global_args.verb);
|
||||
}
|
||||
|
||||
static void cmd_gdev_nbr_found(char *argv, int offset)
|
||||
{
|
||||
bs_trace_set_prefix_dev(global_args.global_device_nbr);
|
||||
}
|
||||
|
||||
static void print_no_sim_warning(void)
|
||||
{
|
||||
bs_trace_warning("Neither simulation id or the device number "
|
||||
"have been set. I assume you want to run "
|
||||
"without a BabbleSim phy (-nosim)\n");
|
||||
bs_trace_warning("If this is not what you wanted, check with "
|
||||
"--help how to set them\n");
|
||||
bs_trace_raw(3, "setting sim_id to 'bogus', device number to 0 "
|
||||
"and nosim\n");
|
||||
}
|
||||
|
||||
static void bsim_register_basic_args(void)
|
||||
{
|
||||
#define args (&global_args)
|
||||
/* This define allows reusing the definitions provided by the utils library */
|
||||
static bs_args_struct_t args_struct_toadd[] = {
|
||||
ARG_TABLE_S_ID,
|
||||
ARG_TABLE_P_ID_2G4,
|
||||
ARG_TABLE_DEV_NBR,
|
||||
ARG_TABLE_GDEV_NBR,
|
||||
ARG_TABLE_VERB,
|
||||
ARG_TABLE_SEED,
|
||||
ARG_TABLE_COLOR,
|
||||
ARG_TABLE_NOCOLOR,
|
||||
ARG_TABLE_FORCECOLOR,
|
||||
{
|
||||
.is_switch = true,
|
||||
.option = "nosim",
|
||||
.type = 'b',
|
||||
.dest = (void *)&nosim,
|
||||
.descript = "Do not connect to the Physical layer simulator"
|
||||
},
|
||||
BS_DUMP_FILES_ARGS,
|
||||
{
|
||||
.manual = true,
|
||||
.option = "argstest",
|
||||
.name = "arg",
|
||||
.type = 'l',
|
||||
.descript = "The arguments that follow will be passed straight to the testcase "
|
||||
"init function. (Note: If more than 1 MCU is present, argtest corresponds "
|
||||
"to argtestmcu0)"
|
||||
},
|
||||
{
|
||||
.manual = true,
|
||||
.option = "argsmain",
|
||||
.name = "arg",
|
||||
.type = 'l',
|
||||
.descript = "The arguments that follow will be passed to main (default)"
|
||||
},
|
||||
ARG_TABLE_ENDMARKER
|
||||
};
|
||||
#undef args
|
||||
|
||||
bs_add_dynargs(&args_struct, args_struct_toadd);
|
||||
}
|
||||
|
||||
NSI_TASK(bsim_register_basic_args, PRE_BOOT_1, 0);
|
||||
|
||||
static void bsim_cleanup_args(void)
|
||||
{
|
||||
bs_cleanup_dynargs(&args_struct);
|
||||
}
|
||||
|
||||
NSI_TASK(bsim_cleanup_args, ON_EXIT_POST, 0);
|
||||
|
||||
void bs_add_extra_dynargs(bs_args_struct_t *args_struct_toadd)
|
||||
{
|
||||
bs_add_dynargs(&args_struct, args_struct_toadd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the arguments provided in the command line: set args based on it or
|
||||
* defaults, and check they are correct
|
||||
*/
|
||||
void nsi_handle_cmd_line(int argc, char *argv[])
|
||||
{
|
||||
const char *bogus_sim_id = "bogus";
|
||||
|
||||
bs_args_set_defaults(args_struct);
|
||||
global_args.verb = 2;
|
||||
bs_trace_set_level(global_args.verb);
|
||||
|
||||
static const char default_phy[] = "2G4";
|
||||
|
||||
enum {Main = 0, Test = 1} parsing = Main;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (bs_is_option(argv[i], "argstest", 0)) {
|
||||
parsing = Test;
|
||||
continue;
|
||||
} else if (bs_is_option(argv[i], "argsmain", 0)) {
|
||||
parsing = Main;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parsing == Main) {
|
||||
if (!bs_args_parse_one_arg(argv[i], args_struct)) {
|
||||
bs_args_print_switches_help(args_struct);
|
||||
bs_trace_error_line("Incorrect option %s\n",
|
||||
argv[i]);
|
||||
}
|
||||
} else if (parsing == Test) {
|
||||
void nsif_cpu0_save_test_arg(char *argv);
|
||||
nsif_cpu0_save_test_arg(argv[i]);
|
||||
} else {
|
||||
bs_trace_error_line("Bad error\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user did not set the simulation id or device number
|
||||
* we assume he wanted to run with nosim (but warn him)
|
||||
*/
|
||||
if ((!nosim) && (global_args.s_id == NULL) && (global_args.device_nbr == UINT_MAX)) {
|
||||
print_no_sim_warning();
|
||||
nosim = true;
|
||||
}
|
||||
if (nosim) {
|
||||
if (global_args.s_id == NULL) {
|
||||
global_args.s_id = (char *)bogus_sim_id;
|
||||
}
|
||||
if (global_args.device_nbr == UINT_MAX) {
|
||||
global_args.device_nbr = 0;
|
||||
}
|
||||
hwll_set_nosim(true);
|
||||
}
|
||||
|
||||
if (global_args.device_nbr == UINT_MAX) {
|
||||
bs_args_print_switches_help(args_struct);
|
||||
bs_trace_error_line("The command line option <device number> "
|
||||
"needs to be set\n");
|
||||
}
|
||||
if (global_args.global_device_nbr == UINT_MAX) {
|
||||
global_args.global_device_nbr = global_args.device_nbr;
|
||||
bs_trace_set_prefix_dev(global_args.global_device_nbr);
|
||||
}
|
||||
global_device_nbr = global_args.global_device_nbr;
|
||||
if (!global_args.s_id) {
|
||||
bs_args_print_switches_help(args_struct);
|
||||
bs_trace_error_line("The command line option <simulation ID> "
|
||||
"needs to be set\n");
|
||||
}
|
||||
if (!global_args.p_id) {
|
||||
global_args.p_id = (char *)default_phy;
|
||||
}
|
||||
|
||||
if (global_args.rseed == UINT_MAX) {
|
||||
global_args.rseed = 0x1000 + global_args.device_nbr;
|
||||
}
|
||||
|
||||
bs_random_init(global_args.rseed);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the simulation id
|
||||
*/
|
||||
char *bsim_args_get_simid(void)
|
||||
{
|
||||
return global_args.s_id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get this device number in the simulation, as it is
|
||||
* known in the overall simulation.
|
||||
* In general this is the device number you want
|
||||
*/
|
||||
unsigned int bsim_args_get_global_device_nbr(void)
|
||||
{
|
||||
return global_args.global_device_nbr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get this device number in the 2G4 Phy simulation
|
||||
*/
|
||||
unsigned int bsim_args_get_2G4_device_nbr(void)
|
||||
{
|
||||
return global_args.device_nbr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get this device number in the 2G4 Phy simulation
|
||||
*/
|
||||
char *bsim_args_get_2G4_phy_id(void)
|
||||
{
|
||||
return global_args.p_id;
|
||||
}
|
||||
|
||||
char *get_simid(void)
|
||||
{
|
||||
return bsim_args_get_simid();
|
||||
}
|
||||
|
||||
unsigned int get_device_nbr(void)
|
||||
{
|
||||
return bsim_args_get_global_device_nbr();
|
||||
}
|
33
boards/posix/nrf52_bsim/common/bsim_args_runner.h
Normal file
33
boards/posix/nrf52_bsim/common/bsim_args_runner.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef BOARDS_POSIX_BSIM_COMMON_BSIM_ARGS_RUNNER_H
|
||||
#define BOARDS_POSIX_BSIM_COMMON_BSIM_ARGS_RUNNER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bs_cmd_line.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void bs_add_extra_dynargs(bs_args_struct_t *args_struct_toadd);
|
||||
|
||||
char *bsim_args_get_simid(void);
|
||||
char *bsim_args_get_2G4_phy_id(void);
|
||||
unsigned int bsim_args_get_global_device_nbr(void);
|
||||
unsigned int bsim_args_get_2G4_device_nbr(void);
|
||||
|
||||
/* Will be deprecated in favor of bsim_args_get_simid() */
|
||||
char *get_simid(void);
|
||||
/* Will be deprecated in favor of bsim_args_get_global_device_nbr() */
|
||||
unsigned int get_device_nbr(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BOARDS_POSIX_BSIM_COMMON_BSIM_ARGS_RUNNER_H */
|
|
@ -20,7 +20,7 @@
|
|||
#ifndef BOARDS_POSIX_NRF52_BSIM_CMDLINE_H
|
||||
#define BOARDS_POSIX_NRF52_BSIM_CMDLINE_H
|
||||
|
||||
#include "../native_posix/cmdline_common.h"
|
||||
#include "../../native_posix/cmdline_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
245
boards/posix/nrf52_bsim/common/phy_sync_ctrl.c
Normal file
245
boards/posix/nrf52_bsim/common/phy_sync_ctrl.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "bs_cmd_line.h"
|
||||
#include "bs_dynargs.h"
|
||||
#include "bs_utils.h"
|
||||
#include "bs_types.h"
|
||||
#include "bs_tracing.h"
|
||||
#include "nsi_tasks.h"
|
||||
#include "nsi_hws_models_if.h"
|
||||
#include "NRF_HWLowL.h"
|
||||
#include "xo_if.h"
|
||||
#include "bsim_args_runner.h"
|
||||
|
||||
/* By default every second we will inform the Phy simulator about our timing */
|
||||
#define BSIM_DEFAULT_PHY_MAX_RESYNC_OFFSET 1000000
|
||||
|
||||
static struct {
|
||||
double start_offset;
|
||||
double max_resync_offset;
|
||||
bool delay_init;
|
||||
bool sync_preinit;
|
||||
bool sync_preboot;
|
||||
} sync_args;
|
||||
|
||||
static bs_time_t phy_sync_ctrl_event_timer = TIME_NEVER;
|
||||
static bs_time_t last_resync_time;
|
||||
|
||||
static void psc_program_next_event(void)
|
||||
{
|
||||
if (sync_args.max_resync_offset != TIME_NEVER) {
|
||||
phy_sync_ctrl_event_timer = last_resync_time + sync_args.max_resync_offset;
|
||||
|
||||
bs_time_t now = nsi_hws_get_time();
|
||||
|
||||
if (phy_sync_ctrl_event_timer < now) {
|
||||
phy_sync_ctrl_event_timer = now;
|
||||
}
|
||||
} else {
|
||||
phy_sync_ctrl_event_timer = TIME_NEVER;
|
||||
}
|
||||
nsi_hws_find_next_event();
|
||||
}
|
||||
|
||||
static void phy_sync_ctrl_event_reached(void)
|
||||
{
|
||||
|
||||
last_resync_time = nsi_hws_get_time();
|
||||
|
||||
hwll_sync_time_with_phy(last_resync_time);
|
||||
psc_program_next_event();
|
||||
}
|
||||
|
||||
NSI_HW_EVENT(phy_sync_ctrl_event_timer, phy_sync_ctrl_event_reached, 900);
|
||||
|
||||
static void phy_sync_ctrl_init(void)
|
||||
{
|
||||
last_resync_time = nsi_hws_get_time();
|
||||
|
||||
psc_program_next_event();
|
||||
}
|
||||
|
||||
NSI_TASK(phy_sync_ctrl_init, HW_INIT, 100);
|
||||
|
||||
/**
|
||||
* Keep track of the last time we synchronized the time with the Phy
|
||||
*/
|
||||
void phy_sync_ctrl_set_last_phy_sync_time(bs_time_t time)
|
||||
{
|
||||
last_resync_time = time;
|
||||
psc_program_next_event();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the maximum resynchronization offset
|
||||
* (How long, in simulation time, can we spend without talking with the Phy)
|
||||
* Note that this value may be configured as a command line argument too
|
||||
*/
|
||||
void phy_sync_ctrl_set_max_resync_offset(bs_time_t max_resync_offset)
|
||||
{
|
||||
sync_args.max_resync_offset = max_resync_offset;
|
||||
|
||||
psc_program_next_event();
|
||||
}
|
||||
|
||||
/* For backwards compatibility with the old board code */
|
||||
void tm_set_phy_max_resync_offset(bs_time_t offset_in_us)
|
||||
{
|
||||
phy_sync_ctrl_set_max_resync_offset(offset_in_us);
|
||||
}
|
||||
|
||||
static double tmp_start_of;
|
||||
|
||||
static void cmd_start_of_found(char *argv, int offset)
|
||||
{
|
||||
if (tmp_start_of < 0) {
|
||||
bs_trace_error_line("start offset (%lf) cannot be smaller than 0\n", tmp_start_of);
|
||||
}
|
||||
sync_args.start_offset = tmp_start_of;
|
||||
xo_model_set_toffset(sync_args.start_offset);
|
||||
}
|
||||
|
||||
static void cmd_no_delay_init_found(char *argv, int offset)
|
||||
{
|
||||
sync_args.delay_init = false;
|
||||
}
|
||||
|
||||
static void cmd_no_sync_preinit_found(char *argv, int offset)
|
||||
{
|
||||
sync_args.sync_preinit = false;
|
||||
}
|
||||
|
||||
static void cmd_no_sync_preboot_found(char *argv, int offset)
|
||||
{
|
||||
sync_args.sync_preboot = false;
|
||||
}
|
||||
|
||||
static double tmp_max_resync_offset;
|
||||
|
||||
static void cmd_max_resync_offset_found(char *argv, int offset)
|
||||
{
|
||||
if (tmp_max_resync_offset < 500) {
|
||||
bs_trace_warning("You are attempting to set a very low phy resynchronization of %d."
|
||||
"Note this will have a performance impact\n",
|
||||
tmp_max_resync_offset);
|
||||
}
|
||||
sync_args.max_resync_offset = tmp_max_resync_offset;
|
||||
}
|
||||
|
||||
static void phy_sync_ctrl_register_args(void)
|
||||
{
|
||||
static bs_args_struct_t args_struct_toadd[] = {
|
||||
{
|
||||
.option = "start_offset",
|
||||
.name = "start_of",
|
||||
.type = 'f',
|
||||
.dest = (void *)&tmp_start_of,
|
||||
.call_when_found = cmd_start_of_found,
|
||||
.descript = "Offset in time (at the start of the simulation) of this device. "
|
||||
"At time 0 of the device, the phy will be at <start_of>"
|
||||
},
|
||||
{
|
||||
.is_switch = true,
|
||||
.option = "sync_preinit",
|
||||
.type = 'b',
|
||||
.dest = (void *)&sync_args.sync_preinit,
|
||||
.descript = "Postpone HW initialization and CPU boot until the Phy has "
|
||||
"reached time 0 (or start_offset) (by default not set)"
|
||||
},
|
||||
{
|
||||
.is_switch = true,
|
||||
.option = "no_sync_preinit",
|
||||
.type = 'b',
|
||||
.call_when_found = cmd_no_sync_preinit_found,
|
||||
.descript = "Clear sync_preinit. Note that by default sync_preinit is not set"
|
||||
},
|
||||
{
|
||||
.is_switch = true,
|
||||
.option = "sync_preboot",
|
||||
.type = 'b',
|
||||
.dest = (void *)&sync_args.sync_preboot,
|
||||
.descript = "Postpone CPU boot (but not HW initialization) until the "
|
||||
"Phy has reached time 0 (or start_offset) (by default not set)"
|
||||
"If sync_preinit is set, this option has no effect."
|
||||
},
|
||||
{
|
||||
.is_switch = true,
|
||||
.option = "no_sync_preboot",
|
||||
.type = 'b',
|
||||
.call_when_found = cmd_no_sync_preboot_found,
|
||||
.descript = "Clear sync_preboot. Note that by default sync_preboot is not set"
|
||||
},
|
||||
{
|
||||
.is_switch = true,
|
||||
.option = "delay_init",
|
||||
.type = 'b',
|
||||
.dest = (void *)&sync_args.delay_init,
|
||||
.descript = "If start_offset is used, postpone HW initialization and CPU boot "
|
||||
"until start_offset is reached (by default not set)"
|
||||
},
|
||||
{
|
||||
.is_switch = true,
|
||||
.option = "no_delay_init",
|
||||
.type = 'b',
|
||||
.call_when_found = cmd_no_delay_init_found,
|
||||
.descript = "Clear delay_init. Note that by default delay_init is not set"
|
||||
},
|
||||
{
|
||||
.option = "mro",
|
||||
.name = "max_resync_offset",
|
||||
.type = 'd',
|
||||
.dest = (void *)&tmp_max_resync_offset,
|
||||
.call_when_found = cmd_max_resync_offset_found,
|
||||
.descript = "Set the max Phy synchronization offset, that is, how far the device "
|
||||
"time can be from the Phy time before it resynchronizes with the Phy "
|
||||
"again (by default 1e6, 1s). Note that this value may be changed "
|
||||
"programmatically by tests"
|
||||
},
|
||||
ARG_TABLE_ENDMARKER
|
||||
};
|
||||
|
||||
bs_add_extra_dynargs(args_struct_toadd);
|
||||
|
||||
sync_args.max_resync_offset = BSIM_DEFAULT_PHY_MAX_RESYNC_OFFSET;
|
||||
}
|
||||
|
||||
NSI_TASK(phy_sync_ctrl_register_args, PRE_BOOT_1, 10);
|
||||
|
||||
void phy_sync_ctrl_connect_to_2G4_phy(void)
|
||||
{
|
||||
bs_trace_raw(9, "%s: Connecting to phy...\n", __func__);
|
||||
hwll_connect_to_phy(bsim_args_get_2G4_device_nbr(),
|
||||
bsim_args_get_simid(),
|
||||
bsim_args_get_2G4_phy_id());
|
||||
bs_trace_raw(9, "%s: Connected\n", __func__);
|
||||
}
|
||||
|
||||
void phy_sync_ctrl_pre_boot2(void)
|
||||
{
|
||||
if (((sync_args.start_offset > 0) && (sync_args.delay_init))
|
||||
|| sync_args.sync_preinit) {
|
||||
/* Delay the next steps until the simulation time has
|
||||
* reached either time 0 or start_offset.
|
||||
*/
|
||||
hwll_wait_for_phy_simu_time(BS_MAX(sync_args.start_offset, 0));
|
||||
sync_args.sync_preboot = false; /* Already sync'ed */
|
||||
}
|
||||
}
|
||||
|
||||
void phy_sync_ctrl_pre_boot3(void)
|
||||
{
|
||||
/*
|
||||
* If sync_preboot was set, we sync with the phy
|
||||
* right before booting the CPU
|
||||
*/
|
||||
if (sync_args.sync_preboot) {
|
||||
hwll_wait_for_phy_simu_time(BS_MAX(sync_args.start_offset, 0));
|
||||
}
|
||||
}
|
26
boards/posix/nrf52_bsim/common/phy_sync_ctrl.h
Normal file
26
boards/posix/nrf52_bsim/common/phy_sync_ctrl.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef BOARDS_POSIX_BSIM_COMMON_PHY_SYNC_CTRL_H
|
||||
#define BOARDS_POSIX_BSIM_COMMON_PHY_SYNC_CTRL_H
|
||||
|
||||
#include "bs_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
void phy_sync_ctrl_set_last_phy_sync_time(bs_time_t time);
|
||||
void phy_sync_ctrl_set_max_resync_offset(bs_time_t max_resync_offset);
|
||||
void phy_sync_ctrl_connect_to_2G4_phy(void);
|
||||
void phy_sync_ctrl_pre_boot2(void);
|
||||
void phy_sync_ctrl_pre_boot3(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BOARDS_POSIX_BSIM_COMMON_PHY_SYNC_CTRL_H */
|
12
boards/posix/nrf52_bsim/common/posix_arch_if.c
Normal file
12
boards/posix/nrf52_bsim/common/posix_arch_if.c
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "nsi_main.h"
|
||||
|
||||
void posix_exit(int exit_code)
|
||||
{
|
||||
nsi_exit(exit_code);
|
||||
}
|
48
boards/posix/nrf52_bsim/common/runner_hooks.c
Normal file
48
boards/posix/nrf52_bsim/common/runner_hooks.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Note this run in the runner context, and therefore
|
||||
* this file should therefore only be built once for all CPUs.
|
||||
*/
|
||||
|
||||
#include "bs_tracing.h"
|
||||
#include "bs_dump_files.h"
|
||||
#include "bs_pc_backchannel.h"
|
||||
#include "nsi_tasks.h"
|
||||
#include "nsi_main.h"
|
||||
#include "nsi_hw_scheduler.h"
|
||||
#include "NRF_HWLowL.h"
|
||||
#include "bsim_args_runner.h"
|
||||
|
||||
static uint8_t main_clean_up_trace_wrap(void)
|
||||
{
|
||||
return nsi_exit_inner(0);
|
||||
}
|
||||
|
||||
static void trace_registration(void)
|
||||
{
|
||||
bs_trace_register_cleanup_function(main_clean_up_trace_wrap);
|
||||
bs_trace_register_time_function(nsi_hws_get_time);
|
||||
}
|
||||
|
||||
NSI_TASK(trace_registration, PRE_BOOT_1,
|
||||
0 /*we want to run this as early as possible */);
|
||||
|
||||
static void open_dumps(void)
|
||||
{
|
||||
bs_dump_files_open(bsim_args_get_simid(),
|
||||
bsim_args_get_global_device_nbr());
|
||||
}
|
||||
|
||||
NSI_TASK(open_dumps, PRE_BOOT_2, 500);
|
||||
|
||||
static void exit_hooks(void)
|
||||
{
|
||||
hwll_terminate_simulation();
|
||||
bs_dump_files_close_all();
|
||||
bs_clean_back_channels();
|
||||
}
|
||||
|
||||
NSI_TASK(exit_hooks, ON_EXIT_PRE, 500);
|
|
@ -6,7 +6,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "bs_tracing.h"
|
||||
#include "posix_board_if.h"
|
||||
|
||||
/*
|
||||
* Provide the posix_print_* functions required from all POSIX arch boards
|
||||
|
@ -17,9 +16,8 @@
|
|||
|
||||
void posix_vprint_error_and_exit(const char *format, va_list vargs)
|
||||
{
|
||||
bs_trace_vprint(BS_TRACE_WARNING, NULL, 0, 0, BS_TRACE_AUTOTIME, 0,
|
||||
bs_trace_vprint(BS_TRACE_ERROR, NULL, 0, 0, BS_TRACE_AUTOTIME, 0,
|
||||
format, vargs);
|
||||
posix_exit(1);
|
||||
}
|
||||
|
||||
void posix_vprint_warning(const char *format, va_list vargs)
|
||||
|
@ -67,3 +65,21 @@ int posix_trace_over_tty(int file_number)
|
|||
{
|
||||
return bs_trace_is_tty(file_number);
|
||||
}
|
||||
|
||||
void nsi_vprint_error_and_exit(const char *format, va_list vargs)
|
||||
{
|
||||
bs_trace_vprint(BS_TRACE_ERROR, NULL, 0, 0, BS_TRACE_AUTOTIME, 0,
|
||||
format, vargs);
|
||||
}
|
||||
|
||||
void nsi_vprint_warning(const char *format, va_list vargs)
|
||||
{
|
||||
bs_trace_vprint(BS_TRACE_WARNING, NULL, 0, 0, BS_TRACE_AUTOTIME, 0,
|
||||
format, vargs);
|
||||
}
|
||||
|
||||
void nsi_vprint_trace(const char *format, va_list vargs)
|
||||
{
|
||||
bs_trace_vprint(BS_TRACE_RAW, NULL, 0, 2, BS_TRACE_AUTOTIME, 0,
|
||||
format, vargs);
|
||||
}
|
|
@ -1,16 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "zephyr/types.h"
|
||||
#include <stdint.h>
|
||||
#include "fake_timer.h"
|
||||
#include "time_machine.h"
|
||||
#include <zephyr/arch/posix/posix_soc_if.h>
|
||||
#include <posix_board_if.h>
|
||||
#include <posix_soc.h>
|
||||
#include "nsi_hw_scheduler.h"
|
||||
|
||||
/**
|
||||
* Replacement to the kernel k_busy_wait()
|
||||
|
@ -24,9 +25,9 @@
|
|||
*/
|
||||
void arch_busy_wait(uint32_t usec_to_wait)
|
||||
{
|
||||
bs_time_t time_end = tm_get_hw_time() + usec_to_wait;
|
||||
bs_time_t time_end = nsi_hws_get_time() + usec_to_wait;
|
||||
|
||||
while (tm_get_hw_time() < time_end) {
|
||||
while (nsi_hws_get_time() < time_end) {
|
||||
/*
|
||||
* There may be wakes due to other interrupts or nested calls to
|
||||
* k_busy_wait in interrupt handlers
|
||||
|
@ -56,10 +57,10 @@ void posix_cpu_hold(uint32_t usec_to_waste)
|
|||
* There may be wakes due to other interrupts or nested calls to
|
||||
* cpu_hold in interrupt handlers
|
||||
*/
|
||||
time_start = tm_get_hw_time();
|
||||
time_start = nsi_hws_get_time();
|
||||
fake_timer_wake_in_time(time_start + to_wait);
|
||||
posix_change_cpu_state_and_wait(true);
|
||||
to_wait -= tm_get_hw_time() - time_start;
|
||||
to_wait -= nsi_hws_get_time() - time_start;
|
||||
|
||||
posix_irq_handler();
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ This board models some of the NRF52 SOC peripherals:
|
|||
* FICR (Factory Information Configuration Registers)
|
||||
* NVMC (Non-Volatile Memory Controller)
|
||||
|
||||
The nrf52_bsim board definition uses the POSIX architecture to
|
||||
The nrf52_bsim board definition uses the POSIX architecture and the native simulator to
|
||||
run applications natively on the development system, this has the benefit of
|
||||
providing native code execution performance and easy debugging using
|
||||
native tools, but inherits :ref:`its limitations <posix_arch_limitations>`.
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "soc.h"
|
||||
#include "posix_soc.h"
|
||||
#include "NRF_HW_model_top.h"
|
||||
#include "NRF_HWLowL.h"
|
||||
#include "bs_tracing.h"
|
||||
#include "bs_types.h"
|
||||
#include "bs_utils.h"
|
||||
#include "bs_rand_main.h"
|
||||
#include "bs_pc_backchannel.h"
|
||||
#include "bs_dump_files.h"
|
||||
#include "time_machine.h"
|
||||
#include "argparse.h"
|
||||
#include "bstests.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
uint8_t inner_main_clean_up(int exit_code)
|
||||
{
|
||||
static int max_exit_code;
|
||||
|
||||
max_exit_code = BS_MAX(exit_code, max_exit_code);
|
||||
|
||||
/*
|
||||
* posix_soc_clean_up may not return if this is called from a SW thread,
|
||||
* but instead it would get posix_exit() recalled again
|
||||
* ASAP from the HW thread
|
||||
*/
|
||||
posix_soc_clean_up();
|
||||
|
||||
hwll_terminate_simulation();
|
||||
nrf_hw_models_free_all();
|
||||
bs_dump_files_close_all();
|
||||
|
||||
bs_clean_back_channels();
|
||||
|
||||
uint8_t bst_result = bst_delete();
|
||||
|
||||
return BS_MAX(bst_result, max_exit_code);
|
||||
}
|
||||
|
||||
uint8_t main_clean_up_trace_wrap(void)
|
||||
{
|
||||
return inner_main_clean_up(0);
|
||||
}
|
||||
|
||||
void posix_exit(int exit_code)
|
||||
{
|
||||
exit(inner_main_clean_up(exit_code));
|
||||
}
|
||||
|
||||
uint global_device_nbr;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/*
|
||||
* Let's ensure that even if we are redirecting to a file, we get stdout
|
||||
* and stderr line buffered (default for console)
|
||||
* Note that glibc ignores size. But just in case we set a reasonable
|
||||
* number in case somebody tries to compile against a different library
|
||||
*/
|
||||
setvbuf(stdout, NULL, _IOLBF, 512);
|
||||
setvbuf(stderr, NULL, _IOLBF, 512);
|
||||
|
||||
bs_trace_register_cleanup_function(main_clean_up_trace_wrap);
|
||||
bs_trace_register_time_function(tm_get_abs_time);
|
||||
|
||||
nrf_hw_pre_init();
|
||||
run_native_tasks(_NATIVE_PRE_BOOT_1_LEVEL);
|
||||
|
||||
struct NRF_bsim_args_t *args;
|
||||
|
||||
args = nrfbsim_argsparse(argc, argv);
|
||||
global_device_nbr = args->global_device_nbr;
|
||||
|
||||
run_native_tasks(_NATIVE_PRE_BOOT_2_LEVEL);
|
||||
|
||||
bs_trace_raw(9, "%s: Connecting to phy...\n", __func__);
|
||||
hwll_connect_to_phy(args->device_nbr, args->s_id, args->p_id);
|
||||
bs_trace_raw(9, "%s: Connected\n", __func__);
|
||||
|
||||
bs_random_init(args->rseed);
|
||||
bs_dump_files_open(args->s_id, args->global_device_nbr);
|
||||
|
||||
/* We pass to a possible testcase its command line arguments */
|
||||
bst_pass_args(args->test_case_argc, args->test_case_argv);
|
||||
|
||||
if (((args->nrf_hw.start_offset > 0) && (args->delay_init))
|
||||
|| args->sync_preinit) {
|
||||
/* Delay the next steps until the simulation time has
|
||||
* reached either time 0 or start_offset.
|
||||
*/
|
||||
hwll_wait_for_phy_simu_time(BS_MAX(args->nrf_hw.start_offset, 0));
|
||||
args->sync_preboot = false; /* Already sync'ed */
|
||||
}
|
||||
|
||||
nrf_hw_initialize(&args->nrf_hw);
|
||||
|
||||
run_native_tasks(_NATIVE_PRE_BOOT_3_LEVEL);
|
||||
|
||||
bst_pre_init();
|
||||
|
||||
if (args->sync_preboot) {
|
||||
hwll_wait_for_phy_simu_time(BS_MAX(args->nrf_hw.start_offset, 0));
|
||||
}
|
||||
|
||||
posix_boot_cpu();
|
||||
|
||||
run_native_tasks(_NATIVE_FIRST_SLEEP_LEVEL);
|
||||
|
||||
bst_post_init();
|
||||
|
||||
tm_run_forever();
|
||||
|
||||
/* This code is unreachable */
|
||||
bs_trace_exit_line("\n");
|
||||
return 0;
|
||||
}
|
101
boards/posix/nrf52_bsim/nsi_if.c
Normal file
101
boards/posix/nrf52_bsim/nsi_if.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <soc.h>
|
||||
#include <posix_native_task.h>
|
||||
#include <nsi_cpu_if.h>
|
||||
#include "bstests.h"
|
||||
#include "bs_tracing.h"
|
||||
#include "phy_sync_ctrl.h"
|
||||
|
||||
NATIVE_SIMULATOR_IF void nsif_cpu0_pre_cmdline_hooks(void)
|
||||
{
|
||||
run_native_tasks(_NATIVE_PRE_BOOT_1_LEVEL);
|
||||
}
|
||||
|
||||
#define TESTCASAE_ARGV_ALLOCSIZE 128
|
||||
|
||||
static struct {
|
||||
char **test_case_argv;
|
||||
int test_case_argc;
|
||||
int allocated_size;
|
||||
} test_args;
|
||||
|
||||
NATIVE_SIMULATOR_IF void nsif_cpu0_save_test_arg(char *argv)
|
||||
{
|
||||
if (test_args.test_case_argc >= test_args.allocated_size) {
|
||||
test_args.allocated_size += TESTCASAE_ARGV_ALLOCSIZE;
|
||||
test_args.test_case_argv = realloc(test_args.test_case_argv,
|
||||
test_args.allocated_size * sizeof(char *));
|
||||
if (test_args.test_case_argv == NULL) { /* LCOV_EXCL_BR_LINE */
|
||||
bs_trace_error_line("Can't allocate memory\n"); /* LCOV_EXCL_LINE */
|
||||
}
|
||||
}
|
||||
|
||||
bs_trace_raw(9, "cmdarg: adding '%s' to testcase args[%i]\n",
|
||||
argv, test_args.test_case_argc);
|
||||
test_args.test_case_argv[test_args.test_case_argc++] = argv;
|
||||
}
|
||||
|
||||
static void test_args_free(void)
|
||||
{
|
||||
if (test_args.test_case_argv) {
|
||||
free(test_args.test_case_argv);
|
||||
test_args.test_case_argv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
NATIVE_TASK(test_args_free, ON_EXIT_PRE, 100);
|
||||
|
||||
NATIVE_SIMULATOR_IF void nsif_cpu0_pre_hw_init_hooks(void)
|
||||
{
|
||||
run_native_tasks(_NATIVE_PRE_BOOT_2_LEVEL);
|
||||
phy_sync_ctrl_connect_to_2G4_phy();
|
||||
|
||||
/* We pass to a possible testcase its command line arguments */
|
||||
bst_pass_args(test_args.test_case_argc, test_args.test_case_argv);
|
||||
phy_sync_ctrl_pre_boot2();
|
||||
}
|
||||
|
||||
NATIVE_SIMULATOR_IF void nsif_cpu0_boot(void)
|
||||
{
|
||||
run_native_tasks(_NATIVE_PRE_BOOT_3_LEVEL);
|
||||
bst_pre_init();
|
||||
phy_sync_ctrl_pre_boot3();
|
||||
posix_boot_cpu();
|
||||
run_native_tasks(_NATIVE_FIRST_SLEEP_LEVEL);
|
||||
bst_post_init();
|
||||
}
|
||||
|
||||
NATIVE_SIMULATOR_IF 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();
|
||||
|
||||
uint8_t bst_result = bst_delete();
|
||||
return bst_result;
|
||||
}
|
||||
|
||||
NATIVE_SIMULATOR_IF void nsif_cpu0_irq_raised(void)
|
||||
{
|
||||
posix_interrupt_raised();
|
||||
}
|
||||
|
||||
NATIVE_SIMULATOR_IF void nsif_cpu0_bst_tick(uint64_t time)
|
||||
{
|
||||
bst_tick(time);
|
||||
}
|
||||
|
||||
NATIVE_SIMULATOR_IF void nsif_cpu0_irq_raised_from_sw(void)
|
||||
{
|
||||
void posix_irq_handler_im_from_sw(void);
|
||||
posix_irq_handler_im_from_sw();
|
||||
}
|
|
@ -1,233 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "NRF_HW_model_top.h"
|
||||
#include "NRF_HWLowL.h"
|
||||
#include "bs_tracing.h"
|
||||
#include "bs_types.h"
|
||||
#include "bs_utils.h"
|
||||
|
||||
/* Note: All timers are relative to hw_time and NOT to 'now' */
|
||||
extern bs_time_t timer_nrf_main_timer;
|
||||
|
||||
/* The events priorities are as in this list from top to bottom
|
||||
* Priority being which timer executes first if several trigger at the same
|
||||
* instant
|
||||
*/
|
||||
static enum {
|
||||
NRF_HW_MAIN_TIMER = 0,
|
||||
NUMBER_OF_TIMERS,
|
||||
NONE
|
||||
} next_timer_index = NONE;
|
||||
|
||||
static bs_time_t *Timer_list[NUMBER_OF_TIMERS] = {
|
||||
&timer_nrf_main_timer,
|
||||
};
|
||||
static bs_time_t next_timer_time = TIME_NEVER;
|
||||
|
||||
/*
|
||||
* Current absolute time of this device, as the device knows it.
|
||||
* It is never reset:
|
||||
*/
|
||||
static bs_time_t now;
|
||||
/* Current time the HW of this device things it is */
|
||||
static bs_time_t hw_time;
|
||||
/*
|
||||
* Offset between the current absolute time of the device and the HW time
|
||||
* That is, the absolute time when the HW_time got reset
|
||||
*/
|
||||
static bs_time_t hw_time_delta;
|
||||
|
||||
/* Last time we synchronized with the bsim PHY, in device abs time */
|
||||
static bs_time_t last_bsim_phy_sync_time;
|
||||
|
||||
#define BSIM_DEFAULT_PHY_MAX_RESYNC_OFFSET 1000000
|
||||
/* At least every second we will inform the simulator about our timing */
|
||||
static bs_time_t max_resync_offset = BSIM_DEFAULT_PHY_MAX_RESYNC_OFFSET;
|
||||
|
||||
/**
|
||||
* Set the maximum amount of time the device will spend without talking
|
||||
* (synching) with the phy.
|
||||
* This does not change the functional behavior of the Zephyr code or of the
|
||||
* radio emulation, and it is only relevant if special test code running in the
|
||||
* device interacts behind the scenes with other devices test code.
|
||||
* Setting for example a value of 5ms will ensure that this device time
|
||||
* will never be more than 5ms away from the phy. Setting it in all devices
|
||||
* to 5ms would then ensure no device time is farther apart than 5ms from any
|
||||
* other.
|
||||
*
|
||||
* Note that setting low values has a performance penalty.
|
||||
*/
|
||||
void tm_set_phy_max_resync_offset(bs_time_t offset_in_us)
|
||||
{
|
||||
max_resync_offset = offset_in_us;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute current time (no HW model except the RADIO
|
||||
* should look into this)
|
||||
*/
|
||||
bs_time_t tm_get_abs_time(void)
|
||||
{
|
||||
return now;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current HW time
|
||||
*/
|
||||
bs_time_t tm_get_hw_time(void)
|
||||
{
|
||||
return hw_time;
|
||||
}
|
||||
|
||||
bs_time_t posix_get_hw_cycle(void)
|
||||
{
|
||||
return tm_get_hw_time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the HW time
|
||||
*/
|
||||
static void tm_reset_hw_time(void)
|
||||
{
|
||||
hw_time = 0;
|
||||
hw_time_delta = now;
|
||||
if (now != 0) {
|
||||
bs_trace_error_line("Reset not supposed to happen after "
|
||||
"initialization\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current hw_time value given the absolute time
|
||||
*/
|
||||
INLINE void tm_update_HW_time(void)
|
||||
{
|
||||
hw_time = now - hw_time_delta;
|
||||
}
|
||||
|
||||
bs_time_t tm_get_hw_time_from_abs_time(bs_time_t abstime)
|
||||
{
|
||||
if (abstime == TIME_NEVER) {
|
||||
return TIME_NEVER;
|
||||
}
|
||||
return abstime - hw_time_delta;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the HW time
|
||||
*/
|
||||
void tm_reset_hw_times(void)
|
||||
{
|
||||
tm_reset_hw_time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance the internal time values of this device until time
|
||||
*/
|
||||
static void tm_sleep_until_abs_time(bs_time_t time)
|
||||
{
|
||||
if (time >= now) {
|
||||
/*
|
||||
* Ensure that at least we sync with the phy
|
||||
* every max_resync_offset
|
||||
*/
|
||||
if (time > last_bsim_phy_sync_time + max_resync_offset) {
|
||||
hwll_sync_time_with_phy(time);
|
||||
last_bsim_phy_sync_time = time;
|
||||
}
|
||||
now = time;
|
||||
} else {
|
||||
/* LCOV_EXCL_START */
|
||||
bs_trace_warning_manual_time_line(now, "next_time_time "
|
||||
"corrupted (%"PRItime"<= %"PRItime", timer idx=%i)\n",
|
||||
time, now, next_timer_index);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
tm_update_HW_time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep track of the last time we synchronized the time with the scheduler
|
||||
*/
|
||||
void tm_update_last_phy_sync_time(bs_time_t abs_time)
|
||||
{
|
||||
last_bsim_phy_sync_time = abs_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance the internal time values of this device
|
||||
* until the HW time reaches time @a t.
|
||||
*
|
||||
* @param t Time to advance to.
|
||||
*/
|
||||
static void tm_sleep_until_hw_time(bs_time_t t)
|
||||
{
|
||||
bs_time_t next_time = TIME_NEVER;
|
||||
|
||||
if (t != TIME_NEVER) {
|
||||
next_time = t + hw_time_delta;
|
||||
}
|
||||
tm_sleep_until_abs_time(next_time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look into all timers and update next_timer accordingly
|
||||
* To be called each time a "timed process" updates its timer
|
||||
*/
|
||||
void tm_find_next_timer_to_trigger(void)
|
||||
{
|
||||
next_timer_time = *Timer_list[0];
|
||||
next_timer_index = 0;
|
||||
|
||||
for (uint i = 1; i < NUMBER_OF_TIMERS ; i++) {
|
||||
if (next_timer_time > *Timer_list[i]) {
|
||||
next_timer_time = *Timer_list[i];
|
||||
next_timer_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bs_time_t tm_get_next_timer_abstime(void)
|
||||
{
|
||||
return next_timer_time + hw_time_delta;
|
||||
}
|
||||
|
||||
bs_time_t tm_hw_time_to_abs_time(bs_time_t hwtime)
|
||||
{
|
||||
if (hwtime == TIME_NEVER) {
|
||||
return TIME_NEVER;
|
||||
}
|
||||
return hwtime + hw_time_delta;
|
||||
}
|
||||
|
||||
bs_time_t tm_abs_time_to_hw_time(bs_time_t abstime)
|
||||
{
|
||||
if (abstime == TIME_NEVER) {
|
||||
return TIME_NEVER;
|
||||
}
|
||||
return abstime - hw_time_delta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run ahead: Run the HW models and advance time as needed
|
||||
* Note that this function does not return
|
||||
*/
|
||||
void tm_run_forever(void)
|
||||
{
|
||||
while (1) {
|
||||
tm_sleep_until_hw_time(next_timer_time);
|
||||
switch (next_timer_index) {
|
||||
case NRF_HW_MAIN_TIMER:
|
||||
nrf_hw_some_timer_reached();
|
||||
break;
|
||||
default:
|
||||
bs_trace_error_time_line("next_timer_index "
|
||||
"corrupted\n");
|
||||
break;
|
||||
}
|
||||
tm_find_next_timer_to_trigger();
|
||||
}
|
||||
}
|
|
@ -1,34 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _TIME_MACHINE_H
|
||||
#define _TIME_MACHINE_H
|
||||
#ifndef _BOARD_POSIX_NRF52_BSIM_TIME_MACHINE_H
|
||||
#define _BOARD_POSIX_NRF52_BSIM_TIME_MACHINE_H
|
||||
|
||||
#include "bs_types.h"
|
||||
#include "time_machine_if.h"
|
||||
#include "zephyr/toolchain.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bs_time_t tm_get_abs_time(void);
|
||||
bs_time_t tm_get_hw_time_from_abs_time(bs_time_t abstime);
|
||||
bs_time_t tm_get_hw_time(void);
|
||||
bs_time_t tm_hw_time_to_abs_time(bs_time_t hwtime);
|
||||
bs_time_t tm_abs_time_to_hw_time(bs_time_t abstime);
|
||||
|
||||
void tm_reset_hw_times(void);
|
||||
|
||||
void tm_find_next_timer_to_trigger(void);
|
||||
bs_time_t tm_get_next_timer_abstime(void);
|
||||
|
||||
void tm_update_last_phy_sync_time(bs_time_t abs_time);
|
||||
|
||||
/* This header and prototype exists for backwards compatibility with old bsim tests */
|
||||
void tm_set_phy_max_resync_offset(bs_time_t offset_in_us);
|
||||
|
||||
void tm_run_forever(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
2
west.yml
2
west.yml
|
@ -297,7 +297,7 @@ manifest:
|
|||
groups:
|
||||
- tools
|
||||
- name: nrf_hw_models
|
||||
revision: aa8d6f67f5fc95f576ef9ea4c4ef438320f88eb2
|
||||
revision: 5993de6656e9c9238e975393c402d2f70339a1b3
|
||||
path: modules/bsim_hw_models/nrf_hw_models
|
||||
- name: open-amp
|
||||
revision: 42b7c577714b8f22ce82a901e19c1814af4609a8
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue