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 == 0→ErrorCode::InvalidConfignum_cores > 4→ErrorCode::InvalidConfigram_size == 0→ErrorCode::InvalidConfigquantum == 0→ErrorCode::InvalidConfig- A
ram_base + ram_sizethat 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.