| .. _bsim boards: |
| |
| Bsim boards |
| ########### |
| |
| This page covers the design, architecture and rationale, of the |
| :ref:`nrf52_bsim<nrf52_bsim>` board and other similar bsim boards. |
| Particular details on the nRF52 simulation board, including how to use it, |
| can be found in that :ref:`board documentation<nrf52_bsim>`. |
| These boards are postfixed with `_bsim` as they use BabbleSim |
| (shortened bsim). |
| |
| .. contents:: |
| :depth: 2 |
| :backlinks: entry |
| :local: |
| |
| .. _BabbleSim: |
| https://BabbleSim.github.io |
| |
| .. _EDTT: |
| https://github.com/EDTTool/EDTT |
| |
| .. _Architecture of HW models used for FW development and testing: |
| https://babblesim.github.io/arch_hw_models.html |
| |
| Overall objective |
| ***************** |
| |
| Bsim boards main purpose is to be test-benches for |
| integration testing of embedded code on workstation/simulation. |
| Integration testing in the sense that the code under test will, at the very |
| least, run with the Zephyr RTOS just like for any other |
| :ref:`POSIX arch based board<posix_arch_rationale>`, but in addition these |
| will include some HW models which, to some degree, pretend to be the real |
| embedded HW. |
| |
| These tests are run in workstation, that is, without using real embedded HW. |
| The intention being to be able to run tests much faster than real time, |
| without the need for real HW, and in a deterministic/reproducible fashion. |
| |
| Unlike native_posix, bsim boards do not interact directly with any host |
| peripherals, and their execution is independent of the host load, or timing. |
| |
| |
| Different types of tests and how the bsim boards relate to them |
| =============================================================== |
| |
| With the POSIX architecture we provided an overall |
| :ref:`comparison of what the POSIX arch provides vs other options<posix_arch_compare>`. |
| That comparison applies fully to these boards, but in this section we expand |
| further on the differences, benefits and drawbacks of different testing |
| methodologies normally employed by embedded SW developers and how they relate |
| to these boards. |
| |
| - Unit tests: |
| Typical unit tests frameworks provide unit testing |
| support which covers a different need: testing a component in isolation. |
| Zephyr provides a unit testing target (unit_testing) which is not related to |
| these bsim boards. |
| - Integration tests on real HW: Allows testing with the real SW |
| components that may be too dependent on the exact HW particularities, and |
| possibly without any changes compared to the final solution. |
| As such can provide better integration coverage than simulation ins ome cases, |
| but at the expense of slower execution, needing the real HW setups, |
| test in general not being reproducible, and in many cases failures |
| not being easy to debug. |
| They otherwise serve a very similar purpose to simulation integration tests. |
| - Integration tests on workstation (what the POSIX arch and these boards enable) |
| |
| - Using bsim boards: Allow testing the embedded SW (or a subset), including |
| the OS, models of peripherals etc. By testing them in conjunction, |
| it is possible to test the components interactions and their integration. |
| - Using bsim boards with the BabbleSim Physical layer simulation allows |
| testing how several devices would interact with each other. |
| For ex. how a left and a right earbud synchronize and exchange data and |
| audio over their radio link, and how they interact with a mobile phone. |
| - Using bsim boards, and the `EDTT`_ framework: With the EDTT framework we can |
| test the embedded code under test while controlling the test from external |
| python test scripts. This is supported by compiling the embedded code with |
| an special driver that handles the EDTT communication (its RPC transport) |
| and an embedded application that handles the RPC calls themselves, while |
| the python test scripts provide the test logic. |
| - Using Zephyr's native_posix board: It also allows integration testing of |
| the embedded code, but without any specific HW. In that way, many embedded |
| components which are dependent on the HW would not be suited for testing in |
| that platform. Just like the bsim boards, this Zephyr target board can |
| be used with or without Zephyr's ztest system and twister. |
| The native_posix board shares the :ref:`POSIX architecture<Posix arch>` |
| with the bsim boards. |
| |
| - Zephyr's ztest infrastructure and Zephyr's twister: |
| Based on dedicated embedded test applications build with the code under test. |
| The embedded test application is responsible for driving the tests and check |
| the results on its own, and provide a test result to a PC which directs the |
| test. |
| Originally used as a framework for integration testing on target, |
| with a very dedicated test application, |
| these are fully supported with the bsim boards. |
| |
| Design |
| ****** |
| |
| Layering: Zephyr's arch, soc and board layers |
| ============================================= |
| |
| The basic architecture layering of these boards is as follows: |
| |
| - The architecture, SOC and board components of Zephyr are replaced with |
| simulation specific ones. |
| - The architecture (arch) is the Zephyr :ref:`POSIX architecture<Posix arch>` |
| layer. |
| The SOC layer is the soc_inf layer. And the board layer is dependent on |
| the specific device we are simulating. |
| - The POSIX architecture provides an adaptation from the Zephyr arch API |
| (which handles mostly the thread context switching) to the Linux kernel. |
| See :ref:`POSIX arch architecture<posix_arch_architecture>` |
| - The soc_inf layer provides the overall CPU "simulation" and the handling of |
| control between the "CPU simulation" (Zephyr threads) and the HW models thread |
| ( See `Threading`_ ) |
| - The board layer provides all SOC/ IC specific content, including |
| (or linking to) HW models, IRQ handling, busy wait API |
| (see :ref:`posix_busy_wait<posix_busy_wait>`), and Zephyr's printk backend. |
| Note that in a normal Zephyr target interrupt handling and a custom busy wait |
| would be provided by the SOC layer, but abusing Zephyr's layering, and for the |
| soc_inf layer to be generic, these were delegated to the board. |
| The board layer also provides the :c:func:`main` entry point for the linux |
| program, command line argument handling, the overall time scheduling of |
| the simulated device, and other test specific functionality like bs_tests |
| hooks, trace control, etc. |
| Note that the POSIX arch and soc_inf expect a set of APIs being provided by |
| the board. This includes the busy wait API, a basic tracing API, the interrupt |
| controller and interrupt handling APIs, :c:func:`posix_exit`, |
| and :c:func:`posix_get_hw_cycle` (see posix_board_if.h and posix_soc_if.h ). |
| |
| .. figure:: layering.svg |
| :align: center |
| :alt: Zephyr layering in native & bsim builds |
| :figclass: align-center |
| |
| Overall architecture in a Zephyr application in an embedded target vs a bsim |
| target |
| |
| Important limitations |
| ===================== |
| |
| All native and bsim boards share the same set of |
| :ref:`important limitations which<posix_arch_limitations>` |
| are inherited from the POSIX arch and soc_inf design. |
| |
| .. _Threading: |
| |
| Threading and overall scheduling of CPU and HW models |
| ===================================================== |
| |
| The threading description, as well as the general SOC and board architecture |
| introduced in |
| :ref:`POSIX arch architecture<posix_arch_architecture>` |
| apply to the bsim boards. |
| |
| Moreover in |
| `Architecture of HW models used for FW development and testing`_ |
| more details on the HW models and their scheduling are provided. |
| |
| Time and the time_machine |
| ========================= |
| |
| Simulated time in bsim boards is in principle fully decoupled from |
| real wall-clock time. As described in |
| :ref:`POSIX arch architecture<posix_arch_architecture>`, |
| simulated time is advanced |
| as needed to the next scheduled HW event, and does not progress while |
| the simulated CPU is executing code. |
| |
| In general simulation time will pass much faster than real time, |
| and the simulation results will not be affected in any way by the |
| load of the simulation host or by the process execution being "paused" |
| in a debugger or similar. |
| |
| The time_machine component provides the overall HW event time loop |
| required by the HW models, which consists of a very simple |
| "search for next event", "advance time to next event and execute it" loop, |
| together with an API for components that use it to inform about their events |
| timers having been updated. Events are defined at design time, |
| they are not registered dynamically for simplicity and speed. |
| |
| Use of babblesim components: tracing, random number generation, logging activity |
| ================================================================================ |
| |
| The same considerations as for the HW models apply to the bsim boards, see |
| `Architecture of HW models used for FW development and testing`_. |
| |
| The communication between a Zephyr device and other simulated devices is |
| handled over the bsim libPhyCom libraries. For the radio activity the figure |
| below represents this communication: |
| |
| |
| .. figure:: Zephyr_and_bsim.svg |
| :align: center |
| :alt: Communication between a Zephyr device and other simulated devices |
| :figclass: align-center |
| |
| Communication between a Zephyr device and other simulated devices |
| |
| Test code may also communicate with other devices' test code using the bsim |
| backchannels. These provide a direct, reliable pipe between devices' test code |
| can use to exchange data. |
| |
| |
| About using Zephyr APIs |
| ======================= |
| |
| Note that even though bsim board code is linked with the Zephyr kernel, |
| one should in general not call Zephyr APIs from the board code itself. |
| In particular, one should not call Zephyr APIs from the original/HW models |
| thread as the Zephyr code would be called from the wrong context, |
| and will with all likelihood cause all kind of difficult to debug issues. |
| |
| In general board code should be considered as lower level than the Zephyr OS, |
| and not dependent on it. |
| For example, board code should not use the printk API as that anyhow would |
| result in a call back into the board code (the bsim specific printk backend) |
| which relies on the bs_trace API. Instead, for tracing the bs_trace API |
| should be used directly. |
| The same applies to other Zephyr APIs, including the entropy API, etc. |
| |
| printk and posix_print backend |
| ============================== |
| |
| The bsim board provides a very simple backend for Zephyr's `printk()`, |
| which simply routes the printk strings to the bs_trace bsim API. |
| So printk messages are printed in the console (stdout) together with all |
| other device messages. |
| The board also provides the posix_print API which is expected by the posix ARCH |
| and soc inf code, and which is based on the same bs_trace API. |
| |
| bs_tests |
| ======== |
| |
| The bsim boards provide also the bs_tests facility. |
| |
| This allows tests to be defined (registered), and for each of these tests to |
| use a number of special test hooks which are present only in these simulated |
| targets. |
| |
| These tests are built together with the embedded SW, and are present in the |
| binary but will not be executed by default. |
| From the command line the user can query what tests are present, and select |
| which test (if any) should be executed. When a test is selected its registered |
| callbacks are assigned to the respective hooks. |
| |
| There is a set of one time hooks at different levels of initialization of the HW |
| and Zephyr OS, a hook to process possible command line arguments, and, a hook |
| that can be used to sniff or capture interrupts. |
| bs_tests also provides a hook which will be called from the embedded application |
| :c:func:`main`, but this will only work if the main application supports it, |
| that is, if the main app is a version for simulation which calls |
| :c:func:`bst_main` when running in the bsim board. |
| |
| Apart from these hooks, the bs_tests system provides facilities to build a |
| dedicated test "task". This will be executed in the HW models thread context, |
| but will have access to all SW variables. This task will be driven with a |
| special timer which can be configured to produce either periodic or one time |
| ticks. When these ticks occur a registered test tick function will be called. |
| This can be used to support the test logic, like run checks or perform actions |
| at specific points in time. This can be combined with Babblesim's tb_defs macros |
| to build quite complex test tasks which can wait for a given amount of time, |
| for conditions to be fulfilled, etc. |
| |
| Note: When writing the tests with bs_tests one needs to be aware that other |
| bs tests will probably be built with the same application, and that therefore |
| the tests should not be registering initialization or callback functions using |
| NATIVE_TASKS or Zephyr's PRE/POST kernel driver initialization APIs as this |
| will execute even if the test is not selected. |
| Instead the equivalent bs_tests provided hooks should be used. |
| |
| Command line argument parsing |
| ============================= |
| |
| bsim boards need to handle command line arguments. There are several sets of |
| arguments: |
| |
| - Basic arguments: to enable selecting things like trace verbosity, random seed, |
| simulation device number and simulation id (when connected to a phy), etc. |
| This follow as much as possible the same convention as other bsim |
| devices to ease use for developers. |
| - The HW models command line arguments: The HW models will expose which |
| arguments they need to have processed, but the bsim board as actual |
| integrating program ensures they are handled. |
| - Test (bs_tests) control: To select a test, print which are available, and |
| pass arguments to the tests themselves. |
| |
| Command line argument parsing is handled by using the bs_cmd_line component |
| from Babblesim's base/libUtilv1 library. And basic arguments definitions that |
| comply with the expected convention are provided in bs_cmd_line_typical.h. |
| |
| Other considerations |
| ==================== |
| |
| - Endianness: Code will be built for the host target architecture, which is |
| typically x86. x86 is little endian, which is typically also the case for the |
| target architecture. If this is not the case, embedded code which works in one |
| may not work in the other due to endianness bugs. |
| Note that Zephyr code is be written to support both big and little endian. |
| - WordSize: The bsim targets, as well as normal embedded targets are 32 bit |
| targets. In the case of the bsim targets this is done by explicitly targeting |
| x86 (ILP32 ABI) instead of x86_64. This is done purposefully to provide more |
| accurate structures layout in memory and therefore better reproduce possible |
| issues related to access to structures members or array overflows. |