Files
nesemu/docs/architecture.md
se.cherkasov ea0c5b1894
Some checks failed
CI / rust (push) Has been cancelled
chore: fix clippy warnings and update docs to match public API
Fix 9 clippy warnings across mmc5 mapper and desktop frontend.
Sync api_contract.md and architecture.md with actual public surface.
2026-03-16 15:05:02 +03:00

4.8 KiB

Architecture

This document describes how the workspace is organized internally.

Use ../README.md for project overview, integration.md for host integration, and api_contract.md for supported public surface.

Workspace Layout

  • nesemu: reusable emulation library and host-facing runtime wrappers
  • crates/nesemu-adapter-api: backend-agnostic adapter traits
  • crates/nesemu-adapter-headless: headless/null adapter implementations
  • crates/nesemu-desktop: GTK4 desktop frontend that consumes the root crate

High-Level Layers

The workspace is split into four layers:

  1. native_core Owns emulation correctness and hardware-facing behavior.
  2. runtime Wraps the core with host-oriented execution, pacing, lifecycle control, and save-state helpers.
  3. adapter crates Define integration edges without coupling the core to a concrete backend.
  4. desktop frontend Serves as a consumer and manual test harness, not as part of the library contract.

Core Module Boundaries

  • src/native_core/cpu: 6502 execution, addressing helpers, opcode dispatch
  • src/native_core/ppu: rendering pipeline, VRAM/OAM/register behavior
  • src/native_core/apu: timing, channel state, and audio-facing hardware state
  • src/native_core/bus: component wiring and device-visible read/write semantics
  • src/native_core/mapper: cartridge mapper abstraction and concrete implementations
  • src/native_core/ines: iNES parsing and ROM metadata
  • src/native_core/state_io: shared state decoding helpers

Runtime Module Boundaries

  • src/runtime/core.rs: NesRuntime orchestration around CPU + bus
  • src/runtime/state.rs: runtime save/load state format
  • src/runtime/audio.rs: interim PCM synthesis from core state
  • src/runtime/timing.rs: frame pacing types and video timing
  • src/runtime/types.rs: public joypad-related types and helpers
  • src/runtime/constants.rs: frame dimensions and video constants
  • src/runtime/error.rs: RuntimeError type definitions
  • src/runtime/ring_buffer.rs: lock-free ring buffer for audio sample transport
  • src/runtime/adapters.rs: adapter bridge types (behind adapter-api feature)
  • src/runtime/host/io.rs: host IO traits and null implementations
  • src/runtime/host/executor.rs: per-frame execution unit
  • src/runtime/host/clock.rs: clock abstraction and pacing implementations
  • src/runtime/host/loop_runner.rs: host loop wrapper for frame-based execution
  • src/runtime/host/session.rs: app lifecycle wrapper for running, pausing, and stepping

Data Flow

At a high level, the runtime stack looks like this:

  1. ROM bytes are parsed into cartridge metadata and ROM contents.
  2. A mapper is created from the ROM description.
  3. NativeBus wires CPU, PPU, APU, mapper, and input-visible state together.
  4. Cpu6502 executes against the bus.
  5. NesRuntime wraps the core to provide frame-level execution, rendering, and save-state helpers.
  6. RuntimeHostLoop and ClientRuntime adapt the runtime to host application control flow.

Public Surface Strategy

The root crate re-exports the integration-critical API so external users do not need to depend on the internal module layout.

The design intent is:

  • external clients use root re-exports and runtime
  • advanced clients may use native_core
  • internal module paths are free to evolve faster than the root surface

Host Responsibilities

The library intentionally leaves these concerns to the host application:

  • windowing and presentation backend
  • audio device/output backend
  • platform input mapping
  • ROM file I/O
  • persistent state storage

Input, Video, and Audio Contracts

  • JoypadButtons are exposed in the public order [Up, Down, Left, Right, A, B, Start, Select]
  • InputProvider polls the current button state from the host
  • VideoOutput receives RGBA frames
  • AudioOutput receives mixed mono samples
  • port 2 is currently treated as disconnected in the exposed core API

Save-State Design

  • NativeBus::save_state and NativeBus::load_state persist low-level emulator state
  • NesRuntime extends that state with runtime metadata such as frame number and active buttons
  • save-state payloads are versioned for crate-internal use, not for long-term external compatibility

Testing Layout

  • CPU tests are grouped by behavior, interrupts, and invariants
  • mapper tests are grouped by mapper family and property-style checks
  • runtime tests cover frame execution, pacing, state roundtrips, and lifecycle control
  • tests/public_api.rs exercises the supported public flow as a black-box consumer

Constraints And Tradeoffs

  • no platform backend is bundled beyond the GTK desktop example
  • audio mixing in runtime/audio.rs is intentionally interim
  • optional adapter crates are thin integration layers, not mandatory parts of the core runtime
  • compatibility promises are defined in docs/api_contract.md, not by internal module visibility