Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/azahar-emu/azahar/llms.txt

Use this file to discover all available pages before exploring further.

Azahar organizes all emulation work through a central Core::System singleton (defined in src/core/core.h). When you load a game, System::Load() initializes every subsystem in dependency order — memory, kernel, CPU cores, DSP, GPU — then hands control to System::RunLoop(), which drives the ARM11 CPU and schedules hardware events until the game exits or you request a reset.

Top-level subsystems

ARM CPU backends

One or more Core::ARM_Interface instances execute ARM11 machine code. Azahar selects either the Dynarmic JIT or the Dyncom interpreter at startup based on your platform and settings.

HLE kernel

Kernel::KernelSystem (in src/core/hle/kernel/kernel.h) manages processes, threads, IPC sessions, shared memory, timers, and resource limits — all without running real 3DS kernel code.

Memory subsystem

Memory::MemorySystem (in src/core/memory.h) owns the page tables and physical memory regions that back every address space in the emulated system.

Audio DSP

AudioCore::DspInterface (in src/audio_core/dsp_interface.h) is the abstract base for HLE and LLE audio emulation. The concrete backend is chosen at runtime and exposed on System via System::DSP().

Video / GPU

VideoCore::GPU (in src/video_core/gpu.h) is the high-level GPU interface. It owns the PICA200 emulation core (Pica::PicaCore) and the active renderer backend.

Service manager

Service::SM::ServiceManager (accessed via System::ServiceManager()) bootstraps all HLE service modules and routes IPC requests from emulated processes.

ARM CPU emulation

The abstract base class Core::ARM_Interface (in src/core/arm/arm_interface.h) defines the contract every CPU backend must satisfy:
// src/core/arm/arm_interface.h
class ARM_Interface : NonCopyable {
public:
    virtual void Run() = 0;
    virtual void Step() = 0;
    virtual void ClearInstructionCache() = 0;
    virtual void InvalidateCacheRange(u32 start_address, std::size_t length) = 0;
    virtual void SetPC(u32 addr) = 0;
    virtual u32  GetPC() const = 0;
    virtual void SaveContext(ThreadContext& ctx) = 0;
    virtual void LoadContext(const ThreadContext& ctx) = 0;
    virtual void PrepareReschedule() = 0;
    // ...
};
System holds a std::vector<std::shared_ptr<ARM_Interface>> for multi-core support (the 3DS has two ARM11 cores) and exposes System::GetCore(u32 core_id) and System::GetRunningCore(). Two backends are available:
BackendLocationDescription
Dynarmicsrc/core/arm/dynarmic/JIT recompiler. Translates ARM11 blocks to native x86-64 or AArch64 code at runtime. Available on x86-64 and arm64 builds (#if CITRA_ARCH(x86_64) || CITRA_ARCH(arm64)). Recommended for performance.
Dyncomsrc/core/arm/dyncom/Interpreter. Executes one ARM11 instruction at a time via a dispatch loop. Slower but portable to any host architecture.
Dynarmic is selected automatically on x86-64 and arm64 hosts. Dyncom serves as the fallback on other architectures and as the single-step backend used by the GDB stub.

HLE kernel

Kernel::KernelSystem (in src/core/hle/kernel/kernel.h) re-implements the 3DS operating system kernel in host C++ rather than running 3DS firmware. It creates and manages:
  • Processes (Process, src/core/hle/kernel/process.h) — loaded from NCCH executables by the app loader
  • Threads (Thread, src/core/hle/kernel/thread.h) — scheduled cooperatively by ThreadManager across both ARM11 cores
  • SynchronizationMutex, Semaphore, Event, Timer, AddressArbiter (one source file per primitive in src/core/hle/kernel/)
  • IPC sessionsClientPort, ServerPort, ClientSession, ServerSession handle the 3DS inter-process communication protocol
  • Virtual memoryVMManager (in src/core/hle/kernel/vm_manager.h) manages per-process address spaces
  • Shared memorySharedMemory allows GPU and DSP shared pages to be mapped into process address spaces
The kernel exposes a std::recursive_mutex hle_lock that serializes all HLE state access from the CPU thread. IPC traffic can be recorded for debugging through IPCDebugger::Recorder (in src/core/hle/kernel/ipc_debugger/).

HLE services

src/core/hle/service/ contains high-level implementations of every 3DS system service, organized by module:
  • APT (service/apt/) — Application Manager, applet lifecycle, AppletManager
  • FS (service/fs/) — File system access; bridges to archive backends via Service::FS::ArchiveManager
  • GSP (service/gsp/) — Graphics service; relays GPU commands and interrupt signals to VideoCore::GPU
  • DSP (service/dsp/) — Audio DSP interface; forwards pipe reads/writes to AudioCore::DspInterface
  • HID (service/hid/) — Input (buttons, touch screen, accelerometer, gyroscope)
  • CAM (service/cam/) — Camera interface
  • MIC (service/mic/) — Microphone; checks host OS permission via System::HasMicPermission()
  • IR (service/ir/) — Infrared remote and extra buttons
  • PLGLDR (service/plgldr/) — Plugin loader (Luma3DS-compatible)
  • SM (service/sm/) — Service Manager; the root registry used by all other services

Memory subsystem

Memory::MemorySystem (declared in src/core/memory.h) manages the full 32-bit ARM11 physical address space. It provides the page tables consumed by both CPU backends (ARM_Interface::SetPageTable()). The kernel’s VMManager builds per-process virtual-to-physical mappings on top of this system.
On real hardware the 3DS has either 128 MB (Old 3DS) or 256 MB (New 3DS) of FCRAM. Azahar selects the active memory mode through Kernel::MemoryMode (values Prod, Dev1Dev4, NewProd, NewDev1) when initializing KernelSystem.

File system

The file system layer lives in src/core/file_sys/. An abstract ArchiveBackend interface covers every storage medium the 3DS exposes, and Service::FS::ArchiveManager routes fs:USER/fs:LDR IPC requests to the correct backend:
Archive backendHeaderDescription
ArchiveSdmcarchive_sdmc.hSD card — maps to the host sdmc/ directory
ArchiveNandarchive_nand.hNAND storage — maps to nand/ on the host
ArchiveNccharchive_ncch.hRead-only ROM filesystem inside an NCCH partition
ArchiveSaveDataarchive_savedata.hPer-title save data
ArchiveExtSaveDataarchive_extsavedata.hExtended save data (shared between titles)
ArchiveSelfNccharchive_selfncch.hSelf-referencing archive for the running title’s own RomFS
ArchiveSystemSaveDataarchive_systemsavedata.hSystem-wide save data (e.g., Mii data)
ArchiveArticarchive_artic.hRemote cartridge access over the Artic Base network protocol
Layered patches are handled by LayeredFS (layered_fs.h), which intercepts RomFS reads and substitutes files from the host.

App loader

src/core/loader/ provides format-specific loaders that all derive from Loader::AppLoader (in loader/loader.h). Azahar selects the right loader based on the file extension and magic bytes:
LoaderFileSupported formats
AppLoader_NCCHncch.h.3ds, .cci, .cxi, .app (NCCH/CCI cartridge images)
AppLoader_ELFelf.h.elf (raw ARM ELF binaries)
AppLoader_3DSX3dsx.h.3dsx (homebrew portables)
AppLoader_Articartic.hRemote cartridge streaming over Artic Base

Additional core systems

Movie recording

Core::Movie (src/core/movie.h) records and plays back input sequences for TAS and bug reproduction. System::Movie() exposes the instance.

Save states

System::SaveState(u32 slot) and System::LoadState(u32 slot) serialize the full emulator state using Boost.Serialization. Buffer-based variants (SaveStateBuffer / LoadStateBuffer) support in-memory snapshots.

GDB stub

src/core/gdbstub/ implements the GDB Remote Serial Protocol. When enabled at compile time (ENABLE_GDBSTUB), GDBStub::HandlePacket() is called each run-loop iteration so a debugger can step, inspect registers, and set breakpoints.

RPC server

src/core/rpc/ (Core::RPC::Server) provides a scripting interface when built with ENABLE_SCRIPTING. It lets external tools read and write emulated memory and trigger events.

Network / multiplayer

src/network/ implements the multiplayer room system. Peers exchange packets over the network and System relays them through the HLE NWM (network module) service.

Cheat engine

Cheats::CheatEngine (src/core/cheats/cheats.h) applies GameShark-style memory patches each frame. System::CheatEngine() exposes the instance.

Frontend integration

Azahar’s core is frontend-agnostic. The two official frontends are:
  • citra_qt — the desktop Qt6 frontend. It creates a Frontend::EmuWindow subclass backed by an OpenGL or Vulkan surface, registers applet implementations (Frontend::MiiSelector, Frontend::SoftwareKeyboard), and drives System::RunLoop() from a dedicated emulation thread.
  • Android — the Android frontend wraps the same Core::System API and renders into a SurfaceView using the same renderer backends.
Frontends register themselves with System before calling System::Load():
// Pseudocode — typical frontend initialization sequence
system.RegisterMiiSelector(mii_selector_impl);
system.RegisterSoftwareKeyboard(swkbd_impl);
system.RegisterImageInterface(image_interface_impl);
system.RegisterVideoDumper(video_dumper_backend);
system.Load(emu_window, rom_path);
Frontend::EmuWindow (in src/core/frontend/) is the abstract window interface that the renderer uses to swap buffers, query the framebuffer layout, and receive surface-change notifications.

Build docs developers (and LLMs) love