/QEMU 4.0 adds micro:bit emulation support

QEMU 4.0 adds micro:bit emulation support

22 May 2019

micro:bit emulation support is available from QEMU 4.0
onwards and can be used for low-level software testing and development. Unlike
existing micro:bit simulators, QEMU performs full-system emulation and actually
runs the same ARM code as the real hardware. This blog post explains what
full-system emulation means and why QEMU is now a useful tool for developing
micro:bit software.

The micro:bit is a tiny ARM board
designed for teaching. It is increasingly being used around the world to
expose children to computers, programming, and electronics in a low-cost way
with an active online community that shares project ideas, lesson plans, and
programming tips.

micro:bit board

Simulators and emulators

Simulators are used for many tasks from mobile app development to
performance analysis of computer hardware. It is possible to develop code
using a simulator without having access to real hardware. Oftentimes using a
simulator is more convenient than flashing and debugging programs on real
hardware.

Emulators allow programs written for one computer system to run on a
different computer system. They use techniques like machine code
interpreters
and
just-in-time
compilers
to execute
guest programs that do not run natively on the host computer. Each CPU
instruction must be correctly implemented by the emulator so it can run guest
software.

How existing micro:bit simulators work

Simulators can be implemented at various layers in the software stack. The
MakeCode editor for JavaScript
development includes a micro:bit simulator:

MakeCode editor

This simulator does not execute any ARM code and is therefore not running
the same CPU instructions as a real micro:bit. Instead it reuses the JavaScript
engine already available in your web browser to execute micro:bit JavaScript
programs. This is achieved by providing the micro:bit JavaScript APIs that
micro:bit programs expect. The programs don’t need to know whether those APIs
are implemented by the real micro:bit software stack or whether they are
actually calling into the MakeCode simulator.

In the screenshot above the micro:bit program calls showString("Hello
world!")
and this becomes a call into the MakeCode simulator code to
render images of LEDs in the web browser. On real hardware the code path is
different and eventually leads to an LED matrix driver that lights
up the LEDs by driving output pins on the micro:bit board.

Full-system emulation

Unlike the MakeCode simulator, QEMU emulates the micro:bit CPU and boots
from the same ARM code as the real micro:bit board. The simulation happens at
the CPU instruction and hardware interface level instead of at the JavaScript
API level. This is called full-system emulation because the entire
guest software environment is present.

What are the advantages of full-system emulation?

  • Programs written in any language can run (MicroPython, mbed C/C++, etc)
  • Boot, device driver, and language run-time code can be tested
  • Bugs in lower layers of the software stack can be reproduced
  • CPU architecture-specific bugs can be reproduced (stack and memory corruption bugs)
  • A debugger can be connected to inspect the entire software stack

The main disadvantage of full-system emulation is that the performance
overhead is higher since simulation happens at the CPU instruction level.
Programs consist of many CPU instructions so the task of emulation is
performance-sensitive. Luckily the micro:bit’s CPU is much less powerful than
CPUs available in our laptops and desktops, so programs execute at a reasonable
speed.

Running micro:bit programs on QEMU

QEMU emulates the core devices on the micro:bit, including the serial port
(UART) and timers. This is enough for developing and testing low-level
software but does not offer the LEDs, radio, and other devices that most
micro:bit programs rely on. These devices might be emulated by QEMU in the
future, but for now the main use of QEMU is for developing and testing
low-level micro:bit code.

To run test.hex:

$ qemu-system-arm -M microbit -device loader,file=test.hex -serial stdio

Any output written to the serial port is printed to the terminal by QEMU.

Debugging micro:bit programs with QEMU and GDB

QEMU has GDB guest debugging support. This means GDB can connect to QEMU in
order to debug the guest software. This is similar to debugging a real system
over JTAG, except no hardware is necessary!

Connect with GDB to debug the guest:

$ qemu-system-arm -M microbit -device loader,file=test.hex -s
$ gdb
(gdb) target remote tcp:127.0.0.1:1234
(gdb) x/10i $pc
=> 0x161c4:	ldr	r3, [r4, #0]
   0x161c6:	cmp	r3, #0
   0x161c8:	beq.n	0x161d2
   0x161ca:	ldr	r3, [pc, #48]	; (0x161fc)
   0x161cc:	ldr	r3, [r3, #0]
   0x161ce:	cmp	r3, #0
   0x161d0:	bne.n	0x161d8
   0x161d2:	movs	r0, #6
   0x161d4:	bl	0x16160
   0x161d8:	ldr	r0, [r4, #0]

Having a debugger is very powerful. QEMU can also load ELF files in
addition to the popular .hex files used for micro:bit programs. ELF files can
contain debugging information that enables source-level debugging so GDB can
display function and variable names as well as listing the source code instead
of showing assembly instructions.

Conclusion

QEMU now offers a platform for developing and testing micro:bit programs.
It is open to future extension, hopefully to emulate more devices and offer
a graphical user interface.

micro:bit emulation was contributed by Julia Suvorova and Steffen Görtz as
part of their Outreachy and Google Summer of Code internships with QEMU. Jim
Mussared, Joel Stanley, and Stefan Hajnoczi acted as mentors and contributed
patches as well.