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:
| Module | Purpose |
|---|---|
args | Command-line argument definitions using clap derive macros |
config | TOML configuration file support with merge logic |
error | Comprehensive error types with helpful messages |
execution | Execution engine with generic stop conditions |
output | Extensible output formatting system |
§Design Principles
- Separation of Concerns: Each module has a single responsibility
- Extensibility: Adding new features requires minimal changes
- Error Handling: All errors are structured with helpful messages
- Builder Pattern: Configuration objects use fluent builder APIs
- 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-ENDorSTART:LENGTH. - validate_
args - Validate CLI arguments for consistency and completeness.