Oberon RTK

Testing Overview

Overview of spec-based automated testing for Astrobe Oberon programs

The gdbtestengine provides spec-based automated testing for Astrobe Oberon programs running on hardware. Declarative test specifications describe what to check or trace at specific procedure entry points. The engine runs inside GDB, sets breakpoints, collects values from registers and memory, and produces a timestamped report.

Testing requires an ELF file with DWARF debug data, built by gen-rdb and make-elf.

Workflow

The preparation steps are:

  1. compile and link with Astrobe (produces .bin, .lst, .map)
  2. gen-rdb Prog.map – generates the rdb/ directory
  3. make-elf Prog.bin --debug – builds the ELF with debug data
  4. start a GDB server – OpenOCD, matched to your debug probe

Quick Start

  1. write a .spec file in rdb-gdb-tests/specs/
  2. connect GDB to the target:
arm-none-eabi-gdb-py3 Prog.elf
(gdb) target extended-remote localhost:3333
(gdb) load
  1. run the test:
(gdb) set environment SPEC init-test.spec
(gdb) run-test

The run-test command is a GDB alias defined in ~/.gdbinit that sources the gdbtestengine. Reports are written to rdb-gdb-tests/reports/.

For batch execution (no interactive prompt):

arm-none-eabi-gdb-py3 -batch
    -ex "target extended-remote localhost:3333" \
    -ex "load" \
    -ex "set environment SPEC init-test.spec" \
    -ex "run-test" Prog.elf

Example Spec

A spec file that checks argument values at procedure entry points during the program's initialisation phase:

-- SignalSync init-phase test spec
-- Tests known argument values at procedure entry points.

option timeout = 15
option max-hits = 20

-- Stop after seeing all init calls
stop after 10 hits

-- LED.Set is called with {LED.Pico} = 128 = 0x80
proc LED.Set
  at entry
    check arg leds = 128

-- Kernel.SetPeriod is called twice during init:
--   SetPeriod(50, 0)    -- T0period=50, startAfter=0
--   SetPeriod(100, 100) -- T3period=100, startAfter=100
-- We trace both args to see the values.
proc Kernel.SetPeriod
  at entry
    trace arg period
    trace arg startAfter

-- Cores.CoreId is a leaf proc with no args.
proc Cores.CoreId
  at entry
    trace local cid

Key elements:

  • option – configure timeout and maximum breakpoint hits
  • stop after N hits – terminate the test after N breakpoint hits
  • proc Module.Procedure – select a procedure
  • at entry – location within the procedure
  • check – verify a value (PASS/FAIL)
  • trace – record a value (always PASS)

The spec language supports comparison operators (=, #, >, <, >=, <=), cross-module constants, memory reads with field and bit-range access, signed/unsigned control, NIL, and sentinel conditions for controlling test execution windows.

The spec grammar covers the spec language in detail.

Testing Approach

The engine uses a descriptive, parallel model: the spec declares all procedures and checks up front, and the engine sets breakpoints on all of them simultaneously. The program runs freely; breakpoints fire in whatever order the program flow dictates. This means the spec writer does not need to predict execution order – the engine handles any interleaving.

Because hardware breakpoint slots are limited (typically 4-8 on Cortex-M), the engine rotates breakpoints automatically when more procedures are instrumented than slots are available. Each rotation replaces one breakpoint with another, so all procedures are eventually covered. This is transparent to the spec writer.

Sentinel directives (start, stop) control the execution window – the phase of the program during which checks and traces are active. This allows targeting specific execution phases (initialisation, steady state, shutdown) without filtering unrelated hits.

Future extensions will add trigger conditions based on the call stack, sequential test ordering, and the composition of individual specs into test suites.

Constant Resolution

Spec files can reference exported Oberon constants using the Module.Constant syntax. The engine resolves these from the .alst files at start-up. Constants defined as literals or as expressions within a single module resolve correctly. Constants that depend on cross-module references in their defining expression (eg. DEV0.FLASH_ACR = FLASH_BASE + 000H where FLASH_BASE comes from another module) may not resolve. In such cases, use the constant from the module that owns the base definition.

GDB Server Scripts

Ready-made scripts for starting GDB servers are in <repo>/tools/server-scripts/. Each script has .sh and .cmd variants. Start the appropriate server before running tests. See External Tools for the full list and installation details.

Last updated: 11 March 2026