Migrating from TEMU 4 to TEMU 5

TEMU 5 is a major version, so interfaces deprecated during the TEMU 4 series have been removed. This guide is specifically about migration from TEMU 4.6.x to TEMU 5.1. Most .temu scripts and most device models keep working with no or only small changes.

What Changed

Table 1. TEMU 4 to TEMU 5 changes that affect existing setups
Area TEMU 4 TEMU 5

System execution

Machine model (was deprecated)

Removed, scheduler object created with init-scheduler

Embedding applications

Scheduler part of the support library

Separate scheduler and profiler libraries, global scheduler created explicitly

Memory space decode

4-byte granularity

8-byte granularity

Reset

reset is cpu-reset, defaulting to DEFAULT_CPU

reset obj=board0 or reset cpu=cpu0 (no default object) with new reset controllers for multi-core systems

Source level debugging

experimental-debug-* commands

Removed, debugging contexts through the TCF server and the TEMU GUI

GDB server

gdb-server command or GdbServer object

GdbServer object only

Device registers

Experimental temu_addRegisterBank() and temu_addRegister()

Replaced by temu_addMemoryMappedRegister*() and register metadata

Bulk model memory access

MemoryIface (readBytes, writeBytes)

MemoryIface is deprecated, use MemAccessIface transactions

Embedded Python

Python 2.7, ctypes wrappers

Python 3.13, SWIG wrappers

Table 2. Subset of what is new in TEMU 5
Area TEMU 4 TEMU 5

Scheduling

Single-level scheduler (identical to and backwards compatible with the TEMU 4 Scheduler)

Multi-level scheduler with synchronization domains and reverse execution

Board description

sysconfig TEMU scripts

YAML component library (see Components)

Debugging

GDB server

TEMU GUI, TCF and MCP servers, OS awareness

Architectures

SPARC, PowerPC, ARMv7-R

Adds ARM Cortex-M and RISC-V

Scheduling

The Machine model tracked time for a group of processors and was the object that run acted on. It was removed in TEMU 5 and replaced by schedulers. There can only be one scheduler in a simulation.

The machine-reset command is gone, and the DEFAULT_MACHINE variable is no longer consulted by any command. DEFAULT_RUNNABLE still exists, but run with no obj argument runs the scheduler.

A TEMU 4 script that looked like this:

import Machine

Machine.new name=machine0
DEFAULT_RUNNABLE=machine0
DEFAULT_MACHINE=machine0

connect a=machine0.cpus b=cpu0:CpuIface
connect a=machine0.cpus b=cpu1:CpuIface

cpu0.parentTimeSource = machine0
cpu1.parentTimeSource = machine0

machine0.quanta = 10000

becomes, using the single-level scheduler (which already existed in TEMU 4 and if it was already used no changes are needed, using init-scheduler is recommended though):

init-scheduler variant=single-level

sched.set-frequency frequency=cpu0.freq
sched.set-quanta quanta=10000
sched.set-threads threads=1
sched.bind-to-group group=0 cpu=cpu0
sched.bind-to-group group=0 cpu=cpu1

cpu0.parentTimeSource = sched
cpu1.parentTimeSource = sched

init-scheduler creates the scheduler as an object called sched. The variant argument selects the implementation.

Use single-level when porting. It is the TEMU 4 scheduler, and its command surface is unchanged: set-threads, bind-to-group, set-frequency, set-quanta, run and step. Scheduler is a class-name alias for SingleLevelScheduler, Scheduler.new still works.

TEMU 5 also has a second scheduler, selected with multi-level. It adds synchronization domains, which let a multi-core processor stay in one deterministic synchronization domain while running on several host threads, and it is a prerequisite for reverse execution. See Running the Simulated System for how to configure either scheduler, and Emulation Performance for thread count, barrier and affinity choices.

The Machine C API is gone: temu_machineRun(), temu_machineReset() and temu_cpuGetMachine() no longer exist. Use temu_runSecs() to run, and call reset() on the object’s ResetIface to reset.

Library Initialisation

The support library no longer initialises everything, and it no longer creates anything runnable on its own. Scheduling and profiling live in separate libraries which must be initialised after temu_initSupportLib(), and the global scheduler has to be created explicitly.

A TEMU 4 embedder wrote:

#include "temu-c/Support/Init.h"

temu_initPathSupport(argv[0]);
temu_initSupportLib();

The TEMU 5 equivalent is:

#include "temu-c/Support/Init.h"
#include "temu-c/Scheduler/Init.h"

temu_initSupportLib();
temu_initScheduler();
temu_initProfilerLib();

// Create the global scheduler, this replaces the Machine model.
temu_createScheduler(teSV_MultiLevel);

temu_initSupportLib() now calls temu_initPathSupportAuto() itself, so the explicit temu_initPathSupport(argv[0]) call is only needed if the path must be derived from a specific executable.

temu_initSnapshotLib() and temu_initFluxLib() are needed additionally if the application uses snapshots or reverse execution.

Large Memory Transactions

This is the change most likely to alter the behavior of a working model without producing any compiler diagnostic.

A large transaction is one with Size > 3. It carries a pointer in Value rather than a scalar, Size >> 2 gives the number of units and 1 << (Size & 3) the width of each unit.

Processors never emit large transactions. They can happen because of DMA engines in e.g. SpaceWire or Ethernet controllers, or initiated through the TEMU C API. If you never encounter them, then this section does not apply.

The memory space splits a large transaction into unit-sized accesses for any endpoint that does not set LargeTransactions in its capabilities (see temu_MemAccessIface). The splitting rule is the same in TEMU 4 and TEMU 5, but TEMU 4 ignored the capabilities of page-aligned whole-page mappings and always split there. TEMU 5 honours LargeTransactions on every mapping, so a model or bridge that declares it now receives large transactions it never saw in TEMU 4.

What changed is the granularity at which the memory space decodes an address to a mapping. TEMU 4 resolved within a partially mapped page through a per-word table, giving 4-byte granularity. Whole-page mappings had a single entry. In TEMU 5, this is now 8 bytes. This only makes a difference if you have sub-8-byte-sized mappings.

Endianness of the Payload

The memory space never byte-swaps the payload of a large transaction as a whole. Swapping is applied per unit, and only on the path where the memory space splits the transaction itself.

An endpoint that declares LargeTransactions therefore receives the buffer exactly as the initiator wrote it, and is responsible for honoring the endianness bit in the transaction flags. This is true of both TEMU 4 and TEMU 5, but it becomes visible the moment a model changes whether it declares the capability, so it is worth knowing when comparing the two.

Capabilities Are Not Enforced

temu_MemAccessCapabilities is not enforced by default, the TEMU memory subsystem only ever reads LargeTransactions.

TransactionBaseSizes and Endianness are not read on that path. A model that declares 32-bit-only base sizes will still be handed 8-bit and 16-bit accesses, in TEMU 4 and in TEMU 5 alike.

If you do want the declaration honored, TEMU 5 has a MemorySnooper model that enforces it. Inserted between an initiator and a device, it fails a transaction whose unit size the device does not list, or can instead modify the access (splitting it into smaller supported ones or widening it through a read-modify-write).

Removed Models and Classes

Three classes were removed outright.

Machine

The whole Machine plugin is gone, so import Machine fails. See Scheduling.

Scheduler

Renamed to SingleLevelScheduler, with Scheduler kept as a built-in class alias.

BreakManager

The memory space break manager was replaced by the breakpoint management in the new debugging library, which is reached through the TCF server and the GUI rather than by instantiating an object.

No device models were removed. TEMU 5 adds a large number of them for new boards.

Reset

In TEMU 4, reset was an alias for cpu-reset, it took a cpu argument and fell back to the DEFAULT_CPU variable. In TEMU 5, reset, cpu-reset and object-reset are the same command. It accepts either obj or cpu, prefers the generic ResetIface over CpuIface, and has no default object.

A bare reset with no argument fails in TEMU 5. Pass obj or cpu explicitly.

TEMU 5 also has a ResetController model, which pairs naturally with components. A component instantiates one, fans its reset output out to the ResetIface of every object on the board, and exports it. Resetting the board is then a single reset obj=board0, which reaches devices that a CPU-local reset never touched.

Command Line Changes

Removed Commands

Table 3. Commands Removed in TEMU 5
Removed Replacement

machine-reset

reset obj=<board> or reset cpu=<cpu>

gdb, gdb-server, experimental-debug-*

See Debugging

The experimental register commands, exp- and experimental-

pregs, pbanks and object properties

license-release

No replacement, licenses are released on exit

New Commands

init-scheduler

Create the global scheduler, see Scheduling. This is the one command a TEMU 4 script has to gain.

Model Interface Changes

All model plugins must be rebuilt against the TEMU 5 headers. The support library soname changed from libTEMUSupport.so.4 to libTEMUSupport.so.5, so a TEMU 4 plugin binary cannot be loaded at all.

Memory

temu_MemoryIface, with its readBytes() and writeBytes() members, is marked deprecated in TEMU 5, as are both of its members. Models doing bulk memory access should issue transactions through MemAccessIface instead, using temu_memoryReadTransaction(), temu_memoryWriteTransaction() and temu_memoryExchangeTransaction(), or the temu_memoryRead* and temu_memoryWrite* helpers.

MemorySpace publishes two MemAccessIface implementations. The one reached through the vtable, and therefore through temu_memoryWriteTransaction(), is the fast non-locking path. The one published under the name MemAccessIface, which is what real system configurations connect through connect a=cpuN.memAccessL2 b=mem0:MemAccessIface, takes the memory space lock for teMK_IO mappings when the transaction carries TEMU_MT_LOCK_ACQUIRE.

Serial and Ethernet

Both interfaces gained one optional member at the end of the structure, and both changes are backward compatible. An existing model that leaves the new member as NULL behaves exactly as it did in TEMU 4.

temu_SerialIface

New isClearToReceive(). A receiver can report whether its receive path can accept another byte, and a sender can consult its peer before pushing one instead of overrunning it. NULL means always clear to receive.

temu_PHYIface

New setPromiscuous(), so a MAC can tell its PHY or link that its receive filtering changed. temu_EthernetIface already had one in TEMU 4 and is unchanged.

CAN

CAN FD support was added, with a new temu_CanFDFrame type and receiveFD() and sendFD() members on the device and bus interfaces. The classic CAN frame type and its interface members are unchanged, so existing CAN models keep working.

SPI

TEMU 5 adds a second generation SPI interface set alongside the existing one, supporting chip select handling, quad SPI and data rates. The TEMU 4 interfaces are retained but are now deprecated, so existing SPI models keep working while they are ported.

MIL-STD-1553

The bus interface gained a reset() member.

Register API

The register API was experimental in TEMU 4 and has been replaced. Models that used it will not compile until they are ported.

Where TEMU 4 built a register bank object and hung registers and fields off it, TEMU 5 registers memory mapped registers directly on the class:

// TEMU 4
temu_RegisterBank *Bank = temu_addRegisterBank(Cls, "regs", &MemAccessIface);
temu_addRegister(Bank, "ctrl", offsetof(MyDevice, Ctrl), teTY_U32, 1,
                 writeCtrl, readCtrl, "Control register", 0x00, 4);

// TEMU 5
temu_addMemoryMappedRegister32(Cls, "ctrl", offsetof(MyDevice, Ctrl), 1,
                               "Control register");

TEMU 4.6 already had the experimental temu-c/Support/NewRegisterAPI.h header, it is now temu-c/Support/Register.h with the same function signatures.

Register metadata, including fields, now lives in temu_RegisterMetaData and temu_FieldMetaData in temu-c/Support/Register.h, and is what drives the register views in the GUI and the TCF register service.

Device models that never used the experimental register API are not affected. Registers implemented as ordinary properties with a MemAccessIface dispatch switch keep working.

Logging

temu_logSetFunc() and temu_logSetAdvancedFunc() still work. TEMU 5 adds a sink model on top, where several sinks can be active at once and each is identified by a temu_LogSinkHandle:

temu_LogSinkHandle H = temu_logAddFunc(myLoggingFunc);
temu_logRemoveSink(H);
temu_logClearSinks();

Plugin Metadata

TEMU 5 plugins can declare metadata that the plugin manager reads at load time. It is optional in TEMU 5, a plugin without it still loads, but declaring it means plugin-list can report the vendor, version and license of your models.

Add it once, at file scope, anywhere in the plugin:

#include "temu-c/Support/Objsys.h"

TEMU_PLUGIN_MD_DEF_V1 = {
  1,                 // Metadata version, always 1 for this macro
  "Example Company", // Vendor
  "MyModels",        // Plugin name
  1, 0, 0,           // Plugin version, major/minor/patch
  5, 1, 0,           // TEMU version compiled against
  0,                 // Flags, see TEMU_PLUGIN_FLAG_*
  "abc1234",         // Revision, for example a Git hash
  "Proprietary",     // License
  "Example device models",
  "(c) Example Corp 2026",
};

The ABI version fields are the TEMU version the plugin was compiled against, which lets the plugin manager warn about a mismatch rather than failing on an unresolved symbol later.

See Plugins.

Embedded Python

TEMU 4 embedded Python 2.7. TEMU 5 embeds Python 3.13 and bundles it, so the host system Python version does not matter.

Python scripts run with --run-script or the script-run command must be ported to Python 3.

The temu.c.* modules keep their import paths, so from temu.c.support import objsys still works. As of TEMU 5.1 they are generated with SWIG rather than being raw ctypes bindings.

from temu.c.support import objsys

cpu = objsys.objectForName("cpu0")

Python callbacks for events, notifications and commands are wrapped as well.

The ctypes wrappers are still available, selected by the python/legacy-wrappers configuration key, but they are deprecated.

Debugging

TEMU 4 offered source level debugging through the experimental-debug-* command family, and an in-process GDB server started with the gdb-server command.

In TEMU 5 the experimental-debug-* commands are gone. Source level debugging is built around debugging contexts, exposed through the TCF server, the MCP server and the TEMU GUI. See Software Debugging, Model Context Protocol Server, and the GUI guide.

The gdb and gdb-server commands are gone too. The GdbServer object, which TEMU 4.6 already had, is now the only way to start a GDB server:

import GdbDebugger
GdbServer.new name=gdb port=6666 mem=mem0
connect-timesource obj=gdb ts=cpu0

For scripts that used the command this is a behavioral change as well as a syntactic one. The TEMU 4 gdb-server command blocked until GDB disconnected. The object runs the server on its own thread, so the script continues.

Snapshots

TEMU 5 adds a binary snapshot format, TSnap, saved and restored with tsnap-write and tsnap-read. JSON snapshots, snapshot-save and snapshot-restore, still work unchanged but are deprecated, see Snapshots.

tsnap-write file=boot.tsnap
tsnap-read file=boot.tsnap
Table 4. JSON and TSnap snapshots
JSON (snapshot-save) TSnap (tsnap-write)

Files

JSON object graph plus host endian RAM and ROM dumps

A single .tsnap file, memory included

Contents

Objects and properties

Plugins, classes, objects, properties and memory

Restore

Recreates objects, or keeps them with inplace=1

Always disposes all objects, reloads the plugins and recreates the objects

Relative paths

Current directory

Configurable via runtime/snapshots (.temu/snapshots in a project)

Inspection

No dedicated tool

snapshot-inspector in TEMU’s bin/

TSnap is the format behind reverse execution and plugin-reload, so a model that restores correctly from a .tsnap file also works with both.

Model state must be in properties or pseudo properties. TSnap does not call ObjectIface::serialise() and deserialise() (see Custom Snapshots). A model that needs to fix up derived state can subscribe to the temu.snapshot.take and temu.snapshot.restore notifications instead, or use pseudo-properties.

New in TEMU 5

Migrating also unlocks functionality that has no TEMU 4 equivalent:

  • Reverse execution, driven by the multi-level scheduler.

  • Projects, see Project Files.

  • The TEMU GUI and the TCF server behind it.

  • A Model Context Protocol server, see Model Context Protocol Server.

  • OS awareness, see OS Awareness.

  • RISC-V support, including NOEL-V and GR765, with binary translation.

  • ARM Cortex-M4 and Cortex-M7, with an STM32F4 device set.

  • Additional console models: PTY, Telnet and TCF, see Serial Consoles.

  • Graphics output models, I2C, SpaceFibre, CAN FD and TTEthernet.

  • Guest software race detection (ThreadSanitizer style).