User guide¶
How to run and embed the Tero emulator. This is the User Manual:
its audience is people who run tero-emu or link tero_runtime into
their own program. For how the emulator works internally, see the
architecture overview (the Developer Manual).
Map of this guide¶
| Page | What it covers |
|---|---|
| CLI reference | Every tero-emu flag — meaning, default, when to use it. |
| Embedding as a library | Emulator::create, the lifecycle, load_elf, run_for/run_until, the memory API, injecting services, the GDB stub. |
| Configuration | Every EmulatorConfig field — meaning, default, effect; the recipe pattern. |
| UART and console | ICharacterDevice, StdoutCharDevice, the APBUART, multiple UARTs, capturing and routing output. |
| Debugging with GDB | Attaching a GDB front-end, RTEMS thread-awareness, supported RSP packets, behaviour under JIT/Switch/MultiThread. |
| Hello World guide | Compiling an RTEMS guest from scratch with RCC + mkprom2. |
| GR712RC reference | The GR712RC memory map, peripheral instances, and IRQ assignments. |
If you are brand new, start with the getting-started section (install, build, first boot) and come back here for depth.
The shape of using Tero¶
Whether you use the CLI or the library, the flow is the same five steps. The CLI just wraps them:
flowchart LR
A["Build an EmulatorConfig<br/>(gr712rc_config / gr740_config<br/>+ overrides)"] --> B["Emulator::create(cfg)"]
B --> C["set_logger / set_uart_character_device<br/>(optional)"]
C --> D["initialize()"]
D --> E["load_elf / load_binary"]
E --> F["run_for / run_until<br/>(loop)"]
- Configure by struct. Start from a SoC recipe
(
gr712rc_config()orgr740_config()) and override the fields you care about. There are no config files and no global state — see Configuration. - Create.
Emulator::create(cfg)validates the config and returns aResult<std::unique_ptr<Emulator>>. - Inject services (optional). Replace the default logger, console
UART chardev, or observer — but only before
initialize(). - Initialize. Wires RAM, peripherals, the bus, and (if requested) the GDB stub.
- Load and run.
load_elf()/load_binary(), thenrun_for()orrun_until()in a loop, inspecting theRunResultbetween calls.
Two execution methods, one binary¶
Both execution methods are compiled into every build and selected at
runtime by EmulatorConfig::translation (default true):
- Binary translation (JIT) — decode each block to an architecture- neutral IR, run it through a tiered LLVM JIT, with the IR interpreter as a fallback. This is the fast default.
- Switch interpreter — fetch-decode-execute one instruction at a time; the reference path and correctness oracle.
You never rebuild to switch. The library exposes this as a config field;
the CLI exposes diagnostic flags (--no-translation, --ir-interp-only).
See Execution model and
IR and LLVM JIT for how it works.
Two execution modes (host threading)¶
Orthogonal to the execution method, EmulatorConfig::execution_mode
selects how simulated cores map onto host threads:
- SingleThread (default) — all cores advance cooperatively in one host thread (round-robin quantum). SMP2-compatible; zero locking overhead.
- MultiThread — each simulated core runs on its own host thread, for
standalone throughput. CLI flag:
--mt.
Where to go from here¶
- Running from the shell → CLI reference.
- Embedding in C++ → Embedding as a library.
- Tuning behaviour → Configuration.
- Console I/O → UART and console.
- Debugging → Debugging with GDB.