new simulated board: nrf52_bsim
Added a new simulated board, which models the NRF52832 SOC. Its main use is for workstation testing and simulation of the BLE stack and any application which relies mostly on it. It uses BabbleSim (http://Babblesim.github.io) for the radio simulation. And the NRF52 HW models hosted in that same GitHub organization: https://github.com/BabbleSim/ext_NRF52_hw_models For speed it uses the POSIX arch to (not) emulate the CPU. It uses Vanilla Zephyr, with a couple of configuration differences: * It uses (like other POSIX arch boards) the system libC * It does not use the nrfx hosted by Zehpyr in ext/, but the one provided by the HW models. Otherwise it relies in the same drivers as the real NRF52 boards. Signed-off-by: Alberto Escolar Piedras <alpi@oticon.com>
This commit is contained in:
parent
5f39dbb1b0
commit
ceaa46d07b
26 changed files with 2353 additions and 1 deletions
|
@ -1,6 +1,6 @@
|
|||
.. _boards_posix:
|
||||
|
||||
Native POSIX Boards
|
||||
POSIX/NATIVE Boards
|
||||
###################
|
||||
|
||||
.. toctree::
|
||||
|
|
|
@ -38,6 +38,8 @@ It has only been tested on Linux, but should also be compatible with macOS.
|
|||
This port will **not** work in Windows Subsystem for Linux (WSL) because WSL
|
||||
does not support native 32-bit binaries.
|
||||
|
||||
.. _native_important_limitations:
|
||||
|
||||
Important limitations
|
||||
*********************
|
||||
|
||||
|
|
71
boards/posix/nrf52_bsim/CMakeLists.txt
Normal file
71
boards/posix/nrf52_bsim/CMakeLists.txt
Normal file
|
@ -0,0 +1,71 @@
|
|||
if (NOT DEFINED ENV{BSIM_COMPONENTS_PATH})
|
||||
message(FATAL_ERROR "This board requires the BabbleSim simulator. Please set\
|
||||
the enviroment variable BSIM_COMPONENTS_PATH to point to its components \
|
||||
folder. More information can be found in\
|
||||
https://babblesim.github.io/folder_structure_and_env.html")
|
||||
endif()
|
||||
if (NOT DEFINED ENV{BSIM_OUT_PATH})
|
||||
message(FATAL_ERROR "This board requires the BabbleSim simulator. Please set\
|
||||
the enviroment variable BSIM_OUT_PATH to point to the folder where the\
|
||||
simulator is compiled to. More information can be found in\
|
||||
https://babblesim.github.io/folder_structure_and_env.html")
|
||||
endif()
|
||||
|
||||
zephyr_library()
|
||||
zephyr_library_compile_definitions(NO_POSIX_CHEATS)
|
||||
|
||||
zephyr_include_directories(
|
||||
fake
|
||||
$ENV{BSIM_COMPONENTS_PATH}/ext_NRF52_hw_models/src/nrfx_hal/
|
||||
$ENV{BSIM_COMPONENTS_PATH}/ext_NRF52_hw_models/src/HW_models/
|
||||
)
|
||||
|
||||
#Due to the BLE controller assumption about enum size
|
||||
zephyr_compile_options(
|
||||
-fshort-enums
|
||||
)
|
||||
|
||||
zephyr_library_sources(
|
||||
irq_handler.c
|
||||
k_busy_wait.c
|
||||
bstests_entry.c
|
||||
argparse.c
|
||||
main.c
|
||||
time_machine.c
|
||||
trace_hook.c
|
||||
)
|
||||
|
||||
zephyr_library_include_directories(
|
||||
fake
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
|
||||
$ENV{BSIM_COMPONENTS_PATH}/ext_NRF52_hw_models/src/HW_models/
|
||||
$ENV{BSIM_COMPONENTS_PATH}/ext_NRF52_hw_models/src/nrfx_hal/
|
||||
$ENV{BSIM_COMPONENTS_PATH}/libRandv2/src/
|
||||
)
|
||||
|
||||
zephyr_ld_options(
|
||||
-lm
|
||||
)
|
||||
|
||||
add_library(bsim_libUtilv1 STATIC IMPORTED GLOBAL)
|
||||
add_library(bsim_libPhyComv1 STATIC IMPORTED GLOBAL)
|
||||
add_library(bsim_lib2G4PhyComv1 STATIC IMPORTED GLOBAL)
|
||||
add_library(bsim_libRandv2 STATIC IMPORTED GLOBAL)
|
||||
add_library(bsim_libNRF52_hw STATIC IMPORTED GLOBAL)
|
||||
set_target_properties(bsim_libUtilv1 PROPERTIES IMPORTED_LOCATION $ENV{BSIM_OUT_PATH}/lib/libUtilv1.32.a)
|
||||
set_target_properties(bsim_libPhyComv1 PROPERTIES IMPORTED_LOCATION $ENV{BSIM_OUT_PATH}/lib/libPhyComv1.32.a)
|
||||
set_target_properties(bsim_lib2G4PhyComv1 PROPERTIES IMPORTED_LOCATION $ENV{BSIM_OUT_PATH}/lib/lib2G4PhyComv1.32.a)
|
||||
set_target_properties(bsim_libRandv2 PROPERTIES IMPORTED_LOCATION $ENV{BSIM_OUT_PATH}/lib/libRandv2.32.a)
|
||||
set_target_properties(bsim_libNRF52_hw PROPERTIES IMPORTED_LOCATION $ENV{BSIM_OUT_PATH}/lib/libNRF52_hw_models.32.a)
|
||||
zephyr_append_cmake_library(bsim_libUtilv1)
|
||||
zephyr_append_cmake_library(bsim_libPhyComv1)
|
||||
zephyr_append_cmake_library(bsim_lib2G4PhyComv1)
|
||||
zephyr_append_cmake_library(bsim_libRandv2)
|
||||
zephyr_append_cmake_library(bsim_libNRF52_hw)
|
||||
|
||||
# This is due to some tests using _Static_assert which is a 2011 feature, but
|
||||
# otherwise relying on compilers supporting it also when set to C99.
|
||||
# This was in general ok, but with some host compilers and C library versions
|
||||
# it led to problems. So we override it to 2011 for native applications.
|
||||
set_property(GLOBAL PROPERTY CSTD c11)
|
30
boards/posix/nrf52_bsim/Kconfig
Normal file
30
boards/posix/nrf52_bsim/Kconfig
Normal file
|
@ -0,0 +1,30 @@
|
|||
|
||||
if BOARD_NRF52_BSIM
|
||||
|
||||
comment "NRF52_BSIM options"
|
||||
|
||||
config PRINTK_HOOK_INIT_PRIORITY
|
||||
int
|
||||
depends on BOARD_NRF52_BSIM
|
||||
default 50
|
||||
help
|
||||
Just the driver init priority
|
||||
|
||||
endif # BOARD_NRF52_BSIM
|
||||
|
||||
|
||||
# This would eventually be shared by a possible family of simulated NRF boards
|
||||
# which use BabbleSim. When that happens, we can move this to a common
|
||||
# Kconfig file
|
||||
|
||||
config SOC_SERIES_BSIM_NRFXX
|
||||
bool
|
||||
depends on SOC_POSIX
|
||||
help
|
||||
Any NRF simulated SOC with BabbleSim, based on the POSIX arch
|
||||
|
||||
config SOC_SERIES_BSIM_NRF52X
|
||||
bool
|
||||
depends on SOC_SERIES_BSIM_NRFXX
|
||||
help
|
||||
Any NRF52 simulated SOC with BabbleSim, based on the POSIX arch
|
15
boards/posix/nrf52_bsim/Kconfig.board
Normal file
15
boards/posix/nrf52_bsim/Kconfig.board
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
config BOARD_NRF52_BSIM
|
||||
bool "NRF52 simulation model"
|
||||
select SOC_SERIES_BSIM_NRFXX
|
||||
select SOC_SERIES_BSIM_NRF52X
|
||||
select SOC_COMPATIBLE_NRF
|
||||
select SOC_COMPATIBLE_NRF52X
|
||||
select SOC_COMPATIBLE_NRF52832
|
||||
select CONSOLE_HAS_DRIVER
|
||||
select NRF_RTC_TIMER
|
||||
select CLOCK_CONTROL
|
||||
select CLOCK_CONTROL_NRF5
|
||||
help
|
||||
Will produce a console Linux process which can be executed natively.
|
||||
It needs the BabbleSim simulator both in compile time and to execute
|
42
boards/posix/nrf52_bsim/Kconfig.defconfig
Normal file
42
boards/posix/nrf52_bsim/Kconfig.defconfig
Normal file
|
@ -0,0 +1,42 @@
|
|||
|
||||
if BOARD_NRF52_BSIM
|
||||
|
||||
config BUILD_OUTPUT_BIN
|
||||
default n
|
||||
|
||||
config BUILD_OUTPUT_EXE
|
||||
default y
|
||||
|
||||
config OUTPUT_PRINT_MEMORY_USAGE
|
||||
default n
|
||||
|
||||
config BOARD
|
||||
default "nrf52_bsim"
|
||||
|
||||
if BT
|
||||
|
||||
config BT_CTLR
|
||||
def_bool y
|
||||
|
||||
endif # BT
|
||||
|
||||
if LOG
|
||||
|
||||
# This board can reuse the native_posix logging backend
|
||||
config LOG_BACKEND_NATIVE_POSIX
|
||||
def_bool y if !SERIAL
|
||||
|
||||
# For native_posix we can log immediately without any problem
|
||||
# Doing so will be nicer for debugging
|
||||
config LOG_INPLACE_PROCESS
|
||||
def_bool y
|
||||
|
||||
# If we set LOG_INPLACE_PROCESS, there is no need to have the logging thread
|
||||
# running
|
||||
config LOG_PROCESS_THREAD
|
||||
def_bool n
|
||||
|
||||
endif # LOG
|
||||
|
||||
endif # BOARD_NRF52_BSIM
|
||||
|
181
boards/posix/nrf52_bsim/argparse.c
Normal file
181
boards/posix/nrf52_bsim/argparse.c
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.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_typical.h"
|
||||
#include "NRF_HWLowL.h"
|
||||
|
||||
char executable_name[] = "bs_nrf52_bsim_..";
|
||||
|
||||
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 *args_g;
|
||||
static char *testid;
|
||||
const char *bogus_sim_id = "bogus";
|
||||
|
||||
static void cmd_trace_lvl_found(char *argv, int offset)
|
||||
{
|
||||
bs_trace_set_level(args_g->verb);
|
||||
}
|
||||
|
||||
static void cmd_gdev_nbr_found(char *argv, int offset)
|
||||
{
|
||||
bs_trace_set_prefix_dev(args_g->global_device_nbr);
|
||||
}
|
||||
|
||||
static void cmd_testid_found(char *argv, int offset)
|
||||
{
|
||||
bst_set_testapp_mode(testid);
|
||||
}
|
||||
|
||||
static void cmd_testlist_found(char *argv, int offset)
|
||||
{
|
||||
bst_print_testslist();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void cmd_nosim_found(char *argv, int offset)
|
||||
{
|
||||
hwll_set_nosim(true);
|
||||
}
|
||||
|
||||
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 wand to run "
|
||||
"with 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");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the arguments provided in the command line: set args based on it or
|
||||
* defaults, and check they are correct
|
||||
*/
|
||||
void nrfbsim_argsparse(int argc, char *argv[], struct NRF_bsim_args_t *args)
|
||||
{
|
||||
bool nosim;
|
||||
|
||||
args_g = args;
|
||||
bs_args_struct_t args_struct[] = {
|
||||
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"},
|
||||
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
|
||||
};
|
||||
|
||||
bs_args_set_defaults(args_struct);
|
||||
args->verb = 2;
|
||||
bs_trace_set_level(args->verb);
|
||||
args->test_case_argv[0] = 0;
|
||||
args->test_case_argc = 0;
|
||||
nrf_hw_sub_cmline_set_defaults(&args->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(args, argv[i]);
|
||||
} else {
|
||||
bs_trace_error_line("Bad error\n");
|
||||
}
|
||||
}
|
||||
|
||||
if ((args->s_id == NULL) && (args->device_nbr == UINT_MAX)) {
|
||||
if (!nosim) {
|
||||
print_no_sim_warning();
|
||||
}
|
||||
|
||||
args->s_id = (char *)bogus_sim_id;
|
||||
args->device_nbr = 0;
|
||||
hwll_set_nosim(true);
|
||||
}
|
||||
|
||||
bs_args_typical_dev_post_check((bs_basic_dev_args_t *)args, args_struct,
|
||||
(char *)default_phy);
|
||||
|
||||
if (args->rseed == UINT_MAX) {
|
||||
args->rseed = 0x1000 + args->device_nbr;
|
||||
}
|
||||
}
|
32
boards/posix/nrf52_bsim/argparse.h
Normal file
32
boards/posix/nrf52_bsim/argparse.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef BSIM_NRF_ARGS_H
|
||||
#define BSIM_NRF_ARGS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "NRF_hw_args.h"
|
||||
#include "bs_cmd_line_typical.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;
|
||||
nrf_hw_sub_args_t nrf_hw;
|
||||
};
|
||||
|
||||
void nrfbsim_argsparse(int argc, char *argv[], struct NRF_bsim_args_t *args);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
1
boards/posix/nrf52_bsim/board.cmake
Normal file
1
boards/posix/nrf52_bsim/board.cmake
Normal file
|
@ -0,0 +1 @@
|
|||
set(EMU_PLATFORM native)
|
12
boards/posix/nrf52_bsim/board.h
Normal file
12
boards/posix/nrf52_bsim/board.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __INC_BOARD_H
|
||||
#define __INC_BOARD_H
|
||||
|
||||
#include <soc.h>
|
||||
|
||||
#endif /* __INC_BOARD_H */
|
89
boards/posix/nrf52_bsim/board_irq.h
Normal file
89
boards/posix/nrf52_bsim/board_irq.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014 Wind River Systems, Inc.
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _BOARD_IRQ_H
|
||||
#define _BOARD_IRQ_H
|
||||
|
||||
#include "sw_isr_table.h"
|
||||
#include "zephyr/types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void _isr_declare(unsigned int irq_p, int flags, void isr_p(void *),
|
||||
void *isr_param_p);
|
||||
void _irq_priority_set(unsigned int irq, unsigned int prio, u32_t flags);
|
||||
|
||||
/**
|
||||
* Configure a static interrupt.
|
||||
*
|
||||
* @param irq_p IRQ line number
|
||||
* @param priority_p Interrupt priority
|
||||
* @param isr_p Interrupt service routine
|
||||
* @param isr_param_p ISR parameter
|
||||
* @param flags_p IRQ options
|
||||
*
|
||||
* @return The vector assigned to this interrupt
|
||||
*/
|
||||
#define _ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \
|
||||
({ \
|
||||
_isr_declare(irq_p, 0, isr_p, isr_param_p); \
|
||||
_irq_priority_set(irq_p, priority_p, flags_p); \
|
||||
irq_p; \
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* Configure a 'direct' static interrupt.
|
||||
*
|
||||
* See include/irq.h for details.
|
||||
*/
|
||||
#define _ARCH_IRQ_DIRECT_CONNECT(irq_p, priority_p, isr_p, flags_p) \
|
||||
({ \
|
||||
_isr_declare(irq_p, ISR_FLAG_DIRECT, (void (*)(void *))isr_p, NULL); \
|
||||
_irq_priority_set(irq_p, priority_p, flags_p); \
|
||||
irq_p; \
|
||||
})
|
||||
|
||||
/**
|
||||
* POSIX Architecture (board) specific ISR_DIRECT_DECLARE(),
|
||||
* See include/irq.h for more information.
|
||||
*
|
||||
* The return of "name##_body(void)" is the indication of the interrupt
|
||||
* (maybe) having caused a kernel decision to context switch
|
||||
*
|
||||
* Note that this convention is changed relative to the ARM and x86 archs
|
||||
*
|
||||
* All pre/post irq work of the interrupt is handled in the board
|
||||
* posix_irq_handler() both for direct and normal interrupts together
|
||||
*/
|
||||
#define _ARCH_ISR_DIRECT_DECLARE(name) \
|
||||
static inline int name##_body(void); \
|
||||
int name(void) \
|
||||
{ \
|
||||
int check_reschedule; \
|
||||
check_reschedule = name##_body(); \
|
||||
return check_reschedule; \
|
||||
} \
|
||||
static inline int name##_body(void)
|
||||
|
||||
#define _ARCH_ISR_DIRECT_HEADER() do { } while (0)
|
||||
#define _ARCH_ISR_DIRECT_FOOTER(a) do { } while (0)
|
||||
|
||||
#ifdef CONFIG_SYS_POWER_MANAGEMENT
|
||||
extern void posix_irq_check_idle_exit(void);
|
||||
#define _ARCH_ISR_DIRECT_PM() posix_irq_check_idle_exit()
|
||||
#else
|
||||
#define _ARCH_ISR_DIRECT_PM() do { } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _BOARD_IRQ_H */
|
44
boards/posix/nrf52_bsim/board_soc.h
Normal file
44
boards/posix/nrf52_bsim/board_soc.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/**
|
||||
* @file Extra definitions provided by the board to soc.h
|
||||
*
|
||||
* Background:
|
||||
* The POSIC ARCH/SOC/board layering is different than in normal archs
|
||||
* The "SOC" does not provide almost any of the typical SOC functionality
|
||||
* but that is left for the "board" to define it
|
||||
* Device code may rely on the soc.h defining some things (like the interrupts
|
||||
* numbers)
|
||||
* Therefore this file is included from the inf_clock soc.h to allow a board
|
||||
* to define that kind of SOC related snippets
|
||||
*/
|
||||
|
||||
#ifndef _POSIX_NRF52_BOARD_SOC_H
|
||||
#define _POSIX_NRF52_BOARD_SOC_H
|
||||
|
||||
#include <toolchain.h>
|
||||
#include <misc/util.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <zephyr/types.h>
|
||||
#include <stddef.h>
|
||||
#include "irq.h"
|
||||
#include "irq_sources.h"
|
||||
#include "NRF_regs.h"
|
||||
#include "nrf_soc_if.h"
|
||||
|
||||
#define OFFLOAD_SW_IRQ SWI0_EGU0_IRQn
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _POSIX_NRF52_BOARD_SOC_H */
|
121
boards/posix/nrf52_bsim/bstests.h
Normal file
121
boards/posix/nrf52_bsim/bstests.h
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _BSTESTS_ENTRY_H
|
||||
#define _BSTESTS_ENTRY_H
|
||||
|
||||
#include "bs_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TEST HOOKS:
|
||||
*
|
||||
* You may register some of these functions in your testbench
|
||||
*
|
||||
* Note that you can overwrite this function pointers on the fly
|
||||
*/
|
||||
/*
|
||||
* Will be called with the command line arguments for the testcase.
|
||||
* This is BEFORE any SW has run, and before the HW has been initialized
|
||||
*/
|
||||
typedef void (*bst_test_args_t)(int, char**);
|
||||
/* It will be called (in the HW models thread) before the CPU is booted */
|
||||
typedef void (*bst_test_pre_init_t)(void);
|
||||
/*
|
||||
* It will be called (in the HW models thread) when the CPU goes to sleep
|
||||
* for the first time
|
||||
*/
|
||||
typedef void (*bst_test_post_init_t)(void);
|
||||
/* It will be called (in the HW models thread) each time the bst_timer ticks */
|
||||
typedef void (*bst_test_tick_t)(bs_time_t time);
|
||||
/*
|
||||
* It will be called (in the HW models thread) when the execution is being
|
||||
* terminated (clean up memory and close your files here)
|
||||
*/
|
||||
typedef void (*bst_test_delete_t)(void);
|
||||
/*
|
||||
* It will be called (in SW context) when a HW interrupt is raised.
|
||||
* If it returns true, the normal interrupt handler will NOT be called and
|
||||
* Zephyr will only see a spurious wake
|
||||
* Note: Use this only to perform special tasks, like sniffing interrupts,
|
||||
* or any other interrupt related cheat, but not as a normal interrupt handler
|
||||
*/
|
||||
typedef bool (*bst_test_irq_sniffer_t)(int irq_number);
|
||||
/*
|
||||
* This function will be called (in SW context) as a Zephyr PRE_KERNEL_1
|
||||
* device driver initialization function
|
||||
* Note that the app's main() has not executed yet, and the kernel is not yet
|
||||
* fully ready => You canNOT spawn new threads without wait time yet (or it
|
||||
* will crash)
|
||||
*/
|
||||
typedef void (*bst_test_fake_ddriver_prekernel_t)(void);
|
||||
/*
|
||||
* This function will be called (in SW context) as a Zephyr POST_KERNEL
|
||||
* device driver initialization function
|
||||
* You may spawn any test threads you may need here.
|
||||
* Note that the app main() has not executed yet.
|
||||
*/
|
||||
typedef void (*bst_test_fake_ddriver_postkernel_t)(void);
|
||||
/*
|
||||
* This function will be called (in SW context) as the Zephyr application main
|
||||
*/
|
||||
typedef void (*bst_test_main_t)(void);
|
||||
|
||||
typedef struct {
|
||||
char *test_id;
|
||||
char *test_descr;
|
||||
bst_test_args_t test_args_f;
|
||||
bst_test_pre_init_t test_pre_init_f;
|
||||
bst_test_post_init_t test_post_init_f;
|
||||
bst_test_tick_t test_tick_f;
|
||||
bst_test_delete_t test_delete_f;
|
||||
bst_test_irq_sniffer_t test_irq_sniffer_f;
|
||||
bst_test_fake_ddriver_prekernel_t test_fake_ddriver_prekernel_f;
|
||||
bst_test_fake_ddriver_postkernel_t test_fake_ddriver_postkernel_f;
|
||||
bst_test_main_t test_main_f;
|
||||
} bst_test_instance_t;
|
||||
|
||||
#define BSTEST_END_MARKER \
|
||||
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
|
||||
|
||||
typedef struct test_list_entry_t {
|
||||
bst_test_instance_t *test_instance;
|
||||
struct test_list_entry_t *next;
|
||||
} bst_test_list_t;
|
||||
|
||||
typedef bst_test_list_t *(*bst_test_install_t)(bst_test_list_t *test_tail);
|
||||
|
||||
bst_test_list_t *bst_add_tests(bst_test_list_t *tests,
|
||||
const bst_test_instance_t *test_def);
|
||||
void bst_set_testapp_mode(char *test_id);
|
||||
void bst_pass_args(int argc, char **argv);
|
||||
void bst_pre_init(void);
|
||||
void bst_post_init(void);
|
||||
void bst_main(void);
|
||||
void bst_tick(bs_time_t Absolute_device_time);
|
||||
bool bst_irq_sniffer(int irq_number);
|
||||
uint8_t bst_delete(void);
|
||||
|
||||
/* These return codes need to fit in a uint8_t (0..255), where 0 = successful */
|
||||
typedef enum {Passed = 0, In_progress = 1, Failed = 2} bst_result_t;
|
||||
|
||||
void bst_print_testslist(void);
|
||||
|
||||
/**
|
||||
* Interface for the fake HW device (timer) dedicated to the tests
|
||||
*/
|
||||
void bst_ticker_set_period(bs_time_t tick_period);
|
||||
void bst_ticker_set_next_tick_absolute(bs_time_t absolute_time);
|
||||
void bst_ticker_set_next_tick_delta(bs_time_t absolute_time);
|
||||
void bst_awake_cpu_asap(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
234
boards/posix/nrf52_bsim/bstests_entry.c
Normal file
234
boards/posix/nrf52_bsim/bstests_entry.c
Normal file
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "init.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "bs_types.h"
|
||||
#include "bs_tracing.h"
|
||||
#include "bstests.h"
|
||||
|
||||
/*
|
||||
* Result of the testcase execution.
|
||||
* Note that the executable will return the maximum of bst_result and
|
||||
* {the HW model return code} to the shell and that
|
||||
* {the HW model return code} will be 0 unless it fails or it is
|
||||
* configured illegally
|
||||
*/
|
||||
bst_result_t bst_result;
|
||||
|
||||
static bst_test_instance_t *current_test;
|
||||
static bst_test_list_t *test_list_top;
|
||||
|
||||
__attribute__((weak)) bst_test_install_t test_installers[] = { NULL };
|
||||
|
||||
bst_test_list_t *bst_add_tests(bst_test_list_t *tests,
|
||||
const bst_test_instance_t *test_def)
|
||||
{
|
||||
int idx = 0;
|
||||
bst_test_list_t *tail = tests;
|
||||
bst_test_list_t *head = tests;
|
||||
|
||||
if (tail) {
|
||||
/* First we 'run to end' */
|
||||
while (tail->next) {
|
||||
tail = tail->next;
|
||||
}
|
||||
} else {
|
||||
if (test_def[idx].test_id != NULL) {
|
||||
head = malloc(sizeof(bst_test_list_t));
|
||||
head->next = NULL;
|
||||
head->test_instance = (bst_test_instance_t *)
|
||||
&test_def[idx++];
|
||||
tail = head;
|
||||
}
|
||||
}
|
||||
|
||||
while (test_def[idx].test_id != NULL) {
|
||||
tail->next = malloc(sizeof(bst_test_list_t));
|
||||
tail = tail->next;
|
||||
tail->test_instance = (bst_test_instance_t *)&test_def[idx++];
|
||||
tail->next = NULL;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
static bst_test_instance_t *bst_test_find(bst_test_list_t *tests,
|
||||
char *test_id)
|
||||
{
|
||||
bst_test_list_t *top = tests;
|
||||
|
||||
while (top != NULL) {
|
||||
if (!strcmp(top->test_instance->test_id, test_id)) {
|
||||
/* Match found */
|
||||
return top->test_instance;
|
||||
}
|
||||
top = top->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bst_install_tests(void)
|
||||
{
|
||||
int idx = 0;
|
||||
|
||||
if (test_list_top) {
|
||||
/* Tests were already installed */
|
||||
return;
|
||||
}
|
||||
|
||||
/* First execute installers until first test was installed */
|
||||
while (!test_list_top && test_installers[idx]) {
|
||||
test_list_top = test_installers[idx++](test_list_top);
|
||||
}
|
||||
|
||||
/* After that simply add remaining tests to list */
|
||||
while (test_installers[idx]) {
|
||||
test_installers[idx++](test_list_top);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the tests list displayed with the --testslist command
|
||||
* line option
|
||||
*/
|
||||
void bst_print_testslist(void)
|
||||
{
|
||||
bst_test_list_t *top;
|
||||
|
||||
/* Install tests */
|
||||
bst_install_tests();
|
||||
|
||||
top = test_list_top;
|
||||
while (top) {
|
||||
bs_trace_raw(0, "TestID: %-10s\t%s\n",
|
||||
top->test_instance->test_id,
|
||||
top->test_instance->test_descr);
|
||||
top = top->next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the testcase to be run from its id
|
||||
*/
|
||||
void bst_set_testapp_mode(char *test_id)
|
||||
{
|
||||
/* Install tests */
|
||||
bst_install_tests();
|
||||
|
||||
/* By default all tests start as in progress */
|
||||
bst_result = In_progress;
|
||||
|
||||
current_test = bst_test_find(test_list_top, test_id);
|
||||
if (!current_test) {
|
||||
bs_trace_error_line("test id %s doesn't exist\n", test_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass to the testcase the command line arguments it may have
|
||||
*
|
||||
* This function is called after bst_set_testapp_mode
|
||||
* and before *init_f
|
||||
*/
|
||||
void bst_pass_args(int argc, char **argv)
|
||||
{
|
||||
if (current_test && current_test->test_args_f) {
|
||||
current_test->test_args_f(argc, argv);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be called before the CPU is booted
|
||||
*/
|
||||
void bst_pre_init(void)
|
||||
{
|
||||
if (current_test && current_test->test_pre_init_f) {
|
||||
current_test->test_pre_init_f();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be called when the CPU has gone to sleep for the first time
|
||||
*/
|
||||
void bst_post_init(void)
|
||||
{
|
||||
if (current_test && current_test->test_post_init_f) {
|
||||
current_test->test_post_init_f();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be called each time the bstest_ticker timer is triggered
|
||||
*/
|
||||
void bst_tick(bs_time_t time)
|
||||
{
|
||||
|
||||
if (current_test && current_test->test_tick_f) {
|
||||
current_test->test_tick_f(time);
|
||||
} else {
|
||||
bs_trace_error_line("the test id %s doesn't have a tick handler"
|
||||
" (how come did we arrive here?)\n",
|
||||
current_test->test_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool bst_irq_sniffer(int irq_number)
|
||||
{
|
||||
if (current_test && current_test->test_irq_sniffer_f) {
|
||||
return current_test->test_irq_sniffer_f(irq_number);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int bst_fake_device_driver_pre2_init(struct device *arg)
|
||||
{
|
||||
ARG_UNUSED(arg);
|
||||
if (current_test && current_test->test_fake_ddriver_prekernel_f) {
|
||||
current_test->test_fake_ddriver_prekernel_f();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bst_fake_device_driver_post_init(struct device *arg)
|
||||
{
|
||||
ARG_UNUSED(arg);
|
||||
if (current_test && current_test->test_fake_ddriver_postkernel_f) {
|
||||
current_test->test_fake_ddriver_postkernel_f();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(bst_fake_device_driver_pre2_init, PRE_KERNEL_1, 0);
|
||||
SYS_INIT(bst_fake_device_driver_post_init, POST_KERNEL, 0);
|
||||
|
||||
void bst_main(void)
|
||||
{
|
||||
if (current_test && current_test->test_main_f) {
|
||||
current_test->test_main_f();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be called when the device is being terminated
|
||||
*/
|
||||
uint8_t bst_delete(void)
|
||||
{
|
||||
if (current_test && current_test->test_delete_f) {
|
||||
current_test->test_delete_f();
|
||||
}
|
||||
|
||||
while (test_list_top) {
|
||||
bst_test_list_t *tmp = test_list_top->next;
|
||||
|
||||
free(test_list_top);
|
||||
test_list_top = tmp;
|
||||
}
|
||||
|
||||
return bst_result;
|
||||
}
|
173
boards/posix/nrf52_bsim/doc/board.rst
Normal file
173
boards/posix/nrf52_bsim/doc/board.rst
Normal file
|
@ -0,0 +1,173 @@
|
|||
|
||||
.. _nrf52_bsim:
|
||||
|
||||
NRF52 simulated board (BabbleSim)
|
||||
#################################
|
||||
|
||||
.. contents::
|
||||
:depth: 1
|
||||
:backlinks: entry
|
||||
:local:
|
||||
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
This is a simulated NRF52 board which uses `BabbleSim`_ to simulate the radio
|
||||
activity.
|
||||
This board models some of the NRF52 SOC peripherals:
|
||||
|
||||
* Radio
|
||||
* Timers
|
||||
* Real time counter
|
||||
* Random number gerator
|
||||
* AES CCM & AES ECB encryption HW
|
||||
* Accelerated address resolver
|
||||
* Clock control
|
||||
* PPI (Programmable Peripheral Interconnect)
|
||||
|
||||
The nrf52_bsim board definition uses the POSIX architecture to
|
||||
run applications natively on the development system. As with
|
||||
the ``native_posix`` board, this has the benefit of providing
|
||||
native code execution performance and easy debugging using
|
||||
native tools, but has the same drawbacks. Please refer to
|
||||
:ref:`Native Posix's important limitations <native_important_limitations>`
|
||||
for more details.
|
||||
|
||||
.. _BabbleSim:
|
||||
https://BabbleSim.github.io
|
||||
|
||||
Building and running
|
||||
**********************
|
||||
|
||||
.. note::
|
||||
|
||||
You must have the 32-bit C library installed in your system
|
||||
(in Ubuntu 16.04 install the gcc-multilib package)
|
||||
|
||||
.. note::
|
||||
|
||||
This will **not** work in Windows Subsystem for Linux (WSL) because WSL
|
||||
does not support native 32-bit binaries.
|
||||
|
||||
To target this board you need to have `BabbleSim`_ compiled in your system.
|
||||
If you do not have it yet, you can fetch and build it in this way:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
mkdir -p ${HOME}/bsim && cd ${HOME}/bsim
|
||||
repo init -u git@github.com:BabbleSim/manifest.git -m everything.xml \
|
||||
-b master
|
||||
repo sync
|
||||
make everything -j 8
|
||||
|
||||
Define two environment variables to point to your BabbleSim
|
||||
installation, ``BSIM_OUT_PATH`` and ``BSIM_COMPONENTS_PATH``.
|
||||
If you followed the previous steps, you can just do:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
export BSIM_OUT_PATH=${HOME}/bsim/
|
||||
export BSIM_COMPONENTS_PATH=${HOME}/bsim/components/
|
||||
|
||||
You're now ready to build applications targeting this board, for example:
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/hello_world
|
||||
:host-os: unix
|
||||
:board: nrf52_bsim
|
||||
:goals: build
|
||||
:compact:
|
||||
|
||||
Then you can execute your application using:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ zephyr/zephyr.exe -nosim
|
||||
# Press Ctrl+C to exit
|
||||
|
||||
Note that the executable is a BabbleSim executable. The ``-nosim`` command line
|
||||
option indicates you want to run it detached from a BabbleSim simulation. This
|
||||
is possible only while there is no radio activity. But is perfectly fine for
|
||||
most Zephyr samples and tests.
|
||||
|
||||
When you want to run a simulation with radio activity you need to run also the
|
||||
BableSim 2G4 (2.4GHz) physical layer simulation (phy).
|
||||
|
||||
For example, if you would like to run a simple case with 1 BLE ``central_hr``
|
||||
sample application connecting to a BLE ``peripheral`` sample application:
|
||||
Build the ``central_hr`` application targeting this board and copy the resulting
|
||||
executable to the simulator bin folder with a sensible name:
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/bluetooth/central_hr
|
||||
:host-os: unix
|
||||
:board: nrf52_bsim
|
||||
:goals: build
|
||||
:compact:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ cp zephyr/zephyr.exe \
|
||||
${BSIM_OUT_PATH}/bin/bs_nrf52_bsim_samples_bluetooth_central_hr
|
||||
|
||||
Do the same for the ``peripheral`` sample app:
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/bluetooth/peripheral
|
||||
:host-os: unix
|
||||
:board: nrf52_bsim
|
||||
:goals: build
|
||||
:compact:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ cp zephyr/zephyr.exe \
|
||||
${BSIM_OUT_PATH}/bin/bs_nrf52_bsim_samples_bluetooth_peripheral
|
||||
|
||||
And then run them together with BabbleSim's 2G4 physical layer simulation:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
cd ${BSIM_OUT_PATH}/bin/
|
||||
./bs_nrf52_bsim_samples_bluetooth_peripheral -s=trial_sim -d=0 &
|
||||
./bs_nrf52_bsim_samples_bluetooth_central_hr -s=trial_sim -d=1 &
|
||||
./bs_2G4_phy_v1 -s=trial_sim -D=2 -sim_length=10e6 &
|
||||
|
||||
Where the ``-s`` command line option provides a string which uniquely identifies
|
||||
this simulation; the ``-D`` option tells the Phy how many devices will be run
|
||||
in this simulation; the ``-d`` option tells each device which is its device
|
||||
number in the simulation; and the ``-sim_length`` option specifies the length
|
||||
of the simulation in microseconds.
|
||||
BabbleSim devices and Phy support many command line switches.
|
||||
Run them with ``-help`` for more information.
|
||||
|
||||
|
||||
Debugging
|
||||
**********
|
||||
|
||||
Just like native_posix, the resulting executables are Linux native applications.
|
||||
Therefore they can be debugged or instrumented with the same tools as any other
|
||||
native application, like for example ``gdb`` or ``valgrind``.
|
||||
|
||||
Note that BabbleSim will run fine if one or several of its components are
|
||||
being run in a debugger or instrumented. For example, pausing a device in a
|
||||
breakpoint will pause the whole simulation.
|
||||
|
||||
BabbleSim is fully deterministic by design and the results are not affected by
|
||||
the host computing speed. All randomness is controlled by random seeds which can
|
||||
be provided as command line options.
|
||||
|
||||
|
||||
About time in BabbleSim
|
||||
************************
|
||||
|
||||
Note that time in BabbleSim is simulated and decoupled from real time. Normally
|
||||
simulated time will pass several orders of magnitude faster than real time,
|
||||
only limited by your workstation compute power.
|
||||
If for some reason you want to limit the speed of the simulation to real
|
||||
time or a ratio of it, you can do so by connecting the `handbrake device`_
|
||||
to the BabbleSim Phy.
|
||||
|
||||
.. _handbrake device:
|
||||
https://github.com/BabbleSim/base/tree/master/device_handbrake
|
21
boards/posix/nrf52_bsim/fake/core_cm4.h
Normal file
21
boards/posix/nrf52_bsim/fake/core_cm4.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* This header is a replacement for the real core_cm4.h
|
||||
* so these defines, which are used in other files, exist
|
||||
*/
|
||||
|
||||
#ifndef CORE_CM4_H
|
||||
#define CORE_CM4_H
|
||||
|
||||
#define __I
|
||||
#define __O
|
||||
#define __IO
|
||||
|
||||
#define __IM
|
||||
#define __OM
|
||||
#define __IOM
|
||||
|
||||
#endif
|
4
boards/posix/nrf52_bsim/fake/system_nrf52.h
Normal file
4
boards/posix/nrf52_bsim/fake/system_nrf52.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
/*
|
||||
* This header is a empty on purpose. We need it as it is included from
|
||||
* other Zephyr files, but we do not need the content of the real one
|
||||
*/
|
428
boards/posix/nrf52_bsim/irq_handler.c
Normal file
428
boards/posix/nrf52_bsim/irq_handler.c
Normal file
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* SW side of the IRQ handling
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "irq_offload.h"
|
||||
#include "kernel_structs.h"
|
||||
#include "kernel_internal.h"
|
||||
#include "kswap.h"
|
||||
#include "irq_ctrl.h"
|
||||
#include "posix_core.h"
|
||||
#include "board_soc.h"
|
||||
#include "sw_isr_table.h"
|
||||
#include "soc.h"
|
||||
#include "bs_tracing.h"
|
||||
#include <tracing.h>
|
||||
#include "bstests.h"
|
||||
|
||||
static bool CPU_will_be_awaken_from_WFE;
|
||||
|
||||
typedef void (*normal_irq_f_ptr)(void *);
|
||||
typedef int (*direct_irq_f_ptr)(void);
|
||||
|
||||
static struct _isr_list irq_vector_table[NRF_HW_NBR_IRQs];
|
||||
|
||||
static int currently_running_irq = -1;
|
||||
|
||||
const char *irqnames[] = { /*just for the traces*/
|
||||
"POWER_CLOCK", /*0 */
|
||||
"RADIO", /*1 */
|
||||
"UART0", /*2 */
|
||||
"SPI0_TWI0", /*3 */
|
||||
"SPI1_TWI1", /*4 */
|
||||
"NFCT", /*5 */
|
||||
"GPIOTE", /*6 */
|
||||
"ADC", /*7 */
|
||||
"TIMER0", /*8 */
|
||||
"TIMER1", /*9 */
|
||||
"TIMER2", /*10*/
|
||||
"RTC0", /*11*/
|
||||
"TEMP", /*12*/
|
||||
"RNG", /*13*/
|
||||
"ECB", /*14*/
|
||||
"CCM_AAR", /*15*/
|
||||
"WDT", /*16*/
|
||||
"RTC1", /*17*/
|
||||
"QDEC", /*18*/
|
||||
"LPCOMP", /*19*/
|
||||
"SWI0", /*20*/
|
||||
"SWI1", /*21*/
|
||||
"SWI2", /*22*/
|
||||
"SWI3", /*23*/
|
||||
"SWI4", /*24*/
|
||||
"SWI5", /*25*/
|
||||
"TIMER3", /*26*/
|
||||
"TIMER4", /*27*/
|
||||
"PWM0", /*28*/
|
||||
"PDM", /*29*/
|
||||
"MWU", /*30*/
|
||||
"PWM1", /*31*/
|
||||
"PWM2", /*32*/
|
||||
"SPIM2_SPIS2_SPI2", /*33*/
|
||||
"RTC2", /*34*/
|
||||
"I2S", /*35*/
|
||||
"FPU" /*36*/
|
||||
};
|
||||
|
||||
static inline void vector_to_irq(int irq_nbr, int *may_swap)
|
||||
{
|
||||
/**
|
||||
* Call the test IRQ sniffer, and if it returns
|
||||
* true ignore the interrupt
|
||||
*/
|
||||
bool ret;
|
||||
|
||||
ret = bst_irq_sniffer(irq_nbr);
|
||||
if (ret) {
|
||||
return;
|
||||
}
|
||||
|
||||
bs_trace_raw_time(6, "Vectoring to irq %i (%s)\n", irq_nbr,
|
||||
irqnames[irq_nbr]);
|
||||
|
||||
/*
|
||||
* As in this architecture an irq (code) executes in 0 time,
|
||||
* it is a bit senseless to call _int_latency_start/stop()
|
||||
*/
|
||||
/* _int_latency_start(); */
|
||||
sys_trace_isr_enter();
|
||||
|
||||
if (irq_vector_table[irq_nbr].func == NULL) { /* LCOV_EXCL_BR_LINE */
|
||||
/* LCOV_EXCL_START */
|
||||
posix_print_error_and_exit("Received irq %i without a "
|
||||
"registered handler\n",
|
||||
irq_nbr);
|
||||
/* LCOV_EXCL_STOP */
|
||||
} else {
|
||||
if (irq_vector_table[irq_nbr].flags & ISR_FLAG_DIRECT) {
|
||||
*may_swap |= ((direct_irq_f_ptr)
|
||||
irq_vector_table[irq_nbr].func)();
|
||||
} else {
|
||||
#ifdef CONFIG_SYS_POWER_MANAGEMENT
|
||||
posix_irq_check_idle_exit();
|
||||
#endif
|
||||
((normal_irq_f_ptr)irq_vector_table[irq_nbr].func)
|
||||
(irq_vector_table[irq_nbr].param);
|
||||
*may_swap = 1;
|
||||
}
|
||||
}
|
||||
/* _int_latency_stop(); */
|
||||
|
||||
bs_trace_raw_time(7, "Irq %i (%s) ended\n", irq_nbr, irqnames[irq_nbr]);
|
||||
}
|
||||
|
||||
/**
|
||||
* When an interrupt is raised, this function is called to handle it and, if
|
||||
* needed, swap to a re-enabled thread
|
||||
*
|
||||
* Note that even that this function is executing in a Zephyr thread, it is
|
||||
* effectively the model of the interrupt controller passing context to the IRQ
|
||||
* handler and therefore its priority handling
|
||||
*/
|
||||
void posix_irq_handler(void)
|
||||
{
|
||||
u64_t irq_lock;
|
||||
int irq_nbr;
|
||||
static int may_swap;
|
||||
|
||||
irq_lock = hw_irq_ctrl_get_current_lock();
|
||||
|
||||
if (irq_lock) {
|
||||
/* "spurious" wakes can happen with interrupts locked */
|
||||
return;
|
||||
}
|
||||
|
||||
if (_kernel.nested == 0) {
|
||||
may_swap = 0;
|
||||
}
|
||||
|
||||
_kernel.nested++;
|
||||
|
||||
while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq()) != -1) {
|
||||
int last_current_running_prio = hw_irq_ctrl_get_cur_prio();
|
||||
int last_running_irq = currently_running_irq;
|
||||
|
||||
hw_irq_ctrl_set_cur_prio(hw_irq_ctrl_get_prio(irq_nbr));
|
||||
hw_irq_ctrl_clear_irq(irq_nbr);
|
||||
|
||||
currently_running_irq = irq_nbr;
|
||||
vector_to_irq(irq_nbr, &may_swap);
|
||||
currently_running_irq = last_running_irq;
|
||||
|
||||
hw_irq_ctrl_set_cur_prio(last_current_running_prio);
|
||||
}
|
||||
|
||||
_kernel.nested--;
|
||||
|
||||
/* Call swap if all the following is true:
|
||||
* 1) may_swap was enabled
|
||||
* 2) We are not nesting irq_handler calls (interrupts)
|
||||
* 3) Next thread to run in the ready queue is not this thread
|
||||
* 4) we are in a irq postfix (not just in a WFE)
|
||||
*/
|
||||
if (may_swap
|
||||
&& (hw_irq_ctrl_get_cur_prio() == 256)
|
||||
&& (CPU_will_be_awaken_from_WFE == false)
|
||||
&& (_kernel.ready_q.cache != _current)) {
|
||||
|
||||
_Swap(irq_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thru this function the IRQ controller can raise an immediate interrupt which
|
||||
* will interrupt the SW itself
|
||||
* (this function should only be called from the HW model code, from SW threads)
|
||||
*/
|
||||
void posix_irq_handler_im_from_sw(void)
|
||||
{
|
||||
/*
|
||||
* if a higher priority interrupt than the possibly currently running is
|
||||
* pending we go immediately into irq_handler() to vector into its
|
||||
* handler
|
||||
*/
|
||||
if (hw_irq_ctrl_get_highest_prio_irq() != -1) {
|
||||
if (!posix_is_cpu_running()) { /* LCOV_EXCL_BR_LINE */
|
||||
/* LCOV_EXCL_START */
|
||||
posix_print_error_and_exit("programming error: %s "
|
||||
"called from a HW model thread\n",
|
||||
__func__);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
posix_irq_handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable all interrupts on the CPU
|
||||
*
|
||||
* This routine disables interrupts. It can be called from either interrupt,
|
||||
* task or fiber level. This routine returns an architecture-dependent
|
||||
* lock-out key representing the "interrupt disable state" prior to the call;
|
||||
* this key can be passed to irq_unlock() to re-enable interrupts.
|
||||
*
|
||||
* The lock-out key should only be used as the argument to the irq_unlock()
|
||||
* API. It should never be used to manually re-enable interrupts or to inspect
|
||||
* or manipulate the contents of the source register.
|
||||
*
|
||||
* This function can be called recursively: it will return a key to return the
|
||||
* state of interrupt locking to the previous level.
|
||||
*
|
||||
* WARNINGS
|
||||
* Invoking a kernel routine with interrupts locked may result in
|
||||
* interrupts being re-enabled for an unspecified period of time. If the
|
||||
* called routine blocks, interrupts will be re-enabled while another
|
||||
* thread executes, or while the system is idle.
|
||||
*
|
||||
* The "interrupt disable state" is an attribute of a thread. Thus, if a
|
||||
* fiber or task disables interrupts and subsequently invokes a kernel
|
||||
* routine that causes the calling thread to block, the interrupt
|
||||
* disable state will be restored when the thread is later rescheduled
|
||||
* for execution.
|
||||
*
|
||||
* @return An architecture-dependent lock-out key representing the
|
||||
* "interrupt disable state" prior to the call.
|
||||
*
|
||||
*/
|
||||
unsigned int posix_irq_lock(void)
|
||||
{
|
||||
return hw_irq_ctrl_change_lock(true);
|
||||
}
|
||||
|
||||
unsigned int _arch_irq_lock(void)
|
||||
{
|
||||
return posix_irq_lock();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Enable all interrupts on the CPU
|
||||
*
|
||||
* This routine re-enables interrupts on the CPU. The @a key parameter is a
|
||||
* board-dependent lock-out key that is returned by a previous invocation of
|
||||
* board_irq_lock().
|
||||
*
|
||||
* This routine can be called from either interrupt, task or fiber level.
|
||||
*
|
||||
* @return N/A
|
||||
*
|
||||
*/
|
||||
void posix_irq_unlock(unsigned int key)
|
||||
{
|
||||
hw_irq_ctrl_change_lock(key);
|
||||
}
|
||||
|
||||
void _arch_irq_unlock(unsigned int key)
|
||||
{
|
||||
posix_irq_unlock(key);
|
||||
}
|
||||
|
||||
|
||||
void posix_irq_full_unlock(void)
|
||||
{
|
||||
hw_irq_ctrl_change_lock(false);
|
||||
}
|
||||
|
||||
void _arch_irq_enable(unsigned int irq)
|
||||
{
|
||||
hw_irq_ctrl_enable_irq(irq);
|
||||
}
|
||||
|
||||
void _arch_irq_disable(unsigned int irq)
|
||||
{
|
||||
hw_irq_ctrl_disable_irq(irq);
|
||||
}
|
||||
|
||||
int _arch_irq_is_enabled(unsigned int irq)
|
||||
{
|
||||
return hw_irq_ctrl_is_irq_enabled(irq);
|
||||
}
|
||||
|
||||
void _arch_isr_direct_header(void)
|
||||
{
|
||||
/* Nothing to be done */
|
||||
}
|
||||
|
||||
int posix_get_current_irq(void)
|
||||
{
|
||||
return currently_running_irq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a static interrupt.
|
||||
*
|
||||
* _isr_declare will populate the interrupt table table with the interrupt's
|
||||
* parameters, the vector table and the software ISR table.
|
||||
*
|
||||
* We additionally set the priority in the interrupt controller at
|
||||
* runtime.
|
||||
*
|
||||
* @param irq_p IRQ line number
|
||||
* @param flags [plug it directly (1), or as a SW managed interrupt (0)]
|
||||
* @param isr_p Interrupt service routine
|
||||
* @param isr_param_p ISR parameter
|
||||
* @param flags_p IRQ options
|
||||
*/
|
||||
void _isr_declare(unsigned int irq_p, int flags, void isr_p(void *),
|
||||
void *isr_param_p)
|
||||
{
|
||||
irq_vector_table[irq_p].irq = irq_p;
|
||||
irq_vector_table[irq_p].func = isr_p;
|
||||
irq_vector_table[irq_p].param = isr_param_p;
|
||||
irq_vector_table[irq_p].flags = flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* @internal
|
||||
*
|
||||
* @brief Set an interrupt's priority
|
||||
*
|
||||
* Lower values take priority over higher values.
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
void _irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags)
|
||||
{
|
||||
hw_irq_ctrl_prio_set(irq, prio);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to ARM's NVIC_SetPendingIRQ
|
||||
* set a pending IRQ from SW
|
||||
*
|
||||
* Note that this will interrupt immediately if the interrupt is not masked and
|
||||
* IRQs are not locked, and this interrupt has higher priority than a possibly
|
||||
* currently running interrupt
|
||||
*/
|
||||
void posix_sw_set_pending_IRQ(unsigned int IRQn)
|
||||
{
|
||||
hw_irq_ctrl_raise_im_from_sw(IRQn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to ARM's NVIC_ClearPendingIRQ
|
||||
* clear a pending irq from SW
|
||||
*/
|
||||
void posix_sw_clear_pending_IRQ(unsigned int IRQn)
|
||||
{
|
||||
hw_irq_ctrl_clear_irq(IRQn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage for functions offloaded to IRQ
|
||||
*/
|
||||
static irq_offload_routine_t off_routine;
|
||||
static void *off_parameter;
|
||||
|
||||
/**
|
||||
* IRQ handler for the SW interrupt assigned to irq_offload()
|
||||
*/
|
||||
static void offload_sw_irq_handler(void *a)
|
||||
{
|
||||
ARG_UNUSED(a);
|
||||
off_routine(off_parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Run a function in interrupt context
|
||||
*
|
||||
* Raise the SW IRQ assigned to handled this
|
||||
*/
|
||||
void irq_offload(irq_offload_routine_t routine, void *parameter)
|
||||
{
|
||||
off_routine = routine;
|
||||
off_parameter = parameter;
|
||||
_isr_declare(OFFLOAD_SW_IRQ, 0, offload_sw_irq_handler, NULL);
|
||||
_arch_irq_enable(OFFLOAD_SW_IRQ);
|
||||
posix_sw_set_pending_IRQ(OFFLOAD_SW_IRQ);
|
||||
_arch_irq_disable(OFFLOAD_SW_IRQ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement for ARMs NVIC_SetPendingIRQ()
|
||||
*
|
||||
* Sets the interrupt IRQn as pending
|
||||
* Note:
|
||||
* This will interrupt immediately if the interrupt
|
||||
* is not masked and irqs are not locked, and this interrupt is higher
|
||||
* priority than a possibly currently running interrupt
|
||||
*/
|
||||
void NVIC_SetPendingIRQ(IRQn_Type IRQn)
|
||||
{
|
||||
hw_irq_ctrl_raise_im_from_sw(IRQn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement for ARMs NVIC_ClearPendingIRQ()
|
||||
* Clear pending interrupt IRQn
|
||||
*/
|
||||
void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
|
||||
{
|
||||
hw_irq_ctrl_clear_irq(IRQn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Very simple model of the WFE and SEV ARM instructions
|
||||
* which seems good enough for the Nordic controller
|
||||
*/
|
||||
static bool CPU_event_set_flag;
|
||||
|
||||
void __WFE(void)
|
||||
{
|
||||
if (CPU_event_set_flag == false) {
|
||||
CPU_will_be_awaken_from_WFE = true;
|
||||
posix_halt_cpu();
|
||||
CPU_will_be_awaken_from_WFE = false;
|
||||
}
|
||||
CPU_event_set_flag = false;
|
||||
}
|
||||
|
||||
void __SEV(void)
|
||||
{
|
||||
CPU_event_set_flag = true;
|
||||
}
|
29
boards/posix/nrf52_bsim/k_busy_wait.c
Normal file
29
boards/posix/nrf52_bsim/k_busy_wait.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "zephyr/types.h"
|
||||
#include "fake_timer.h"
|
||||
#include "time_machine.h"
|
||||
#include "posix_soc_if.h"
|
||||
|
||||
#if defined(CONFIG_ARCH_HAS_CUSTOM_BUSY_WAIT)
|
||||
/**
|
||||
* Replacement to the kernel k_busy_wait()
|
||||
* Will block this thread (and therefore the whole zephyr) during usec_to_wait
|
||||
*
|
||||
* Note that interrupts may be received in the meanwhile and that therefore this
|
||||
* thread may loose context
|
||||
*/
|
||||
void k_busy_wait(u32_t usec_to_wait)
|
||||
{
|
||||
bs_time_t time_end = tm_get_hw_time() + usec_to_wait;
|
||||
|
||||
while (tm_get_hw_time() < time_end) {
|
||||
/*There may be wakes due to other interrupts*/
|
||||
fake_timer_wake_in_time(time_end);
|
||||
posix_halt_cpu();
|
||||
}
|
||||
}
|
||||
#endif
|
115
boards/posix/nrf52_bsim/main.c
Normal file
115
boards/posix/nrf52_bsim/main.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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_symbols.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();
|
||||
|
||||
u8_t bst_result = bst_delete();
|
||||
|
||||
if (bst_result != 0) {
|
||||
bs_trace_raw_time(2, "main: The TESTCASE FAILED with return "
|
||||
"code %u\n", bst_result);
|
||||
}
|
||||
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;
|
||||
|
||||
nrfbsim_argsparse(argc, argv, &args);
|
||||
global_device_nbr = args.global_device_nbr;
|
||||
|
||||
bs_read_function_names_from_Tsymbols(argv[0]);
|
||||
|
||||
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);
|
||||
|
||||
nrf_hw_initialize(&args.nrf_hw);
|
||||
|
||||
run_native_tasks(_NATIVE_PRE_BOOT_3_LEVEL);
|
||||
|
||||
bst_pre_init();
|
||||
|
||||
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;
|
||||
}
|
9
boards/posix/nrf52_bsim/nrf52_bsim.yaml
Normal file
9
boards/posix/nrf52_bsim/nrf52_bsim.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
identifier: nrf52_bsim
|
||||
name: NRF52 BabbleSim board
|
||||
type: native
|
||||
arch: posix
|
||||
toolchain:
|
||||
- zephyr
|
||||
testing:
|
||||
ignore_tags:
|
||||
- drivers
|
6
boards/posix/nrf52_bsim/nrf52_bsim_defconfig
Normal file
6
boards/posix/nrf52_bsim/nrf52_bsim_defconfig
Normal file
|
@ -0,0 +1,6 @@
|
|||
CONFIG_ARCH_POSIX=y
|
||||
CONFIG_SOC_POSIX=y
|
||||
CONFIG_BOARD_NRF52_BSIM=y
|
||||
CONFIG_CONSOLE=y
|
||||
CONFIG_NO_OPTIMIZATIONS=y
|
||||
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=32768
|
325
boards/posix/nrf52_bsim/radio_sim_nrfxx.h
Normal file
325
boards/posix/nrf52_bsim/radio_sim_nrfxx.h
Normal file
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2018 Ioannis Glaropoulos
|
||||
* Copyright (c) 2018 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* This header needs lots of types and macros, instead of relaying on
|
||||
* good inclusion order let's pull them through soc.h
|
||||
*/
|
||||
#include "soc.h"
|
||||
|
||||
/* NRF Radio HW timing constants
|
||||
* - provided in US and NS (for higher granularity)
|
||||
* - based on empirical measurements and sniffer logs
|
||||
*/
|
||||
|
||||
/* TXEN->TXIDLE + TXIDLE->TX (with fast Radio ramp-up mode)
|
||||
* in microseconds for LE 1M PHY.
|
||||
*/
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_FAST_NS 41000
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_FAST_US \
|
||||
HAL_RADIO_NS2US_ROUND(HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_FAST_NS)
|
||||
|
||||
/* TXEN->TXIDLE + TXIDLE->TX (with default Radio ramp-up mode)
|
||||
* in microseconds for LE 1M PHY.
|
||||
*/
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_DEFAULT_NS 141000
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_DEFAULT_US \
|
||||
HAL_RADIO_NS2US_ROUND(HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_DEFAULT_NS)
|
||||
|
||||
/* TXEN->TXIDLE + TXIDLE->TX (with default Radio ramp-up mode
|
||||
* and no HW TIFS auto-switch) in microseconds for LE 1M PHY.
|
||||
*/
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_DEFAULT_NO_HW_TIFS_NS 130000
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_DEFAULT_NO_HW_TIFS_US \
|
||||
HAL_RADIO_NS2US_ROUND( \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_DEFAULT_NO_HW_TIFS_NS)
|
||||
|
||||
/* TXEN->TXIDLE + TXIDLE->TX (with fast Radio ramp-up mode)
|
||||
* in microseconds for LE 2M PHY.
|
||||
*/
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_FAST_NS 40000
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_FAST_US \
|
||||
HAL_RADIO_NS2US_ROUND(HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_FAST_NS)
|
||||
|
||||
/* TXEN->TXIDLE + TXIDLE->TX (with default Radio ramp-up mode)
|
||||
* in microseconds for LE 2M PHY.
|
||||
*/
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_DEFAULT_NS 140000
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_DEFAULT_US \
|
||||
HAL_RADIO_NS2US_ROUND(HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_DEFAULT_NS)
|
||||
|
||||
/* TXEN->TXIDLE + TXIDLE->TX (with default Radio ramp-up mode
|
||||
* and no HW TIFS auto-switch) in microseconds for LE 2M PHY.
|
||||
*/
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_DEFAULT_NO_HW_TIFS_NS 129000
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_DEFAULT_NO_HW_TIFS_US \
|
||||
HAL_RADIO_NS2US_ROUND( \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_DEFAULT_NO_HW_TIFS_NS)
|
||||
|
||||
/* RXEN->RXIDLE + RXIDLE->RX (with fast Radio ramp-up mode)
|
||||
* in microseconds for LE 1M PHY.
|
||||
*/
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_FAST_NS 40000
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_FAST_US \
|
||||
HAL_RADIO_NS2US_CEIL(HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_FAST_NS)
|
||||
|
||||
/* RXEN->RXIDLE + RXIDLE->RX (with default Radio ramp-up mode)
|
||||
* in microseconds for LE 1M PHY.
|
||||
*/
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_DEFAULT_NS 140000
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_DEFAULT_US \
|
||||
HAL_RADIO_NS2US_CEIL(HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_DEFAULT_NS)
|
||||
|
||||
/* RXEN->RXIDLE + RXIDLE->RX (with default Radio ramp-up mode and
|
||||
* no HW TIFS auto-switch) in microseconds for LE 1M PHY.
|
||||
*/
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_DEFAULT_NO_HW_TIFS_NS 129000
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_DEFAULT_NO_HW_TIFS_US \
|
||||
HAL_RADIO_NS2US_CEIL( \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_DEFAULT_NO_HW_TIFS_NS)
|
||||
|
||||
/* RXEN->RXIDLE + RXIDLE->RX (with fast Radio ramp-up mode)
|
||||
* in microseconds for LE 2M PHY.
|
||||
*/
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_FAST_NS 40000
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_FAST_US \
|
||||
HAL_RADIO_NS2US_CEIL(HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_FAST_NS)
|
||||
|
||||
/* RXEN->RXIDLE + RXIDLE->RX (with default Radio ramp-up mode)
|
||||
* in microseconds for LE 2M PHY.
|
||||
*/
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_DEFAULT_NS 140000
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_DEFAULT_US \
|
||||
HAL_RADIO_NS2US_CEIL(HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_DEFAULT_NS)
|
||||
|
||||
/* RXEN->RXIDLE + RXIDLE->RX (with default Radio ramp-up mode and
|
||||
* no HW TIFS auto-switch) in microseconds for LE 2M PHY.
|
||||
*/
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_DEFAULT_NO_HW_TIFS_NS 129000
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_DEFAULT_NO_HW_TIFS_US \
|
||||
HAL_RADIO_NS2US_CEIL(\
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_DEFAULT_NO_HW_TIFS_NS)
|
||||
|
||||
#define HAL_RADIO_NRF52832_TX_CHAIN_DELAY_NS 1000
|
||||
#define HAL_RADIO_NRF52832_TX_CHAIN_DELAY_US \
|
||||
HAL_RADIO_NS2US_CEIL(HAL_RADIO_NRF52832_TX_CHAIN_DELAY_NS)
|
||||
|
||||
#define HAL_RADIO_NRF52832_RX_CHAIN_DELAY_1M_NS 9000
|
||||
#define HAL_RADIO_NRF52832_RX_CHAIN_DELAY_1M_US \
|
||||
HAL_RADIO_NS2US_CEIL(HAL_RADIO_NRF52832_RX_CHAIN_DELAY_1M_NS)
|
||||
|
||||
#define HAL_RADIO_NRF52832_RX_CHAIN_DELAY_2M_NS 5000
|
||||
#define HAL_RADIO_NRF52832_RX_CHAIN_DELAY_2M_US \
|
||||
HAL_RADIO_NS2US_CEIL(HAL_RADIO_NRF52832_RX_CHAIN_DELAY_2M_NS)
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_RADIO_ENABLE_FAST)
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_US \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_FAST_US
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_NS \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_FAST_NS
|
||||
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_US \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_FAST_US
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_NS \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_FAST_NS
|
||||
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_US \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_FAST_US
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_NS \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_FAST_NS
|
||||
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_US \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_FAST_US
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_NS \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_FAST_NS
|
||||
|
||||
#else /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */
|
||||
#if defined(CONFIG_BT_CTLR_TIFS_HW)
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_US \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_DEFAULT_US
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_NS \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_DEFAULT_NS
|
||||
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_US \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_DEFAULT_US
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_NS \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_DEFAULT_NS
|
||||
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_US \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_DEFAULT_US
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_NS \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_DEFAULT_NS
|
||||
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_US \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_DEFAULT_US
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_NS \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_DEFAULT_NS
|
||||
|
||||
#else /* !CONFIG_BT_CTLR_TIFS_HW */
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_US \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_DEFAULT_NO_HW_TIFS_US
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_NS \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_DEFAULT_NO_HW_TIFS_NS
|
||||
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_US \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_DEFAULT_NO_HW_TIFS_US
|
||||
#define HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_NS \
|
||||
HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_DEFAULT_NO_HW_TIFS_NS
|
||||
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_US \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_DEFAULT_NO_HW_TIFS_US
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_NS \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_DEFAULT_NO_HW_TIFS_NS
|
||||
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_US \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_DEFAULT_NO_HW_TIFS_US
|
||||
#define HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_NS \
|
||||
HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_DEFAULT_NO_HW_TIFS_NS
|
||||
#endif /* !CONFIG_BT_CTLR_TIFS_HW */
|
||||
#endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */
|
||||
|
||||
#if !defined(CONFIG_BT_CTLR_TIFS_HW)
|
||||
#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
|
||||
#undef EVENT_TIMER
|
||||
#define EVENT_TIMER NRF_TIMER0
|
||||
#define SW_SWITCH_TIMER EVENT_TIMER
|
||||
#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0
|
||||
#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
|
||||
#define SW_SWITCH_TIMER NRF_TIMER1
|
||||
#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0
|
||||
#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
|
||||
|
||||
#define SW_SWITCH_TIMER_TASK_GROUP_BASE 0
|
||||
#endif /* !CONFIG_BT_CTLR_TIFS_HW */
|
||||
|
||||
static inline void hal_radio_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void hal_radio_ram_prio_setup(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static inline u32_t hal_radio_phy_mode_get(u8_t phy, u8_t flags)
|
||||
{
|
||||
ARG_UNUSED(flags);
|
||||
u32_t mode;
|
||||
|
||||
switch (phy) {
|
||||
case BIT(0):
|
||||
default:
|
||||
mode = RADIO_MODE_MODE_Ble_1Mbit;
|
||||
break;
|
||||
|
||||
case BIT(1):
|
||||
mode = RADIO_MODE_MODE_Ble_2Mbit;
|
||||
break;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static inline u32_t hal_radio_tx_power_max_get(void)
|
||||
{
|
||||
return RADIO_TXPOWER_TXPOWER_Pos4dBm;
|
||||
}
|
||||
|
||||
static inline u32_t hal_radio_tx_ready_delay_us_get(u8_t phy, u8_t flags)
|
||||
{
|
||||
ARG_UNUSED(flags);
|
||||
|
||||
switch (phy) {
|
||||
default:
|
||||
case BIT(0):
|
||||
return HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_US;
|
||||
case BIT(1):
|
||||
return HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_US;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32_t hal_radio_rx_ready_delay_us_get(u8_t phy, u8_t flags)
|
||||
{
|
||||
ARG_UNUSED(flags);
|
||||
|
||||
switch (phy) {
|
||||
default:
|
||||
case BIT(0):
|
||||
return HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_US;
|
||||
case BIT(1):
|
||||
return HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_US;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32_t hal_radio_tx_chain_delay_us_get(u8_t phy, u8_t flags)
|
||||
{
|
||||
ARG_UNUSED(phy);
|
||||
ARG_UNUSED(flags);
|
||||
|
||||
return HAL_RADIO_NRF52832_TX_CHAIN_DELAY_US;
|
||||
}
|
||||
|
||||
static inline u32_t hal_radio_rx_chain_delay_us_get(u8_t phy, u8_t flags)
|
||||
{
|
||||
ARG_UNUSED(flags);
|
||||
|
||||
switch (phy) {
|
||||
default:
|
||||
case BIT(0):
|
||||
return HAL_RADIO_NRF52832_RX_CHAIN_DELAY_1M_US;
|
||||
case BIT(1):
|
||||
return HAL_RADIO_NRF52832_RX_CHAIN_DELAY_2M_US;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32_t hal_radio_tx_ready_delay_ns_get(u8_t phy, u8_t flags)
|
||||
{
|
||||
ARG_UNUSED(flags);
|
||||
|
||||
switch (phy) {
|
||||
default:
|
||||
case BIT(0):
|
||||
return HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_1M_NS;
|
||||
case BIT(1):
|
||||
return HAL_RADIO_NRF52832_TXEN_TXIDLE_TX_2M_NS;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32_t hal_radio_rx_ready_delay_ns_get(u8_t phy, u8_t flags)
|
||||
{
|
||||
ARG_UNUSED(flags);
|
||||
|
||||
switch (phy) {
|
||||
default:
|
||||
case BIT(0):
|
||||
return HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_1M_NS;
|
||||
case BIT(1):
|
||||
return HAL_RADIO_NRF52832_RXEN_RXIDLE_RX_2M_NS;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32_t hal_radio_tx_chain_delay_ns_get(u8_t phy, u8_t flags)
|
||||
{
|
||||
ARG_UNUSED(phy);
|
||||
ARG_UNUSED(flags);
|
||||
|
||||
return HAL_RADIO_NRF52832_TX_CHAIN_DELAY_US;
|
||||
}
|
||||
|
||||
static inline u32_t hal_radio_rx_chain_delay_ns_get(u8_t phy, u8_t flags)
|
||||
{
|
||||
ARG_UNUSED(flags);
|
||||
|
||||
switch (phy) {
|
||||
default:
|
||||
case BIT(0):
|
||||
return HAL_RADIO_NRF52832_RX_CHAIN_DELAY_1M_NS;
|
||||
case BIT(1):
|
||||
return HAL_RADIO_NRF52832_RX_CHAIN_DELAY_2M_NS;
|
||||
}
|
||||
}
|
225
boards/posix/nrf52_bsim/time_machine.c
Normal file
225
boards/posix/nrf52_bsim/time_machine.c
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* 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 hw_time
|
||||
*/
|
||||
static void tm_sleep_until_hw_time(bs_time_t hw_time)
|
||||
{
|
||||
bs_time_t next_time = TIME_NEVER;
|
||||
|
||||
if (hw_time != TIME_NEVER) {
|
||||
next_time = hw_time + 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)
|
||||
{
|
||||
return hwtime + hw_time_delta;
|
||||
}
|
||||
|
||||
bs_time_t tm_abs_time_to_hw_time(bs_time_t abstime)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
36
boards/posix/nrf52_bsim/time_machine.h
Normal file
36
boards/posix/nrf52_bsim/time_machine.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _TIME_MACHINE_H
|
||||
#define _TIME_MACHINE_H
|
||||
|
||||
#include "bs_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
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);
|
||||
|
||||
void tm_set_phy_max_resync_offset(bs_time_t offset_in_us);
|
||||
|
||||
void tm_run_forever(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
107
boards/posix/nrf52_bsim/trace_hook.c
Normal file
107
boards/posix/nrf52_bsim/trace_hook.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Oticon A/S
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <init.h>
|
||||
#include "bs_tracing.h"
|
||||
|
||||
#define _STDOUT_BUF_SIZE 256
|
||||
static char stdout_buff[_STDOUT_BUF_SIZE];
|
||||
static int n_pend; /* Number of pending characters in buffer */
|
||||
|
||||
int print_char(int c)
|
||||
{
|
||||
int printnow = 0;
|
||||
|
||||
if ((c != '\n') && (c != '\r')) {
|
||||
stdout_buff[n_pend++] = c;
|
||||
stdout_buff[n_pend] = 0;
|
||||
} else {
|
||||
printnow = 1;
|
||||
}
|
||||
|
||||
if (n_pend >= _STDOUT_BUF_SIZE - 1) {
|
||||
printnow = 1;
|
||||
}
|
||||
|
||||
if (printnow) {
|
||||
bs_trace_print(BS_TRACE_RAW, NULL, 0, 2, BS_TRACE_AUTOTIME, 0,
|
||||
"%s\n", stdout_buff);
|
||||
n_pend = 0;
|
||||
stdout_buff[0] = 0;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush to the terminal any possible pending printk
|
||||
*/
|
||||
void posix_flush_stdout(void)
|
||||
{
|
||||
if (n_pend) {
|
||||
stdout_buff[n_pend] = 0;
|
||||
bs_trace_print(BS_TRACE_RAW, NULL, 0, 2, BS_TRACE_AUTOTIME, 0,
|
||||
"%s", stdout_buff);
|
||||
n_pend = 0;
|
||||
stdout_buff[0] = 0;
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Initialize the driver that provides the printk output
|
||||
*
|
||||
* @return 0 if successful, otherwise failed.
|
||||
*/
|
||||
static int printk_init(struct device *arg)
|
||||
{
|
||||
ARG_UNUSED(arg);
|
||||
|
||||
extern void __printk_hook_install(int (*fn)(int));
|
||||
__printk_hook_install(print_char);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(printk_init, PRE_KERNEL_1, CONFIG_PRINTK_HOOK_INIT_PRIORITY);
|
||||
|
||||
void posix_print_error_and_exit(const char *format, ...)
|
||||
{
|
||||
va_list variable_argsp;
|
||||
|
||||
va_start(variable_argsp, format);
|
||||
bs_trace_vprint(BS_TRACE_ERROR, NULL, 0, 0, BS_TRACE_AUTOTIME, 0,
|
||||
format, variable_argsp);
|
||||
va_end(variable_argsp);
|
||||
}
|
||||
|
||||
void posix_print_warning(const char *format, ...)
|
||||
{
|
||||
va_list variable_argsp;
|
||||
|
||||
va_start(variable_argsp, format);
|
||||
bs_trace_vprint(BS_TRACE_WARNING, NULL, 0, 0, BS_TRACE_AUTOTIME, 0,
|
||||
format, variable_argsp);
|
||||
va_end(variable_argsp);
|
||||
}
|
||||
|
||||
void posix_print_trace(const char *format, ...)
|
||||
{
|
||||
va_list variable_argsp;
|
||||
|
||||
va_start(variable_argsp, format);
|
||||
bs_trace_vprint(BS_TRACE_RAW, NULL, 0, 2, BS_TRACE_AUTOTIME, 0,
|
||||
format, variable_argsp);
|
||||
va_end(variable_argsp);
|
||||
}
|
||||
|
||||
|
||||
int posix_trace_over_tty(int file_number)
|
||||
{
|
||||
return bs_trace_is_tty(file_number);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue