Skip to content

Configuration

The Emulator is configured through a single plain-old struct, lince::runtime::EmulatorConfig, defined in src/runtime/include/lince/runtime/emulator_config.hpp.

Fields

Field Type Default Meaning
num_cores uint32_t 1 Number of LEON cores. GR712RC supports 1–2; GR740 supports 1–4 (Phase 7).
ram_base uint32_t 0x40000000 Physical base address of RAM.
ram_size uint32_t 16 MiB RAM size in bytes.
ns_per_insn uint64_t 20 Simulated nanoseconds per instruction. 20 ns ≈ 50 MHz.
quantum uint32_t 1000 Instructions per core per round-robin pass.
entry_point_override uint32_t 0 If non-zero, override the ELF e_entry and start at this PC.
gdb_stub_port uint16_t 0 If non-zero, bind the GDB remote stub on 127.0.0.1:port.
gdb_stub_wait_for_client bool false If true and the stub is bound, initialize() blocks until a GDB client connects.

Factory helpers

gr712rc_config() returns the SoC-level defaults for the GR712RC. It is the recommended starting point — peripheral addresses are wired by Emulator::initialize(), not stored in the config struct, so the factory just sets num_cores, ram_base, ram_size, etc. to GR712RC-appropriate values.

auto cfg = lince::runtime::gr712rc_config();
cfg.num_cores = 2;
cfg.gdb_stub_port = 9000;
cfg.gdb_stub_wait_for_client = true;

Validation

Emulator::create(cfg) rejects configurations that would produce an unbootable machine:

  • num_cores == 0ErrorCode::InvalidConfig
  • num_cores > 4ErrorCode::InvalidConfig
  • ram_size == 0ErrorCode::InvalidConfig
  • quantum == 0ErrorCode::InvalidConfig
  • A ram_base + ram_size that wraps the 32-bit address space → InvalidAddress

Most other fields are accepted at face value; the result is your problem if you set ns_per_insn = 0 and the simulator's clock never advances.

GDB stub

Setting gdb_stub_port to a non-zero value asks Emulator::initialize() to bind a TCP listener on 127.0.0.1:<port> that speaks the GDB Remote Serial Protocol (RSP) subset required by sparc-rtems-gdb.

A typical workflow:

# Terminal 1 — emulator
./build/src/app/lince-emu --image hello.elf --gdb-port 9000 --gdb-wait

# Terminal 2 — debugger
sparc-rtems5-gdb hello.elf
(gdb) target remote :9000
(gdb) break main
(gdb) continue

--gdb-wait is what you want for early-boot debugging: initialize() does not return until the client is attached, so the very first instruction executes under the debugger's control.

The supported RSP packets are documented in the lince_runtime page under "GDB stub".

Mutating runtime knobs

Some settings are not in EmulatorConfig because they need a service implementation rather than a value:

Setter Replaces Default
set_logger(unique_ptr<ILogger>) All logging output StdoutLogger
set_character_device(unique_ptr<ICharacterDevice>) UART TX/RX StdoutCharDevice

Both must be called before initialize(). The peripheral attachments cache pointers during init, so swapping later has no effect.

Configuring through the CLI

The CLI builds an EmulatorConfig from the flags listed in the CLI reference. The mapping is one-to-one for the fields you typically want to override at run time (--ram, --cores, --budget, --gdb-port, --gdb-wait); the rest are left at their struct defaults. If you need to tweak ram_base, ns_per_insn, etc., either embed Lince as a library or extend lince_app/main.cpp.