Skip to main content

Overview

oboromi currently provides a GUI-based interface for running ARM64 CPU tests. The emulator cannot yet run commercial games or firmware, but provides a foundation for testing CPU emulation accuracy.
Experimental Software: oboromi is in active development. Without a kernel exploit, running retail games is currently impossible. This release focuses on CPU instruction emulation only.

Running the Emulator

Basic Execution

Run the emulator directly from the source directory:
cargo run
This:
  1. Builds the project (if needed)
  2. Initializes the logging system
  3. Launches the eframe/egui GUI window
  4. Creates oboromi.log in the current directory

Release Mode

For better performance, use release mode:
cargo run --release
Release builds are 10-100x faster than debug builds due to full optimizations.

With Tracing Enabled

Enable detailed execution tracing:
cargo run --features trace
You’ll see in the logs:
[INFO][oboromi] -- TRACING ENABLED --
This logs every CPU instruction executed (extremely verbose).
The trace feature is defined in gui/src/main.rs:42-43 and forwards to oboromi-core.

GUI Interface

Startup Sequence

When you launch oboromi:
1

Splash Screen

The GUI displays a splash screen for ~1.6 seconds with:
  • oboromi logo (fade in/out animation)
  • “Experimental” warning
  • Information about current limitations:
    • “This is an experimental foundation for Switch 2 emulation.”
    • “Without a kernel exploit, running retail games is currently impossible.”
    • “This release focuses on CPU instruction emulation only.”
The splash is implemented in gui/src/gui/gui.rs:41-132.
2

Main Window

After the splash, you see the main interface:
  • Window Size: 1200×800 pixels
  • Title: “oboromi”
  • Menu Bar: File and About menus
  • Test Runner: “Run CPU Tests” button
  • Results Panel: Scrollable log viewer

Window Configuration

The GUI is configured in gui/src/main.rs:22-28:
let options = eframe::NativeOptions {
    viewport: egui::ViewportBuilder::default()
        .with_inner_size([1200.0, 800.0])
        .with_title("oboromi"),
    ..Default::default()
};
Quit: Closes the application windowSends egui::ViewportCommand::Close to gracefully terminate.

Running CPU Tests

1

Click 'Run CPU Tests'

The button spawns a background thread that:
  1. Warms up the JIT compiler
  2. Executes ARM64 test suite via oboromi_core::tests::run::run_tests()
  3. Returns results as a vector of strings
gui/src/gui/gui.rs:157-163
if ui.button("Run CPU Tests").clicked() {
    let ctx = ctx.clone();
    self.test_thread = Some(std::thread::spawn(move || {
        ctx.request_repaint();
        run_tests()
    }));
    // ...
}
2

View Progress

While tests run, you’ll see:
Warming up JIT compiler...
Running ARM64 tests...
The UI shows “Running tests…” and disables the button.
3

Analyze Results

Test results appear with color coding:
  • Green: Lines containing “PASS”
  • Red: Lines containing “FAIL”
  • Gray: Other output
The results panel is scrollable and shows all test output.
gui/src/gui/gui.rs:174-184
ScrollArea::vertical().show(ui, |ui| {
    for line in &self.logs {
        let color = if line.contains("PASS") {
            Color32::from_rgb(50, 255, 50)
        } else if line.contains("FAIL") {
            Color32::from_rgb(255, 50, 50)
        } else {
            Color32::from_rgb(200, 200, 200)
        };
        ui.colored_label(color, line);
    }
});

Logging System

Log File Location

Logs are written to oboromi.log in the current working directory (where you ran cargo run).

Log Format

Implemented in gui/src/main.rs:5-20:
fn setup_logger() -> Result<(), fern::InitError> {
    fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "[{}][{}] {}",
                record.level(),
                record.target(),
                message
            ))
        })
        .level(log::LevelFilter::Debug)
        .chain(std::io::stdout())
        .chain(fern::log_file("oboromi.log")?)
        .apply()?;
    Ok()
}
Format: [LEVEL][module::path] message Example log entries:
[INFO][oboromi] GUI initialized
[DEBUG][oboromi_core::cpu] ARM64 core 0 started
[TRACE][oboromi_core::cpu::unicorn_interface] Executing: 0xdeadbeef MOV X0, #42

Log Levels

Shows INFO, WARN, and ERROR messages.
cargo run
Output includes:
  • CPU initialization
  • Test execution start/stop
  • Major state changes

Command-Line Binary

Direct Execution

After building, run the binary directly:
# Debug build
./target/debug/oboromi

# Release build
./target/release/oboromi

Environment Variables

# Enable full backtraces on panic
RUST_BACKTRACE=1 cargo run

# Or with the binary
RUST_BACKTRACE=1 ./target/release/oboromi

Runtime Configuration

Emulation State

The emulator initializes the following system (from core/src/sys/mod.rs):

CPU

  • 8-core ARMv8 CPU
  • Unicorn Engine backend
  • 12GB shared memory

GPU

  • SM86 (NVIDIA Ampere) stub
  • Vulkan 1.3 backend via ash
  • Stubbed command processing

Filesystem

  • VFS implementation
  • 32GB UFS/eMMC emulation
  • No game loading yet

System Services

  • 150+ HLE firmware services
  • Stubs for nn::* modules
  • Defined in core/src/sys/mod.rs:4-166

System Services

All services are initialized as Option<nn::<service>::State> and start as None. Example from core/src/sys/mod.rs:
#[derive(Default)]
pub struct Services {
    pub acc: Option<nn::acc::State>,        // Account services
    pub hid: Option<nn::hid::State>,        // Human Interface Devices
    pub fs: Option<nn::fs::State>,          // Filesystem
    pub vi: Option<nn::vi::State>,          // Visual/Display
    pub gpu: Option<nn::gpu::State>,        // Graphics
    // ... 150+ more services
}

Performance Characteristics

Build Configuration Impact

Command: cargo runPerformance:
  • ~10-100x slower than release
  • Includes debug symbols and assertions
  • No optimizations
  • Large binary size (~500MB with debug info)
Use for:
  • Development and debugging
  • Running in debuggers (gdb/lldb)
  • Quick iteration

Troubleshooting Runtime Issues

Cause: Missing Vulkan drivers or GPU compatibility.Diagnosis:
# Check Vulkan support
vulkaninfo | head -20
Solutions:
  • Linux: Install vulkan-tools and your GPU’s Vulkan driver
  • Windows: Update GPU drivers from manufacturer
  • macOS: Ensure MoltenVK is installed (should be automatic)
Cause: Permission denied or read-only filesystem.Solution: Run from a writable directory:
cd ~/oboromi
cargo run
Cause: Unicorn Engine deadlock or infinite loop in test.Solution:
  1. Check oboromi.log for last instruction executed
  2. File an issue with the test case
  3. Try release mode: cargo run --release
Cause: eframe initialization failure.Check:
RUST_BACKTRACE=1 cargo run 2>&1 | tee error.log
Common causes:
  • Missing assets/oboromi_logo.png (embedded in binary)
  • Graphics driver crash
  • Insufficient memory
Cause: eframe’s ctx.request_repaint() is called unconditionally during splash animation.Workaround: Let the splash finish (~1.6 seconds), then CPU usage drops to near-zero when idle.See gui/src/gui/gui.rs:130 where request_repaint() is called.

Architecture Components

When oboromi runs, these modules are initialized:

Core Modules (core/src/lib.rs)

pub mod cpu;    // ARM64 emulation via Unicorn
pub mod fs;     // Virtual filesystem
pub mod gpu;    // SM86 GPU stub
pub mod nn;     // HLE firmware services
pub mod sys;    // System state management
pub mod tests;  // CPU test suite

CPU Manager

From core/src/cpu/mod.rs:
pub mod unicorn_interface;  // Unicorn Engine bindings
pub use unicorn_interface::UnicornCPU;
pub mod cpu_manager;        // Multi-core orchestration
The 8-core ARMv8 CPU is managed through cpu_manager, which coordinates execution across cores using the Unicorn Engine.

GPU State

From core/src/sys/mod.rs:170-178:
pub struct State {
    pub services: Services,
    pub gpu_state: gpu::State,
}

impl State {
    pub fn new() -> Self {
        Self {
            services: Services::default(),
            gpu_state: gpu::State::default()
        }
    }
}
The GPU state is initialized but currently non-functional (SM86 stub only).

What’s Next

Understanding CPU Tests

Learn what the CPU tests validate

Architecture Deep Dive

Explore the emulator’s design

Contributing Tests

Help expand test coverage

GPU Emulation

Understand SM86 GPU emulation

Advanced Usage

Running Specific Test Cases

Currently, all tests run together via the GUI. To run specific tests, you’ll need to modify core/src/tests/run.rs or invoke test functions directly in your own Rust code:
use oboromi_core::tests::run::run_tests;

fn main() {
    let results = run_tests();
    for line in results {
        println!("{}", line);
    }
}

Integration with Other Tools

The core library can be used as a dependency:
your-project/Cargo.toml
[dependencies]
oboromi-core = { path = "../oboromi/core" }
Then:
use oboromi_core::cpu::UnicornCPU;
use oboromi_core::sys::State;

fn main() {
    let mut state = State::new();
    // Use the emulator programmatically
}

Community & Support