A reference for the engine's runtime internals. For the high-level subsystem tour (Asset Foundry, IR, Core Engine), see architecture_overview.md.
LabWired is a modular execution engine designed to decouple the CPU core from the memory and peripheral bus. This design enables the simulation of multi-architecture systems within a unified peripheral environment.
Ordinary native, CLI-test, debugger, and WASM execution enters through
Machine::advance. It owns batch planning, CPU0/CPU1 scheduling, cycle
publication, peripheral ticks, scheduler delivery, software reset, flash
operations, profiling, and logic observation. Frontends inspect the machine
between bounded calls for assertions, stimuli, UART limits, and artifacts, but
must not call Cpu::step directly.
Outside CPU implementations and test-only integration/unit harnesses, the remaining direct CPU advancement sites are deliberately limited to these implementation and compatibility boundaries:
crates/core/src/machine/boundary.rsis the internal CPU execution primitive owned byMachine::advance; it is not a frontend entry point.- CPU trait implementations, the default
step_batchhelper, and CPU unit helpers operate below or outside the frontend boundary. The direct calls incrates/core/src/peripherals/esp_xtensa_common/rom_thunks.rsare unit-test helpers. crates/core/src/vfi.rsprovides the specialist standaloneShadowEngine. Its lockstep operation deliberately owns direct stepping of the golden and shadow CPUs plus parity comparison; its caller owns the surrounding bus and peripheral lifecycle. It is not an ordinaryMachinefrontend.crates/core/src/multi_core.rsprovides the specialist standaloneMultiCoreMachine::step_allengine. It directly steps each core, ticks its peripherals once, and routes interrupts according to that engine's own policy; it is outside theMachinefrontend lifecycle.crates/cli/src/main.rsusesMachine::advancefor bounded test execution.crates/cli/src/commands/run.rsandcrates/cli/src/commands/snapshot.rscontain specialized bare-CPU ESP bring-up and snapshot loops; these are explicitly outside the ordinary machine frontend path.crates/hw-oracle/src/lib.rs,crates/hw-oracle/src/arm_thumb.rs, andcrates/hw-oracle/src/riscv.rsare bare-CPU hardware validation oracles.
Ordinary WASM wrappers and DebugControl::run have no direct CPU-step path;
they enter through the authoritative machine boundary.
The labwired-core crate provides the central execution loop and state management.
The execution engine is generic over a Cpu trait, allowing for different instruction set architectures (ISAs) to interface with the same system bus.
pub trait Cpu {
/// Resets the CPU state (PC, SP, etc.)
fn reset(&mut self, bus: &mut dyn Bus) -> SimResult<()>;
/// Executes a single instruction cycle
fn step(
&mut self,
bus: &mut dyn Bus,
observers: &[Arc<dyn SimulationObserver>],
config: &SimulationConfig
) -> SimResult<()>;
}The system currently implements:
- Cortex-M (ARMv7-M / ARMv6-M): Supports Thumb-2 instruction decoding.
- RISC-V (RV32IMC): Base integer set plus M/C extensions (e.g. the ESP32-C3 core).
- Xtensa (LX7): Powers the ESP32-S3 targets.
The memory system uses a linear addressing model mapped to host memory regions.
- Flash: Read-only segments populated from the ELF binary.
- RAM: Read-write segments initialized to zero.
- MMIO: Addresses outside predefined memory regions are routed to the Peripheral Bus.
Peripherals communicate with the CPU via the Peripheral trait. This trait defines the contract for Memory-Mapped I/O (MMIO) and time-based state updates.
pub trait Peripheral {
fn read(&self, offset: u64) -> SimResult<u8>;
fn write(&mut self, offset: u64, value: u8) -> SimResult<()>;
fn tick(&mut self) -> PeripheralTickResult;
}This model prevents race conditions where a peripheral modifies memory while the CPU is executing, ensuring strict sequential consistency.
To achieve high MIPS (Million Instructions Per Second) for autonomous agents, LabWired supports configurable performance gates:
- Instruction Decode Cache: A direct-mapped cache in the CPU core that avoids re-decoding instructions on every hit.
- Multi-Byte Bus Fast-Path: Specialized 16/32-bit access methods in
SystemBusthat bypass the virtualread_u8loop for memory regions (RAM/Flash). - Batched Ticking: Configurable
peripheral_tick_interval. Ticking every N cycles instead of every instruction significantly reduces virtual call overhead in the hot path. - Event-Driven Scheduling: Peripherals that know their next deadline register wake-ups with the event scheduler (
crates/core/src/sched/) instead of being polled every tick, eliminating the per-cycle peripheral walk on idle blocks.
Defaults and gating are controlled via SimulationConfig. Setting peripheral_tick_interval to 1 and disabling caches restores strict cycle-accurate behavior for time-sensitive firmware.
The Cortex-M implementation uses a custom stateless decoder for the ARMv7-M Thumb-2 instruction set.
Supported Instruction Classes:
- 32-bit Instructions:
BL,MOVW,MOVT(handled via double half-word fetch). - Control Flow:
B,BL,BX,CBZ/CBNZ,ITblocks. - Arithmetic/Logic:
ADD,SUB,MUL,SDIV/UDIV,AND,ORR,EOR. - Bit Manipulation:
BFI,UBFX,CLZ,RBIT.
LabWired integrates with external debuggers via standard protocols.
The labwired-gdbstub crate implements the RSP server, allowing gdb-multiarch to attach to the simulation. It supports:
- Breakpoints (Software/Hardware)
- Single-stepping
- Register and Memory inspection
The labwired-dap crate provides a direct interface for VS Code. It exposes:
- State Inspection: Live view of registers and call stack.
- Telemetry: A custom event stream for real-time performance metrics (Cycles, MIPS) without polling overhead.