Layers and modules¶
Lince is structured as a stack of CMake static libraries with strict unidirectional dependencies. This page enumerates each layer, what lives in it, and what it must not depend on.
Dependency graph¶
flowchart TD
lince_app[lince_app<br/>CLI executable] --> lince_runtime
demo_dma[demo_dma_device<br/>examples] --> lince_runtime
lince_runtime[lince_runtime<br/>Emulator, ElfLoader, Scheduler] --> lince_defaults
lince_runtime --> lince_peripherals
lince_defaults[lince_defaults<br/>Loggers, CharDevices] -.-> lince_interfaces
lince_peripherals[lince_peripherals<br/>IrqMP, GPTimer, ApbUart, MemCtrl] --> lince_bus
lince_bus[lince_bus<br/>SystemBus, RAM] --> lince_core
lince_core[lince_core<br/>SPARC V8 ISA, CpuState, Decoder] -.-> lince_interfaces
lince_interfaces[lince_interfaces<br/>Header-only API]
Solid arrows are link-time dependencies; dotted arrows are header-only
contracts (lince_interfaces does not produce a .a file).
The graph is acyclic by construction — lince_core does not know
that peripherals exist, lince_bus does not know that there is a CPU,
and lince_interfaces knows nothing about anybody.
What goes where¶
| Module | CMake target | Owns | Depends on |
|---|---|---|---|
| Interfaces | lince_interfaces (INTERFACE) |
Strong types, Result<T>, all I* contracts |
— |
| Core | lince_core |
CpuState, decoder, ISA handlers, trap dispatch |
interfaces |
| Bus | lince_bus |
Ram, SystemBus |
interfaces |
| Peripherals | lince_peripherals |
IrqMP, GPTimer, ApbUart, MemCtrl |
interfaces, bus |
| Runtime | lince_runtime |
Emulator, EmulatorConfig, EventScheduler, ElfLoader, CpuBusBridge, GdbStub |
interfaces, core, bus, peripherals, defaults |
| Defaults | lince_defaults |
StdoutLogger, StdoutCharDevice, NullFaultInjector, DebugPublisher |
interfaces |
| App | lince_app (executable) |
CLI, argument parsing, post-mortem dump | runtime |
| Demo | demo_dma_device (example) |
A custom peripheral with DMA + IRQ | interfaces, runtime (only for the test binary) |
Why the layers exist¶
lince_interfacesexists so any module can take a dependency on a contract without pulling in an implementation. It is header-only, contains no logic, and never breaks ABI.lince_coreis independent of bus and peripherals so the CPU can be unit-tested with hand-crafted instruction streams against any fake bus.lince_busdoes not know about CPUs — it is a pure address router. This lets us reuse it as the DMA target for peripherals (IBusMaster) without circular dependencies.lince_runtimeis the only orchestrator. It composes everything; no other module is allowed to instantiateEmulator,EventScheduler, orElfLoader.lince_defaultsis intentionally tiny. Anything an SMP2 wrapper would replace (logger, char device, fault injector) lives here, so a downstream consumer can drop the entire library and substitute their own implementations.
Module-by-module narrative¶
For deeper module documentation see the dedicated pages under Modules: