Runtime Library — Overview
ARMbasic is a compiler: the PC-side ARMbasic.exe translates BASIC
source into native ARM machine code that runs directly on the target.
Whenever a compiled program needs a non-trivial primitive — print,
wait, flash_write, integer divide, string concatenation, float math
— the emitted code does a BL straight into a fixed flash address in
the firmware. The collection of small helper functions those calls land
on is the runtime library.
This page describes how the runtime is organised; the rest of the Runtime Library section documents each individual call.
Calling convention — global register variables
Every helper takes no formal arguments and returns no value. Instead, six global registers hold the BASIC machine state, and they are live across the whole program:
| Register | Variable | Role |
|---|---|---|
r4 | reg_lindex | l-value index — array subscript, IO pin number, baud-rate slot, destination of *x = … |
r5 | ptr_var_seg | base offset into the variable segment for the current scope |
r6 | reg_operand / f_operand | right-hand operand of a binary operation (typed int or float depending on the helper) |
r7 | reg_accum / f_accum | accumulator — input on entry, result on return |
r9 | reg_next | a "second value" slot — flash source pointer, memcopy source, etc. |
r11 | reg_strscratch | scratch — string source pointer in LEFT$/RIGHT$ |
So the integer divide helper is, in C, simply
reg_accum = reg_accum / reg_operand; — no parameters, no return; the
compiled code set up r6/r7 before the BL and reads r7 after.
This is what makes the helpers so small and cheap to call.
The dispatch table — f_table[]
The firmware exposes a fixed-format f_table[] array at a known flash
location. Slots 0..7 are metadata (version, count, CPU code, code
start, variable base, board type, …); the remaining slots are 1:1
with runtime functions. The PC compiler:
- Pings the live board over UART and reads
f_table[]. - For each BASIC primitive, looks up its slot, computes the absolute
flash address, and emits
BL <addr>. - Downloads the compiled hex into the user-code area and runs it.
Nothing in the firmware ever does a runtime dispatch — the calls are direct, baked in at compile time. The table order is version-locked since version 6.08; new primitives can only be appended.
Function groups
Integer arithmetic and comparison
/, MOD, AND, OR, XOR, ABS, the six relational operators,
logical NOT, and the n-bit reverse used by REV.
Floating-point arithmetic and comparison
+, -, *, /, unary minus, the six relational operators, plus
the four int↔float conversion bridges. f_accum and f_operand are
the same r7 / r6 registers, reinterpreted as float.
String building
A 256-byte STR_ACCUM scratch buffer at the top of the variable
segment holds the in-progress string. Helpers append to it
(f_addstr, f_addsbyte, f_hex2str, f_dec2str, f_left,
f_right), copy it out to a destination (f_savestr), or parse it
back to a number (f_str2dec). f_strcmp, f_strlen, and the
SPRINTF family round out the string surface.
Print / format
Number print, character print, CR / TAB, string print, float print
(with optional rounding), and the BASIC-level SPRINTF wrappers.
Internal flags select the BASIC %G format and round-half-up rules
inside the shared printf implementation.
Wait / timer
WAIT, WAITmicro, TIMER, and SETTIMER. The microsecond tick is
maintained by cpu_micros() driven from SysTick (or TIMER0 on legacy
parts).
GPIO
IN(pin), OUT pin = …, DIR(pin), and the direction setter.
The runtime calls thin per-CPU bridges (cpu_inbit, cpu_outbit,
cpu_rddirbit, cpu_wrdirbit) so the same BASIC code works
unchanged across LPC, nRF, and RP2040 targets.
UART
BAUD, RXD, TXD, and TXFREE map to UART_init /
cpu_getc / cpu_putc / uart_txfree — again, per-CPU
implementations behind a common interface.
ADC
A single weak entry point that each per-CPU file overrides. On parts without an ADC the call returns 0.
Flash write
FWRITE is gated against writing into the code region, tracks the
last sector erased so consecutive writes within one sector skip the
erase step, and then calls the platform-specific WriteFlash.
Memory copy
FREAD is a plain bytewise memcpy driven by the (r9, r4,
r7) register triple — destination, source, and count.
Interrupts
INTSW(0/1) flips the I bit of CPSR via enableIRQ /
disableIRQ.
Sort
SORT calls a recursive quicksort over reg_lindex (array base) for
reg_accum elements.
Line input and program lifecycle
BASICgetln reads a line from the console and echoes it back —
unless the first character is a download / control marker
(:, >0, !, @, ^, "), in which case the line is consumed
silently. Program exit unwinds the saved SP / LR that the
goForIt trampoline stashed on entry and returns control from the
running BASIC program back to the firmware shell.
Variable storage
g_var_seg[] is the single backing array for every BASIC variable
and array. The compiler emits offsets into this array; the firmware
just provides the address. The last 256 bytes are reserved as the
string accumulator (STR_ACCUM).
See also
The pages that follow under Runtime Library document each user-visible call in detail: time functions, math functions, floating point, byte/file/string helpers.