native_sim: Add new native_sim board

Add the new native_sim board, based on the native simulator.

Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
This commit is contained in:
Alberto Escolar Piedras 2023-06-07 10:39:48 +02:00 committed by Chris Friedt
parent 945429e8c3
commit ece74b7b7f
32 changed files with 1208 additions and 16 deletions

View file

@ -1764,15 +1764,32 @@ if(CONFIG_BUILD_OUTPUT_STRIPPED)
endif()
if(CONFIG_BUILD_OUTPUT_EXE)
list(APPEND
post_build_commands
COMMAND
${CMAKE_COMMAND} -E copy ${KERNEL_ELF_NAME} ${KERNEL_EXE_NAME}
)
list(APPEND
post_build_byproducts
${KERNEL_EXE_NAME}
if (NOT CONFIG_NATIVE_LIBRARY)
list(APPEND
post_build_commands
COMMAND
${CMAKE_COMMAND} -E copy ${KERNEL_ELF_NAME} ${KERNEL_EXE_NAME}
)
list(APPEND
post_build_byproducts
${KERNEL_EXE_NAME}
)
else()
if(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
set(MAKE "${CMAKE_MAKE_PROGRAM}" CACHE FILEPATH "cmake defined make")
endif()
find_program(MAKE make REQUIRED)
add_custom_target(native_runner_executable
ALL
COMMENT "Building native simulator runner, and linking final executable"
COMMAND
${MAKE} -f ${ZEPHYR_BASE}/scripts/native_simulator/Makefile all --warn-undefined-variables
-r NSI_CONFIG_FILE=${CMAKE_BINARY_DIR}/zephyr/NSI/nsi_config
# nsi_config is created by the board cmake file
DEPENDS ${logical_target_for_zephyr_elf}
BYPRODUCTS ${KERNEL_EXE_NAME}
)
endif()
endif()
if(CONFIG_BUILD_OUTPUT_INFO_HEADER)

View file

@ -71,7 +71,7 @@ endif()
if(CONFIG_COVERAGE)
zephyr_compile_options($<TARGET_PROPERTY:compiler,coverage>)
zephyr_link_libraries($<TARGET_PROPERTY:linker,coverage>)
zephyr_link_libraries_ifndef(CONFIG_NATIVE_LIBRARY $<TARGET_PROPERTY:linker,coverage>)
endif()
zephyr_sources_ifdef(CONFIG_SEMIHOST semihost.c)

View file

@ -1,5 +1,21 @@
# SPDX-License-Identifier: Apache-2.0
# This native_simulator library is used to pass options to the
# native_simulator runner build. Currently the following are used:
# INTERFACE_COMPILE_OPTIONS:
# Extra compile options to be used during the build of the runner files
# For ex. target_compile_options(native_simulator INTERFACE "-m64")
# INTERFACE_LINK_OPTIONS:
# Extra link options to be passed during the *final* link of the runner
# with the embedded SW.
# For ex. target_link_options(native_simulator INTERFACE "-lstdc++")
# INTERFACE_SOURCES:
# Extra sources to be built in the native simulator runner context
# For ex. target_sources(native_simulator INTERFACE silly.c)
# Note that these are built with the host libC and the include directories
# the runner is built with.
add_library(native_simulator INTERFACE)
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/${CMAKE_HOST_SYSTEM_NAME}.${CMAKE_HOST_SYSTEM_PROCESSOR}.cmake)
# @Intent: Set necessary compiler & linker options for this specific host architecture & OS
include(${CMAKE_HOST_SYSTEM_NAME}.${CMAKE_HOST_SYSTEM_PROCESSOR}.cmake)
@ -8,9 +24,15 @@ else()
# some gcc versions fail to build without -fPIC
zephyr_compile_options(-m64 -fPIC)
zephyr_link_libraries(-m64)
target_link_options(native_simulator INTERFACE "-m64")
target_compile_options(native_simulator INTERFACE "-m64")
else ()
zephyr_compile_options(-m32)
zephyr_link_libraries(-m32)
target_link_options(native_simulator INTERFACE "-m32")
target_compile_options(native_simulator INTERFACE "-m32")
endif ()
endif()
@ -22,24 +44,72 @@ if (CONFIG_NATIVE_APPLICATION)
zephyr_compile_options(
-include ${ZEPHYR_BASE}/arch/posix/include/posix_cheats.h
)
elseif (CONFIG_NATIVE_LIBRARY)
zephyr_compile_options(
-fvisibility=hidden
)
# While doing the partial linking of the native library, some symbols will be missing
# which are provided by the native simulator runner
zephyr_ld_options(
-Wl,--unresolved-symbols=ignore-all
)
if (NOT CONFIG_EXTERNAL_LIBC)
# Get the *compiler* include path, that is where the *compiler* provided headers are (not the
# default libC ones). This includes basic headers like stdint.h, stddef.h or float.h
# We expect something like
# /usr/lib/gcc/x86_64-linux-gnu/12/include or /usr/lib/llvm-14/lib/clang/14.0.0/include
execute_process(
COMMAND ${CMAKE_C_COMPILER} --print-file-name=include/stddef.h
OUTPUT_VARIABLE _OUTPUT
COMMAND_ERROR_IS_FATAL ANY
)
get_filename_component(COMPILER_OWN_INCLUDE_PATH "${_OUTPUT}" DIRECTORY)
# Do not use the C library from this compiler/host,
# but still use the basic compiler headers
# -fno-builtin to avoid the compiler using builtin replacements for std library functions
zephyr_compile_options(
-nostdinc
-isystem ${COMPILER_OWN_INCLUDE_PATH}
$<TARGET_PROPERTY:compiler,freestanding>
-fno-builtin
)
endif()
endif()
# @Intent: Obtain compiler specific flags for no freestanding compilation
zephyr_compile_options($<TARGET_PROPERTY:compiler,hosted>)
if(CONFIG_EXTERNAL_LIBC)
# @Intent: Obtain compiler specific flags for no freestanding compilation
zephyr_compile_options($<TARGET_PROPERTY:compiler,hosted>)
endif()
if(CONFIG_EXTERNAL_LIBCPP)
target_link_options(native_simulator INTERFACE "-lstdc++")
endif()
zephyr_include_directories(${BOARD_DIR})
if(CONFIG_COVERAGE)
target_compile_options(native_simulator INTERFACE $<TARGET_PROPERTY:compiler,coverage>)
target_link_options(native_simulator INTERFACE $<TARGET_PROPERTY:linker,coverage>)
endif()
if (CONFIG_GPROF)
zephyr_compile_options($<TARGET_PROPERTY:compiler,gprof>)
zephyr_link_libraries($<TARGET_PROPERTY:linker,gprof>)
target_link_options(native_simulator INTERFACE "-pg")
endif()
zephyr_compile_definitions(_POSIX_C_SOURCE=200809 _XOPEN_SOURCE=600 _XOPEN_SOURCE_EXTENDED)
zephyr_ld_options(
-ldl
-pthread
)
if (CONFIG_NATIVE_APPLICATION)
zephyr_ld_options(
-ldl
-pthread
)
endif()
# About the -include directive: The reason to do it this way, is because in this
# manner it is transparent to the application. Otherwise posix_cheats.h needs to
@ -85,6 +155,9 @@ if(NOT ${LLVM_SANITIZERS_ARG} STREQUAL "")
set(LLVM_SANITIZERS_ARG "-fsanitize=${LLVM_SANITIZERS_ARG}")
zephyr_compile_options("${LLVM_SANITIZERS_ARG}")
zephyr_link_libraries("${LLVM_SANITIZERS_ARG}")
target_link_options(native_simulator INTERFACE ${LLVM_SANITIZERS_ARG})
target_compile_options(native_simulator INTERFACE ${LLVM_SANITIZERS_ARG})
endif()
# Override the C standard used for compilation to C 2011

View file

@ -7,6 +7,10 @@ zephyr_library_compile_definitions(NO_POSIX_CHEATS)
find_package(PkgConfig REQUIRED)
pkg_search_module(SDL2 REQUIRED sdl2)
zephyr_include_directories(${SDL2_INCLUDE_DIRS})
zephyr_link_libraries(${SDL2_LIBRARIES})
if (CONFIG_NATIVE_APPLICATION)
zephyr_link_libraries(${SDL2_LIBRARIES})
else()
target_link_options(native_simulator INTERFACE "-l${SDL2_LIBRARIES}")
endif()
zephyr_compile_options(${SDL2_CFLAGS_OTHER})
zephyr_library_sources(sdl_events.c)

View file

@ -36,6 +36,7 @@ Important limitations
This board inherits
:ref:`the limitations of its architecture<posix_arch_limitations>`
.. _native_posix_how_to_use:
How to use it
*************
@ -173,6 +174,7 @@ should be considered.
Check the :ref:`POSIX architecture comparison <posix_arch_compare>`
with other development and test options for more insights.
.. _native_posix_architecture:
Architecture
************
@ -246,6 +248,8 @@ simulated time when the last clock ratio adjustment took place.
All times are kept in microseconds.
.. _native_posix_peripherals:
Peripherals
***********

View file

@ -0,0 +1,49 @@
# SPDX-License-Identifier: Apache-2.0
set(NSI_DIR ${ZEPHYR_BASE}/scripts/native_simulator)
zephyr_library()
zephyr_library_compile_definitions(NO_POSIX_CHEATS)
zephyr_library_sources(
cmdline.c
cpu_wait.c
nsi_if.c
irq_handler.c
misc.c
posix_arch_if.c
)
zephyr_include_directories(
${NSI_DIR}/common/src/include
${NSI_DIR}/native/src/include
)
zephyr_library_include_directories(
${ZEPHYR_BASE}/kernel/include
${ZEPHYR_BASE}/arch/posix/include
)
if(CONFIG_HAS_SDL)
add_subdirectory(${ZEPHYR_BASE}/boards/${ARCH}/common/sdl/ ${CMAKE_CURRENT_BINARY_DIR}/sdl)
endif()
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}"
)

View file

@ -0,0 +1,50 @@
# Copyright (c) 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
config BOARD_NATIVE_SIM
bool "Native simulator (Single Core)"
select POSIX_ARCH_CONSOLE
select NATIVE_LIBRARY
select NATIVE_POSIX_TIMER
depends on SOC_POSIX
imply BOARD_NATIVE_POSIX if NATIVE_SIM_NATIVE_POSIX_COMPAT
if BOARD_NATIVE_SIM
comment "Native Simular (Single Core) options"
config NATIVE_SIM_NATIVE_POSIX_COMPAT
bool "Pretend to be a native_posix board"
default y
help
When this option is set the native_sim board will pretend to be
a native_posix board from kconfig point of view, to allow using it directly with
code which was meant for the native_posix board and checks for the macro
CONFIG_BOARD_NATIVE_POSIX, or requires other kconfig options which depend on it.
config NATIVE_SIM_SLOWDOWN_TO_REAL_TIME
bool "Slow down execution to real time"
default n if ARCH_POSIX_LIBFUZZER
default y if BT_USERCHAN || !TEST
help
When selected the execution of the process will be slowed down to real time.
(if there is a lot of load it may be slower than real time)
If deselected, the process will run as fast as possible.
Note that this only decouples simulated time from real/wall time. In either
case the zephyr kernel and application cannot tell the difference unless they
interact with some other driver/device which runs at real time.
# This option definition exists only to enable NATIVE_SIM_NATIVE_POSIX_COMPAT
config BOARD_NATIVE_POSIX
bool
config NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME
bool "Slow down execution to real time (native_posix compat)"
select NATIVE_SIM_SLOWDOWN_TO_REAL_TIME
help
Transitional option which allows applications which targeted native_posix
to set the correct native_sim option (CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME)
source "boards/$(ARCH)/common/sdl/Kconfig"
endif # BOARD_NATIVE_SIM

View file

@ -0,0 +1,17 @@
# Copyright (c) 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
config BOARD_NATIVE_SIM_32BIT
bool "Native simulation, 32-bit mode"
select BOARD_NATIVE_SIM
help
Will produce a console Linux process which can be executed natively
as a 32-bit executable.
config BOARD_NATIVE_SIM_64BIT
bool "Native simulation, 64-bit mode"
select BOARD_NATIVE_SIM
select 64BIT
help
Will produce a console Linux process which can be executed natively
as a 64-bit executable.

View file

@ -0,0 +1,73 @@
# Copyright (c) 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
if BOARD_NATIVE_SIM
config BUILD_OUTPUT_BIN
default n
config BUILD_OUTPUT_EXE
default y
config OUTPUT_PRINT_MEMORY_USAGE
default n
config BOARD
default "native_sim_64" if BOARD_NATIVE_SIM_64BIT
default "native_sim"
if NETWORKING
config NET_L2_ETHERNET
default y if !NET_LOOPBACK && !NET_TEST
config ETH_NATIVE_POSIX
default y if NET_L2_ETHERNET && ETH_DRIVER
endif # NETWORKING
choice BT_HCI_BUS_TYPE
default BT_USERCHAN
depends on BT_HCI
endchoice
if LOG
# For native_sim we can log synchronously without any problem
# Doing so will be nicer for debugging
choice LOG_MODE
default LOG_MODE_IMMEDIATE
endchoice
endif # LOG
if CONSOLE
config POSIX_ARCH_CONSOLE
default y if !SERIAL
config UART_CONSOLE
default y if SERIAL
endif # CONSOLE
config FLASH_SIMULATOR
default y
depends on FLASH
config USB_NATIVE_POSIX
default y
depends on USB_DEVICE_DRIVER
config EEPROM_SIMULATOR
default y
depends on EEPROM
if I2C
config EMUL
default y
endif # I2C
endif # BOARD_NATIVE_SIM

View file

@ -0,0 +1,3 @@
# SPDX-License-Identifier: Apache-2.0
set(SUPPORTED_EMU_PLATFORMS native)

View file

@ -0,0 +1,12 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BOARDS_POSIX_NATIVE_SIM_BOARD_IRQ_H
#define BOARDS_POSIX_NATIVE_SIM_BOARD_IRQ_H
#include "../common/irq/board_irq.h"
#endif /* BOARDS_POSIX_NATIVE_SIM_BOARD_IRQ_H */

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2017 Oticon A/S
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file Extra definitions provided by the board to soc.h
*
* Background:
* The POSIX 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 BOARDS_POSIX_NATIVE_SIM_BOARD_SOC_H
#define BOARDS_POSIX_NATIVE_SIM_BOARD_SOC_H
#include "nsi_cpu0_interrupts.h"
#endif /* BOARDS_POSIX_NATIVE_SIM_BOARD_SOC_H */

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* To support native_posix drivers or tests which register their own arguments
* we provide the same API as in native_posix
*/
#include "nsi_cmdline.h"
void native_add_command_line_opts(struct args_struct_t *args)
{
nsi_add_command_line_opts(args);
}
void native_get_cmd_line_args(int *argc, char ***argv)
{
nsi_get_cmd_line_args(argc, argv);
}
void native_get_test_cmd_line_args(int *argc, char ***argv)
{
nsi_get_test_cmd_line_args(argc, argv);
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2018 Oticon A/S
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BOARDS_POSIX_NATIVE_SIM_CMDLINE_H
#define BOARDS_POSIX_NATIVE_SIM_CMDLINE_H
#include "nsi_cmdline.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* To support native_posix drivers or tests which register their own arguments
* we provide a header with the same name as in native_posix
*/
void native_get_cmd_line_args(int *argc, char ***argv);
void native_get_test_cmd_line_args(int *argc, char ***argv);
void native_add_command_line_opts(struct args_struct_t *args);
#ifdef __cplusplus
}
#endif
#endif /* BOARDS_POSIX_NATIVE_SIM_CMDLINE_H */

View file

@ -0,0 +1,15 @@
/*
* Copyright (c) 2018 Oticon A/S
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BOARDS_POSIX_NATIVE_SIM_CMDLINE_COMMON_H
#define BOARDS_POSIX_NATIVE_SIM_CMDLINE_COMMON_H
/*
* To support native_posix drivers which register their own arguments
* we provide a header with the same name as in native_posix
*/
#include "nsi_cmdline.h"
#endif /* BOARDS_POSIX_NATIVE_SIM_CMDLINE_COMMON_H */

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2020 Oticon A/S
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <stdint.h>
#include <zephyr/arch/posix/posix_soc_if.h>
#include <posix_board_if.h>
#include <posix_soc.h>
#include "nsi_hw_scheduler.h"
#include "nsi_timer_model.h"
/**
* 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 lose context.
* Therefore the wait time may be considerably longer.
*
* All this function ensures is that it will return after usec_to_wait or later.
*
* This special arch_busy_wait() is necessary due to how the POSIX arch/SOC INF
* models a CPU. Conceptually it could be thought as if the MCU was running
* at an infinitely high clock, and therefore no simulated time passes while
* executing instructions(*1).
* Therefore to be able to busy wait this function does the equivalent of
* programming a dedicated timer which will raise a non-maskable interrupt,
* and halting the CPU.
*
* (*1) In reality simulated time is simply not advanced just due to the "MCU"
* running. Meaning, the SW running on the MCU is assumed to take 0 time.
*/
void arch_busy_wait(uint32_t usec_to_wait)
{
uint64_t time_end = nsi_hws_get_time() + usec_to_wait;
while (nsi_hws_get_time() < time_end) {
/*
* There may be wakes due to other interrupts including
* other threads calling arch_busy_wait
*/
hwtimer_wake_in_time(time_end);
posix_halt_cpu();
}
}
/**
* Will block this thread (and therefore the whole Zephyr) during usec_to_waste
*
* Very similar to arch_busy_wait(), but if an interrupt or context switch
* occurs this function will continue waiting after, ensuring that
* usec_to_waste are spent in this context, irrespectively of how much more
* time would be spent on interrupt handling or possible switched-in tasks.
*
* Can be used to emulate code execution time.
*/
void posix_cpu_hold(uint32_t usec_to_waste)
{
uint64_t time_start;
int64_t to_wait = usec_to_waste;
while (to_wait > 0) {
/*
* There may be wakes due to other interrupts or nested calls to
* cpu_hold in interrupt handlers
*/
time_start = nsi_hws_get_time();
hwtimer_wake_in_time(time_start + to_wait);
posix_change_cpu_state_and_wait(true);
to_wait -= nsi_hws_get_time() - time_start;
posix_irq_handler();
}
}

View file

@ -0,0 +1,128 @@
.. _native_sim:
Native simulator - native_sim
#############################
Overview
********
The native_sim board is an evolution of :ref:`native_posix<native_posix>`.
Just like with :ref:`native_posix<native_posix>` you can build your Zephyr application
with the Zephyr kernel, creating a normal Linux executable with your host tooling,
and can debug and instrument it like any other Linux program.
native_sim is based on the
`native simulator <https://github.com/BabbleSim/native_simulator/>`_
and the :ref:`POSIX architecture<Posix arch>`.
Host system dependencies
************************
Please check the
:ref:`Posix Arch Dependencies<posix_arch_deps>`
.. _nativesim_important_limitations:
Important limitations
*********************
Native_sim is based on the :ref:`POSIX architecture<Posix arch>`, and therefore
:ref:`its limitations <posix_arch_limitations>` and considerations apply to it.
How to use it
*************
To build, simply specify the native_sim board as target:
.. zephyr-app-commands::
:zephyr-app: samples/hello_world
:host-os: unix
:board: native_sim
:goals: build
:compact:
Now you have a Linux executable, ``./build/zephyr/zephyr.exe``, you can use just like any
other Linux program.
You can run, debug, build it with sanitizers or with coverage just like with
:ref:`native_posix <native_posix>`.
Please check :ref:`native_posix's how to<native_posix_how_to_use>` for more info.
32 and 64bit versions
*********************
Just like native_posix, native_sim comes with two targets: A 32 bit and 64 bit version.
The 32 bit version, ``native_sim``, is the default target, which will compile
your code for the ILP32 ABI (i386 in a x86 or x86_64 system) where pointers
and longs are 32 bits.
This mimics the ABI of most embedded systems Zephyr targets,
and is therefore normally best to test and debug your code, as some bugs are
dependent on the size of pointers and longs.
This target requires either a 64 bit system with multilib support installed or
one with a 32bit userspace.
The 64 bit version, ``native_sim_64``, compiles your code targeting the
LP64 ABI (x86-64 in x86 systems), where pointers and longs are 64 bits.
You can use this target if you cannot compile or run 32 bit binaries.
C library choice
****************
Unlike native_posix, native_sim may be compiled with a choice of C libraries.
By default it will be compiled with the host C library (:kconfig:option:`CONFIG_EXTERNAL_LIBC`),
but you can also select to build it with :kconfig:option:`CONFIG_MINIMAL_LIBC` or with
:kconfig:option:`CONFIG_PICOLIBC`.
When building with either :ref:`MINIMAL<c_library_minimal>` or :ref:`PICO<c_library_picolibc>` libC
you will build your code in a more similar way as when building for the embedded target,
you will be able to test your code interacting with that C library,
and there will be no conflicts with the :ref:`POSIX OS abstraction<posix_support>` shim,
but, accessing the host for test purposes from your embedded code will be more
difficult, and you will have a limited choice of
:ref:`drivers and backends to chose from<native_sim_peripherals>`.
Architecture
************
:ref:`native_posix's architecture description<native_posix_architecture>` as well as the
:ref:`POSIX architecture description<posix_arch_architecture>` are directly
applicable to native_sim.
If you are interested on the inner workigns of the native simulator itself, you can check
`its documentation <https://github.com/BabbleSim/native_simulator/blob/main/docs/README.md>`_.
.. _native_sim_peripherals:
Peripherals, subsystems backends and host based flash access
************************************************************
Today, native_sim supports the exact same
:ref:`peripherals and backends as native_posix<native_posix_peripherals>`,
with the only caveat that some of these are, so far, only available when compiling with the
host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`).
.. csv-table:: Drivers/backends vs libC choice
:header: Driver class, driver name, driver kconfig, libC choices
adc, ADC emul, :kconfig:option:`CONFIG_ADC_EMUL`, all
bluetooth, userchan, :kconfig:option:`CONFIG_BT_USERCHAN`, host libC
can, can native posix, :kconfig:option:`CONFIG_CAN_NATIVE_POSIX_LINUX`, host libC
console backend, POSIX arch console, :kconfig:option:`CONFIG_POSIX_ARCH_CONSOLE`, all
display, display SDL, :kconfig:option:`CONFIG_SDL_DISPLAY`, host libC
entropy, native posix entropy, :kconfig:option:`CONFIG_FAKE_ENTROPY_NATIVE_POSIX`, host libC
eprom, eprom emulator, :kconfig:option:`CONFIG_EEPROM_EMULATOR`, host libC
ethernet, eth native_posix, :kconfig:option:`CONFIG_ETH_NATIVE_POSIX`, host libC
flash, flash simulator, :kconfig:option:`CONFIG_FLASH_SIMULATOR`, host libC
flash, host based flash access, :kconfig:option:`CONFIG_FUSE_FS_ACCESS`, host libC
gpio, GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL`, all
gpio, SDL GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL_SDL`, host libC
i2c, I2C emulator, :kconfig:option:`CONFIG_I2C_EMUL`, all
input, input SDL touch, :kconfig:option:`CONFIG_INPUT_SDL_TOUCH`, host libC
log backend, native backend, :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX`, all
rtc, RTC emul, :kconfig:option:`CONFIG_RTC_EMUL`, all
serial, uart native posix/PTTY, :kconfig:option:`CONFIG_UART_NATIVE_POSIX`, host libC
serial, uart native TTY, :kconfig:option:`CONFIG_UART_NATIVE_TTY`, host libC
spi, SPI emul, :kconfig:option:`CONFIG_SPI_EMUL`, all
system tick, native_posix timer, :kconfig:option:`CONFIG_NATIVE_POSIX_TIMER`, all
tracing, Posix tracing backend, :kconfig:option:`CONFIG_TRACING_BACKEND_POSIX`, host libC
usb, USB native posix, :kconfig:option:`CONFIG_USB_NATIVE_POSIX`, host libC

View file

@ -0,0 +1,302 @@
/*
* Copyright (c) 2014 Wind River Systems, Inc.
* Copyright (c) 2017 Oticon A/S
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*
* SW side of the IRQ handling
*/
#include <stdint.h>
#include <zephyr/irq_offload.h>
#include <zephyr/kernel_structs.h>
#include "kernel_internal.h"
#include "kswap.h"
#include "irq_ctrl.h"
#include "posix_core.h"
#include <zephyr/sw_isr_table.h>
#include "soc.h"
#include <zephyr/tracing/tracing.h>
#include "irq_handler.h"
#include "board_soc.h"
#include "nsi_cpu_if.h"
typedef void (*normal_irq_f_ptr)(const void *);
typedef int (*direct_irq_f_ptr)(void);
static struct _isr_list irq_vector_table[N_IRQS] = { { 0 } };
static int currently_running_irq = -1;
static inline void vector_to_irq(int irq_nbr, int *may_swap)
{
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_PM
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;
}
}
sys_trace_isr_exit();
}
/**
* 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)
{
uint64_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.cpus[0].nested == 0) {
may_swap = 0;
}
_kernel.cpus[0].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.cpus[0].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
*/
if (may_swap
&& (hw_irq_ctrl_get_cur_prio() == 256)
&& (_kernel.ready_q.cache != _current)) {
(void)z_swap_irqlock(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 nsif_cpu0_irq_raised_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);
}
/**
* @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.
*/
void posix_irq_unlock(unsigned int key)
{
hw_irq_ctrl_change_lock(key);
}
void posix_irq_full_unlock(void)
{
hw_irq_ctrl_change_lock(false);
}
void posix_irq_enable(unsigned int irq)
{
hw_irq_ctrl_enable_irq(irq);
}
void posix_irq_disable(unsigned int irq)
{
hw_irq_ctrl_disable_irq(irq);
}
int posix_irq_is_enabled(unsigned int irq)
{
return hw_irq_ctrl_is_irq_enabled(irq);
}
int posix_get_current_irq(void)
{
return currently_running_irq;
}
/**
* Configure a static interrupt.
*
* posix_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 posix_isr_declare(unsigned int irq_p, int flags, void isr_p(const void *),
const 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.
*/
void posix_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);
}
#ifdef CONFIG_IRQ_OFFLOAD
/**
* Storage for functions offloaded to IRQ
*/
static void (*off_routine)(const void *);
static const void *off_parameter;
/**
* IRQ handler for the SW interrupt assigned to irq_offload()
*/
static void offload_sw_irq_handler(const 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 posix_irq_offload(void (*routine)(const void *), const void *parameter)
{
off_routine = routine;
off_parameter = parameter;
posix_isr_declare(OFFLOAD_SW_IRQ, 0, offload_sw_irq_handler, NULL);
posix_irq_enable(OFFLOAD_SW_IRQ);
posix_sw_set_pending_IRQ(OFFLOAD_SW_IRQ);
posix_irq_disable(OFFLOAD_SW_IRQ);
}
#endif /* CONFIG_IRQ_OFFLOAD */

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2017 Oticon A/S
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BOARDS_POSIX_NATIVE_SIM_IRQ_HANDLER_H
#define BOARDS_POSIX_NATIVE_SIM_IRQ_HANDLER_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void posix_sw_set_pending_IRQ(unsigned int IRQn);
void posix_sw_clear_pending_IRQ(unsigned int IRQn);
#ifdef __cplusplus
}
#endif
#endif /* BOARDS_POSIX_NATIVE_SIM_IRQ_HANDLER_H */

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "posix_native_task.h"
#include "nsi_timer_model.h"
#if defined(CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME)
static void set_realtime_default(void)
{
hwtimer_set_real_time_mode(true);
}
NATIVE_TASK(set_realtime_default, PRE_BOOT_1, 0);
#endif /* CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME */

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* This file provides in native_sim a set of APIs the native_posix board provided
* to allow building the native_posix drivers or applications which depended
* on those.
* Note that all these APIs should be considered deprecated in native_sim, as this
* exists solely as a transitional component.
*/
#ifndef BOARDS_POSIX_NATIVE_SIM_NATIVE_POSIX_COMPAT_H
#define BOARDS_POSIX_NATIVE_SIM_NATIVE_POSIX_COMPAT_H
#include <stdint.h>
#include <zephyr/toolchain.h>
#include "nsi_hw_scheduler.h"
#ifdef __cplusplus
extern "C" {
#endif
static ALWAYS_INLINE void hwm_find_next_timer(void)
{
nsi_hws_find_next_event();
}
static ALWAYS_INLINE uint64_t hwm_get_time(void)
{
return nsi_hws_get_time();
}
#ifdef __cplusplus
}
#endif
#endif /* BOARDS_POSIX_NATIVE_SIM_NATIVE_POSIX_COMPAT_H */

View file

@ -0,0 +1,7 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "../native_posix/native_posix.dts"

View file

@ -0,0 +1,20 @@
identifier: native_sim
name: Native Simulation port - 32-bit
type: native
simulation: native
arch: posix
ram: 65536
flash: 65536
toolchain:
- host
- llvm
supported:
- can
- eeprom
- netif:eth
- usb_device
- adc
- i2c
- spi
- gpio
- rtc

View file

@ -0,0 +1,7 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "native_sim.dts"

View file

@ -0,0 +1,18 @@
identifier: native_sim_64
name: Native Simulation port - 64-bit
type: native
simulation: native
arch: posix
ram: 65536
flash: 65536
toolchain:
- host
- llvm
supported:
- can
- eeprom
- netif:eth
- usb_device
- adc
- gpio
- rtc

View file

@ -0,0 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
CONFIG_SOC_POSIX=y
CONFIG_BOARD_NATIVE_SIM_64BIT=y
CONFIG_CONSOLE=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=1000000

View file

@ -0,0 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
CONFIG_SOC_POSIX=y
CONFIG_BOARD_NATIVE_SIM_32BIT=y
CONFIG_CONSOLE=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=1000000

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <soc.h>
#include <posix_native_task.h>
#include <nsi_cpu_if.h>
void nsif_cpu0_pre_cmdline_hooks(void)
{
run_native_tasks(_NATIVE_PRE_BOOT_1_LEVEL);
}
void nsif_cpu0_pre_hw_init_hooks(void)
{
run_native_tasks(_NATIVE_PRE_BOOT_2_LEVEL);
}
void nsif_cpu0_boot(void)
{
run_native_tasks(_NATIVE_PRE_BOOT_3_LEVEL);
posix_boot_cpu();
run_native_tasks(_NATIVE_FIRST_SLEEP_LEVEL);
}
void nsif_cpu0_cleanup(void)
{
posix_soc_clean_up();
}
void nsif_cpu0_irq_raised(void)
{
posix_interrupt_raised();
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "nsi_cpu_es_if.h"
/*
* This file provides the interfaces the POSIX architecture and soc_inf
* expect from all boards that use them
*/
void posix_exit(int exit_code)
{
nsi_exit(exit_code);
}
void posix_vprint_error_and_exit(const char *format, va_list vargs)
{
nsi_vprint_error_and_exit(format, vargs);
}
void posix_vprint_warning(const char *format, va_list vargs)
{
nsi_vprint_warning(format, vargs);
}
void posix_vprint_trace(const char *format, va_list vargs)
{
nsi_vprint_trace(format, vargs);
}
void posix_print_error_and_exit(const char *format, ...)
{
va_list variable_args;
va_start(variable_args, format);
nsi_vprint_error_and_exit(format, variable_args);
va_end(variable_args);
}
void posix_print_warning(const char *format, ...)
{
va_list variable_args;
va_start(variable_args, format);
nsi_vprint_warning(format, variable_args);
va_end(variable_args);
}
void posix_print_trace(const char *format, ...)
{
va_list variable_args;
va_start(variable_args, format);
nsi_vprint_trace(format, variable_args);
va_end(variable_args);
}
int posix_trace_over_tty(int file_number)
{
return nsi_trace_over_tty(file_number);
}
uint64_t posix_get_hw_cycle(void)
{
return nsi_hws_get_time();
}

View file

@ -0,0 +1,18 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BOARDS_POSIX_NATIVE_SIM_TIMER_MODEL_H
#define BOARDS_POSIX_NATIVE_SIM_TIMER_MODEL_H
/*
* To support the native_posix timer driver
* we provide a header with the same name as in native_posix
*/
#include "nsi_hw_scheduler.h"
#include "nsi_timer_model.h"
#include "native_posix_compat.h"
#endif /* BOARDS_POSIX_NATIVE_SIM_TIMER_MODEL_H */

View file

@ -55,6 +55,7 @@ SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,)
#include <snippets-ram-sections.ld>
#include <zephyr/arch/posix/native_tasks.ld>
#include <zephyr/arch/posix/native_sim_interface.ld>
/* Located in generated directory. This file is populated by the
* zephyr_linker_sources() Cmake function.

View file

@ -0,0 +1,11 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
SECTION_PROLOGUE (.native_sim_if,,)
{
KEEP(*(.native_sim_if));
KEEP(*(.native_sim_if.*));
}