Skip to main content

Introduction

Oboromi is a work-in-progress Nintendo Switch 2 emulator written in Rust. The architecture is designed around accurate emulation of the Switch 2 hardware through a modular system that separates CPU, GPU, memory management, and firmware services.

Core Components

CPU Emulation

ARMv8 CPU emulation with 8 cores using Unicorn Engine

GPU Emulation

SM86 GPU with SASS to SPIR-V translation and Vulkan backend

Memory Management

12GB unified shared memory system across all cores

Firmware Services

High-level emulation of 160+ Nintendo services

System Architecture

The emulator follows a layered architecture:

Module Organization

The codebase is organized into the following core modules:

core/src/cpu/

Handles CPU emulation including:
  • cpu_manager.rs: Multi-core CPU management with 8 ARMv8 cores
  • unicorn_interface.rs: Safe wrapper around Unicorn Engine
  • Memory mapping and register management

core/src/gpu/

Manages GPU emulation:
  • mod.rs: GPU state and Vulkan initialization
  • sm86.rs: SM86 instruction decoder for NVIDIA Ampere architecture
  • sm86_decoder_generated.rs: Generated instruction decoder (254+ instructions)
  • spirv.rs: SPIR-V emission for shader translation

core/src/nn/

Firmware services (Nintendo Network APIs):
  • 160+ service stubs for system calls
  • Macro-based service generation
  • Service initialization and dispatch

core/src/sys/

System state management:
  • Service container holding all active services
  • GPU state integration
  • Global system initialization

Design Principles

Oboromi uses High-Level Emulation (HLE) for firmware services rather than Low-Level Emulation (LLE). This means services are reimplemented in Rust rather than running original Switch 2 firmware code.

Key Design Decisions

  1. Shared Memory Architecture: All 8 CPU cores share a single 12GB memory space mapped through Unicorn’s mem_map_ptr, enabling true multicore memory coherency
  2. SPIR-V as IR: GPU shaders are decoded from SASS (SM86 binary) to SPIR-V intermediate representation, then executed via Vulkan
  3. Macro-Generated Services: The 160+ firmware services use Rust macros to generate boilerplate, reducing code duplication
  4. Pinned Memory: The shared memory buffer is pinned using Pin<Box<[u8]>> to ensure pointers remain valid across the program lifetime

Performance Characteristics

The emulator requires a 64-bit host architecture to address the full 12GB memory space. The compile_error! check enforces this at compile time.

Memory Allocation

// From core/src/cpu/cpu_manager.rs:24
let shared_memory = Pin::new(vec![0u8; MEMORY_SIZE as usize].into_boxed_slice());
On modern operating systems, this 12GB allocation is lazily allocated through virtual memory, meaning physical RAM is only consumed as pages are written.

Core Scheduling

Currently, cores execute in round-robin fashion sequentially. Future versions will support true parallel execution:
// core/src/cpu/cpu_manager.rs:48
pub fn run_all(&self) {
    // for now, just step all cores sequentially (round-robin)
    // in the future, this would be threaded
    for (_i, core) in self.cores.iter().enumerate() {
        core.step();
    }
}

Development Status

This is a work-in-progress emulator. Most instructions and services are stubbed with todo!() macros. The architecture is being built from the ground up with accuracy in mind.

Implemented Components

  • ✅ CPU manager with 8-core initialization
  • ✅ Shared memory setup
  • ✅ Unicorn integration for ARMv8
  • ✅ SM86 decoder skeleton (254+ instruction definitions)
  • ✅ SPIR-V emitter with full instruction set
  • ✅ Service registration system (160 services)
  • ✅ Vulkan initialization

In Progress

  • 🚧 SM86 instruction implementations
  • 🚧 SASS to SPIR-V translation logic
  • 🚧 Service implementations
  • 🚧 Multithreaded core execution
  • 🚧 File system emulation
  • 🚧 Graphics pipeline

Next Steps

To learn more about specific subsystems, explore the detailed architecture pages: