Skip to content

Nintendo 3DS

codingncaffeine edited this page May 26, 2026 · 3 revisions

Nintendo 3DS (Azahar)

Overview

Azahar is the successor to Citra, formed by merging PabloMK7's Citra fork with Lime3DS after the original Citra project was taken down. It requires OpenGL Core >= 3.3 and uses hardware-accelerated rendering via the libretro HW render interface.

ROM Formats

Extension Format
.3ds / .cci Cartridge dump (most common)
.cia Install package
.cxi Executable content
.3dsx Homebrew
.app Raw application data

ROMs must be decrypted — encrypted dumps will not load. No BIOS files are required.

Teardown

Azahar's GPU thread continues cleanup after retro_unload_game returns. Calling context_destroy during this window causes a null-pointer AV (READ 0x8) inside the core — the same pattern seen with PPSSPP.

Fix: Skip context_destroy and call retro_deinit on the emu thread while the GL context is still active. The quarantine delay before wglDeleteContext gives the core's internal threads time to drain safely.

NATIVE AV in [azahar_libretro.dll] RVA=0x2E5B4D: READ addr=0x0000000000000008

Saves

Azahar uses libretro_saves = true — it manages its own save files internally using the save directory path provided by the frontend (BatterySaves/3DS/). The standard retro_get_memory_data SRAM interface returns zero size (no-op).

Input Map

The full RetroPad mapping exposed by the core:

3DS Input RetroPad
D-pad D-pad
Circle Pad Left Analog
C-Stick (New 3DS) Right Analog
A, B, X, Y Face buttons
L, R L, R
ZL (New 3DS) L2
ZR (New 3DS) R2
Start, Select Start, Select
Home / Swap screens L3
Touch screen touch R3

Touch Screen

Touch input on 3DS is driven through the right analog stick (cursor) and the Touch button (tap), not direct mouse-click. This matches the binding scheme defined by the Azahar core itself:

  • Move the cursor on the bottom screen by tilting the right analog stick.
  • Tap by pressing the Touch button (libretro R3, defaulting to right-stick-click on gamepads).

Bind a key or button to Touch in Preferences → Controls for 3DS just like any other button. On a controller, right-stick-click is the natural fit and matches the libretro convention.

The mouse-as-touchscreen path that other libretro cores use is not currently reliable in Azahar (see RetroArch#18911) — the right-stick + Touch button combo is the working path.

Visual Upgrades

Azahar renders at native 400x240 (top screen). The Vulkan HW renderer supports significant upscaling:

Option Native Upscaled (suggested)
citra_resolution_factor 1 4 or 5
citra_texture_filter none ScaleForce or xBRZ
citra_texture_sampling GameControlled Linear (smoother, slight softening)
citra_use_hw_shader enabled enabled
citra_use_shader_jit enabled enabled

All options take effect immediately without restarting the game. Resolution factors above 5x have diminishing returns on the 3DS's small native resolution and may drop frames on mid-range GPUs.

RetroAchievements

The rcheevos library (v11.1+) includes 3DS hash support — Emutastic generates hashes correctly for .3ds, .cci, .cia, and .3dsx ROMs. However, 3DS is not yet a supported RetroAchievements system. No achievement sets have been authored and the RA server returns "Unknown game" for all 3DS hashes.

The rcheevos console ID for 3DS is 62 (RC_CONSOLE_NINTENDO_3DS). Note: this differs from the RA web API's console numbering.

Encrypted ROM Hashing

3DS cartridge dumps can be encrypted (NCCH encryption). The rcheevos hash function requires AES key derivation callbacks (get_3ds_ncch_normal_keys, get_3ds_cia_normal_key) to decrypt partition headers during hashing. Emutastic implements the 3DS key scrambler algorithm: NormalKey = ROL128((ROL128(KeyX, 2) XOR KeyY) + C, 87) where C = 0x1FF9E9AAC5FE0408024591DC5D52768A. Decrypted dumps hash without needing these callbacks.

Clone this wiki locally