Skip to main content

Module cli

Module cli 

Source
Expand description

CLI module for the NES emulator.

This module provides a comprehensive command-line interface for programmatic control of the emulator. It is designed with extensibility and robustness in mind.

§Architecture

The CLI is organized into several submodules, each with a specific responsibility:

ModulePurpose
argsCommand-line argument definitions using clap derive macros
configTOML configuration file support with merge logic
errorComprehensive error types with helpful messages
executionExecution engine with generic stop conditions
outputExtensible output formatting system

§Design Principles

  1. Separation of Concerns: Each module has a single responsibility
  2. Extensibility: Adding new features requires minimal changes
  3. Error Handling: All errors are structured with helpful messages
  4. Builder Pattern: Configuration objects use fluent builder APIs
  5. Crate-Ready: All public types are designed for library use

§Extensibility Guide

§Adding a New Output Format

// 1. Add variant to OutputFormat enum in args.rs
pub enum OutputFormat {
    Hex, Json, Toml, Binary,
    Xml,  // New!
}

// 2. Implement MemoryFormatter trait in output.rs
pub struct XmlFormatter;
impl MemoryFormatter for XmlFormatter {
    fn format(&self, dump: &MemoryDump) -> Result<Vec<u8>, String> {
        // ... format as XML ...
    }
    fn file_extension(&self) -> &'static str { "xml" }
}

// 3. Register in OutputFormat::formatter() and extension()
impl OutputFormat {
    pub fn formatter(&self) -> Box<dyn MemoryFormatter> {
        match self {
            // ... existing ...
            OutputFormat::Xml => Box::new(XmlFormatter),
        }
    }
    pub fn extension(&self) -> &'static str {
        match self {
            // ... existing ...
            OutputFormat::Xml => "xml",
        }
    }
}

§Adding a New Stop Condition

// 1. Add variant to StopCondition enum in execution.rs
pub enum StopCondition {
    Cycles(u128), Frames(u64), PcEquals(u16),
    ScanlineEquals(u16),  // New!
}

// 2. Add corresponding StopReason variant
pub enum StopReason {
    CyclesReached(u128), FramesReached(u64), PcReached(u16),
    ScanlineReached(u16),  // New!
}

// 3. Implement check in ExecutionConfig::check_conditions()
StopCondition::ScanlineEquals(target) if emu.ppu.scanline == *target => {
    return Some(StopReason::ScanlineReached(*target));
}

// 4. Add CLI argument in args.rs
#[arg(long)]
pub until_scanline: Option<u16>,

// 5. Add builder method in ExecutionConfig
pub fn with_scanline(mut self, scanline: u16) -> Self {
    self.stop_conditions.push(StopCondition::ScanlineEquals(scanline));
    self
}

§Adding a New Memory Type

// 1. Add variant to MemoryType enum in output.rs
pub enum MemoryType {
    Cpu, Ppu, Oam, Nametables,
    PaletteRam,  // New!
}

// 2. Add factory method to MemoryDump
impl MemoryDump {
    pub fn palette_ram(data: Vec<u8>) -> Self {
        Self::new(MemoryType::PaletteRam, 0x3F00, data)
    }
}

// 3. Add CLI argument in args.rs
#[arg(long)]
pub dump_palette_ram: bool,

// 4. Handle in main.rs output_results()
if args.memory.dump_palette_ram {
    let dump = create_palette_ram_dump(emu);
    writer.write(&dump)?;
}

§Usage Examples

§Command Line

# Basic headless run
nes_main --headless --rom game.nes --frames 100

# With config file
nes_main --config run.toml

# Memory dump to file
nes_main -H --rom game.nes --frames 60 --read-cpu 0x0000-0x07FF --json -o memory.json

# Pipe-based savestate workflow
nes_main -H --rom game.nes --frames 100 --state-stdout | \
nes_main -H --rom game.nes --state-stdin --frames 50 --save-state final.sav

§Programmatic (Crate API)

use lockstep::cli::{ExecutionConfig, ExecutionEngine, SavestateConfig};
use std::path::PathBuf;

// Create execution config with builder pattern
let exec_config = ExecutionConfig::new()
    .with_frames(100)
    .with_pc_breakpoint(0x8000)
    .with_verbose(true);

// Create savestate config
let save_config = SavestateConfig::new()
    .save_to_file(PathBuf::from("output.sav"));

// Run emulation
let mut engine = ExecutionEngine::new()
    .with_config(exec_config)
    .with_savestate_config(save_config);

engine.load_rom(&PathBuf::from("game.nes"))?;
engine.power_on();

let result = engine.run()?;
println!("Stopped: {:?} after {} frames", result.stop_reason, result.total_frames);

engine.save_savestate()?;

See docs/CLI_INTERFACE.md for full documentation.

Re-exports§

pub use args::CliArgs;
pub use args::OutputFormat;
pub use args::SavestateFormat;
pub use args::VideoExportMode;
pub use args::VideoFormat;
pub use args::parse_hex_u16;
pub use config::ConfigFile;
pub use error::CliError;
pub use error::CliResult;
pub use execution::ExecutionConfig;
pub use execution::ExecutionEngine;
pub use execution::ExecutionResult;
pub use execution::MemoryAccessType;
pub use execution::SavestateConfig;
pub use execution::SavestateDestination;
pub use execution::SavestateSource;
pub use execution::StopCondition;
pub use execution::StopReason;
pub use headless::create_renderer_from_args;
pub use headless::list_renderers;
pub use headless::run_headless;
pub use memory_init::MemoryInit;
pub use memory_init::MemoryInitConfig;
pub use memory_init::apply_memory_init;
pub use memory_init::apply_memory_init_config;
pub use output::InterpretedNametable;
pub use output::InterpretedNametables;
pub use output::InterpretedOam;
pub use output::MemoryDump;
pub use output::MemoryFormatter;
pub use output::MemoryType;
pub use output::OamSprite;
pub use output::OutputWriter;
pub use video::FpsConfig;
pub use video::StreamingVideoEncoder;
pub use video::VideoEncoder;
pub use video::VideoError;
pub use video::VideoResolution;
pub use video::create_encoder;
pub use video::encode_frames;
pub use video::is_ffmpeg_available;

Modules§

args
CLI argument definitions using clap derive macros.
config
Configuration file support for the NES emulator CLI.
error
Error types for the CLI module.
execution
Execution engine for CLI-driven emulation.
headless
Headless mode execution for the NES emulator CLI.
memory_init
Memory initialization utilities for CLI.
output
Output formatting system for CLI memory dumps.
video
Video export module for the NES emulator CLI.

Functions§

parse_args
Parse CLI arguments and optionally merge with a config file.
parse_memory_range
Parse a memory range string in format START-END or START:LENGTH.
validate_args
Validate CLI arguments for consistency and completeness.