Spec version: 0.4 draft
Primary spec file: SPEC.md
Companion overview file: README.md
Project name: Nx86
Project type: GUI-first Nintendo Switch emulator and AArch64-to-x86_64-v4 native binary translation system
Primary compilation technique: Profile-Guided Feedback-Directed Binary Translation
Product name for compilation technique: Continuous Dynamic Compilation
Primary implementation language: Rust
Primary GUI framework: heavily customized egui
Initial OS target: Linux
Initial CPU target: desktop x86_64-v4
Initial graphics backend: Vulkan
Future graphics backend: D3D12
Initial test target: synthetic ARM64 programs
First real software target: homebrew
v1 aspirational title target: The Legend of Zelda: Tears of the Kingdom
Development model before v1.0: closed source
Planned v1.0 license: GPLv3
Main design goal: make Switch software run as natively as possible on desktop x86_64-v4 hardware
Ultimate goal: generate a portable Pure AOT native title folder that no longer requires the full Nx86 emulator application
This specification uses requirement language inspired by RFC-style documents.
- MUST means the feature or behavior is required.
- MUST NOT means the feature or behavior is forbidden.
- SHOULD means the feature or behavior is strongly recommended.
- SHOULD NOT means the feature or behavior should be avoided.
- MAY means the feature or behavior is optional.
- FUTURE means it is intentionally not required in early versions but remains part of the long-term architecture.
Nx86 is intentionally ambitious. Some requirements describe the long-term destination rather than the first implementation milestone.
Nx86 is a GUI-first Nintendo Switch emulator designed around aggressive native recompilation.
Traditional emulators typically execute guest code through an interpreter or runtime JIT. Nx86 instead treats JIT as a fallback and discovery system. Nx86 attempts to analyze, lift, optimize, and compile as much guest AArch64 code as possible into native x86_64-v4 machine code before the user launches a title.
Runtime execution produces profile data. That data is fed back into future compilation passes. Over time, Nx86 should need less JIT, fewer runtime helpers, fewer slowmem paths, and fewer dynamic fallbacks.
This strategy is called:
Continuous Dynamic Compilation
The formal technical name is:
Profile-Guided Feedback-Directed Binary Translation
Nx86 is not designed for instant launch. Nx86 accepts longer first-time compilation and large caches to improve runtime smoothness, reduce translation overhead, and eventually enable Pure AOT output.
Core concept:
Compile before play.
Run as native as possible.
Profile every fallback.
Promote runtime discoveries.
Rebuild better native code.
Move toward 100% Native Coverage.
Nx86 is a GUI-first Nintendo Switch emulator built around Continuous Dynamic Compilation, a Profile-Guided Feedback-Directed Binary Translation system that aggressively recompiles AArch64 code, shaders, runtime-discovered code paths, and title-specific behavior into native x86_64-v4 output, with the long-term goal of producing a portable Pure AOT title folder that can run without the full Nx86 emulator application.
Nx86 follows these principles:
- AOT first.
- JIT only when necessary.
- Interpreter usage during gameplay is a bug.
- Native Coverage should trend toward 100%.
- Runtime feedback is compiler input.
- Long compilation is acceptable.
- Large caches are acceptable.
- Desktop x86_64-v4 performance comes first.
- Accuracy matters.
- Performance wins when correctness is preserved.
- Complexity is hidden by default.
- Compiler internals are available to advanced users.
- The GUI should be clean and casual.
- The developer tools should be powerful.
- The endgame is a native PC-style title folder.
Nx86 is not a normal JIT emulator.
Nx86 is a native recompilation system wrapped in a clean emulator frontend.
The official project name is:
Nx86
Meaning:
NX = Nintendo Switch codename
x86 = primary native host architecture family
Nx86 should feel:
- clean
- casual
- polished
- fast
- technical but approachable
- not corporate
- not terminal-first
- not visually overwhelming by default
The visual target is:
clean emulator frontend
+
visual compiler dashboard
+
optional deep compiler/debugger tooling
Nx86 MUST hide complexity by default.
Casual users should see:
- titles
- compile status
- launch button
- Native Coverage
- compatibility status
- simple cache status
- clear errors
Advanced users should be able to open:
- logs
- disassembly
- CFG view
- NxIR view
- native x86 view
- register allocation view
- guard/deopt view
- VMM view
- scheduler view
- shader/pipeline view
- crash analysis
Nx86 MUST:
- Be a real Nintendo Switch emulator.
- Be GUI-first.
- Use egui with heavy customization.
- Target desktop Linux x86_64-v4 first.
- Use a custom compiler backend from the start.
- Use a shared IR for AOT and JIT.
- Require initial compilation before launching a title.
- Avoid run-while-compiling behavior.
- Use JIT only as an emergency/discovery path.
- Treat interpreter execution during gameplay as a bug.
- Maintain an internal title database.
- Organize titles by title ID.
- Support file import, folder import, and library scanning.
- Allow content to be referenced, copied, or moved.
- Store AOT/cache/profile data inside Nx86-managed folders.
- Support multiple storage locations.
- Refuse unknown/invalid imports until v2.
- Support updates and DLC.
- Create separate caches for title/update versions when executable code changes.
- Automatically invalidate affected caches when executable hashes change.
- Use many small native code objects.
- Support memory-mapped and RAM-loaded code objects.
- Avoid cache compression by default.
- Garbage collect old caches.
- Perform shallow cache checks every launch.
- Perform full verification after updates or crashes.
- Reserve a 64 GB virtual address arena at startup.
- Use a VMM from day one.
- Support fastmem and slowmem.
- Count slowmem as unoptimized/non-native for coverage.
- Support memory mirroring in release.
- Disable memory mirroring in debug.
- Support executable page hashing.
- Support self-modifying code detection.
- Log executable writes with call stack and source block.
- Support guest threading from day one.
- Support optional fiber/task scheduling.
- Support deterministic scheduling as a hidden developer option.
- Save crash-window replay logs.
- Analyze crash logs to improve rebuilds.
- Support shader AOT in v1.
- Use Vulkan first.
- Add D3D12 later.
- Support runtime-level FPS unlock.
- Support resolution scaling globally and per title.
- Support Guarded Speculative Optimization.
- Support title behavior patches.
- Allow required behavior patches to be enabled and undisableable.
- Support profile sharing with user approval.
- Require profile sanitization before export.
- Support signed verified profiles.
- Support centralized and decentralized profile distribution.
- Use SQLite plus human-readable sidecars.
- Provide a README and a separate SPEC.md.
- Use strict requirement language in SPEC.md.
- Include issue templates.
- Include a detailed roadmap.
- Eventually produce Pure AOT title folders.
- Eventually support native PC-style executable output.
- Keep the project architecture broad enough to target TOTK-class titles.
Nx86 MUST NOT:
- Be a JIT-first emulator.
- Prioritize instant launch over native compilation.
- Treat interpreter fallback as normal gameplay behavior.
- Hide all compiler tooling from advanced users.
- Compress native caches by default.
- Run multiple games at once.
- Automatically upload profile data.
- Automatically download shared profiles without approval.
- Show Pure AOT to normal users before it is real.
- Present Pure AOT as available before 100% readiness.
- Require a central private server controlled by the developer.
- Ship copyrighted game assets.
- Ship game dumps.
- Ship proprietary firmware.
- Ship console keys.
- Ship proprietary SDK code.
- Include copyrighted binary blobs in shared profiles.
- Include saves in shared runtime profiles.
- Include personal user data in shared profiles.
- Allow invalid imports before v2.
Nx86 may operate on user-provided legally obtained content.
Nx86 MUST NOT ship:
- copyrighted game dumps
- proprietary firmware
- console keys
- copyrighted assets
- proprietary SDK code
- copied binary blobs in shared profiles
- shared save files
- extracted copyrighted runtime data
Nx86 MAY create a local Pure AOT title folder for the user's own local use.
If Nx86 copies user-provided game content/assets into a local Pure AOT folder, that folder MUST include a legal.txt warning.
Example legal.txt intent:
This folder may contain user-owned game content and generated Nx86 native code.
Do not redistribute this folder.
Do not upload it.
Do not share it.
This folder is intended only for local use by the person who legally provided the original content.
legal.txt is a warning and documentation mechanism. It does not magically make redistribution legal.
Nx86 SHOULD reimplement every system, service, runtime, and firmware behavior that can reasonably be reimplemented.
Nx86 MUST NOT be designed as a firmware-first emulator.
The preferred compatibility strategy is:
clean-room reimplementation
↓
high-level emulation
↓
native Nx86 runtime service
↓
stub only when safe
↓
user-provided local system file fallback only when unavoidable
Nx86 MUST NOT ship firmware, system archives, console keys, proprietary SDK code, or copyrighted system components.
Nx86 MUST NOT include instructions, links, workflows, or tooling for obtaining console keys, dumping firmware, bypassing encryption, or sharing system files.
Nx86 MAY support user-provided local system files when required for compatibility, but this MUST be treated as a compatibility fallback rather than the preferred architecture.
For synthetic ARM64 tests, homebrew, and Pure AOT research, Nx86 SHOULD avoid requiring firmware or keys entirely.
For commercial title compatibility, Nx86 SHOULD reimplement as much Horizon-like service behavior as possible through clean-room HLE and native Nx86 runtime libraries.
Nx86 SHOULD prioritize reimplementing:
- process management
- thread management
- synchronization primitives
- virtual memory behavior
- filesystem services
- save data services
- input services
- gamepad services
- audio services
- graphics services
- shader translation
- GPU pipeline management
- applet/service stubs
- account/user service stubs
- settings service stubs
- time services
- network service stubs
- error/reporting services
- logging services
- runtime loader behavior
Firmware or user-provided system files MAY be supported only when:
- the behavior cannot yet be accurately reimplemented
- the user provides the files locally
- Nx86 does not redistribute them
- Nx86 does not provide acquisition instructions
- the fallback is clearly marked as compatibility-only
- the long-term goal remains reimplementation
Pure AOT output SHOULD depend on Nx86’s own native runtime libraries rather than proprietary firmware files.
A Pure AOT title folder SHOULD include Nx86-provided runtime libraries for:
- input
- audio
- graphics
- filesystem behavior
- service behavior
- windowing
- gamepad support
- title-specific compatibility behavior
Pure AOT SHOULD NOT require the full Nx86 emulator app.
The long-term goal is for Nx86 to replace firmware/runtime dependency with clean-room native runtime components wherever possible.
Nx86 initially targets:
OS: Linux
CPU: x86_64-v4
Graphics: Vulkan thru ash
GUI: egui
Nx86 SHOULD eventually support:
- x86_64-v3
- generic x86_64
- ARM64 hosts
- Windows
- D3D12
- handheld PCs
The first backend SHOULD assume desktop-class x86_64-v4.
It MAY use:
- wide vector instructions
- many vector registers
- mask registers
- aggressive register allocation
- large native code objects
- profile-guided layout
- AVX-512-style lowering
- hot/cold splitting
- direct block chaining
- helper inlining in maximum optimization mode
The v4 backend SHOULD NOT compromise its design for handheld targets during early development.
Nx86 SHOULD use ash for the Vulkan backend.
ash is preferred because Nx86 requires low-level Vulkan control for shader translation, pipeline cache management, descriptor layout control, synchronization, command buffer recording, memory management, debug tooling, and future vendor-specific optimization.
Nx86 MUST wrap ash behind an internal nx86-vulkan abstraction. Raw Vulkan handles and unsafe Vulkan calls SHOULD NOT leak into higher-level emulator crates.
Higher-level graphics crates such as wgpu or vulkano are not preferred for the core renderer because Nx86 needs explicit Vulkan behavior rather than a portability abstraction.
Nx86 MUST include a first-launch wizard.
The wizard SHOULD configure:
- game library folders
- cache folder
- profile folder
- import behavior
- copy/move/reference behavior
- CPU target
- compile thread cap
- all-core warning
- cache size
- profile sharing
- profile upload approval
- profile download approval
- graphics backend
- shader AOT behavior
- controller/input behavior
- developer mode visibility
Add title
↓
Scan title
↓
Create title folder
↓
Compile required native cache
↓
Launch title
↓
Profile missing paths
↓
Rebuild cache later
↓
Improve Native Coverage
Nx86 MUST NOT default to running titles while AOT compilation continues.
Nx86 is not trying to be an instant-boot emulator.
The user-facing model is:
Compile first.
Then play.
Nx86 MUST support:
- importing a file
- importing a folder
- scanning a library folder
- manual import
- automatic library rescans
Nx86 SHOULD allow:
- reference in place
- copy into Nx86 folder
- move into Nx86 folder
AOT output, cache data, profile data, shader data, and reports MUST live in Nx86-managed storage.
Unknown or invalid files MUST be refused until v2.
The v1-era importer should avoid ambiguous “maybe valid” imports.
The Inspector MAY inspect a title even if the title cannot compile.
If the title can run only partially, Nx86 MAY use JIT to run it as compiled as possible.
Nx86 MUST maintain an internal title database.
The database SHOULD use:
SQLite + human-readable sidecar files
SQLite handles:
- indexing
- title lookup
- cache lookup
- update tracking
- profile tracking
- crash report indexing
- compatibility history
- shader cache indexing
Sidecar files handle:
- readable metadata
- per-title settings
- compatibility notes
- compile reports
- profile summaries
- title profile config
- developer notes
Nx86 organizes games by title ID.
Example:
Nx86/
├── titles/
│ └── 0100ABCD12345678/
│ ├── title.nxmeta
│ ├── settings.toml
│ ├── legal.txt
│ ├── content/
│ ├── versions/
│ ├── updates/
│ ├── dlc/
│ ├── cache/
│ │ ├── cpu/
│ │ ├── jit-promoted/
│ │ ├── shaders/
│ │ ├── pipelines/
│ │ └── rollback/
│ ├── profiles/
│ ├── reports/
│ ├── logs/
│ ├── crash/
│ └── inspector/
├── database/
├── shared-profiles/
├── global-cache/
└── config/
Each title folder SHOULD contain:
- title metadata
- user settings
- version metadata
- update metadata
- DLC metadata
- CPU native cache
- promoted JIT cache
- shader cache
- pipeline cache
- runtime profiles
- compile reports
- crash reports
- logs
- inspector exports
- legal warnings if content is copied
- Nx86 MUST maintain title metadata separately from imported content.
- Nx86 MUST support metadata sidecars stored under each title folder.
- Nx86 MUST support local media cache paths for poster/icon/banner/screenshots.
- Nx86 MUST distinguish between:
- user-provided metadata
- filename-derived metadata
- bundled/local database metadata
- optional online metadata
- unknown/fallback metadata
- Nx86 MUST assign a confidence level to metadata.
- Nx86 MUST preserve import success when metadata lookup fails.
- Nx86 MUST never require network access for import.
- Nx86 MUST make online metadata lookup explicit and opt-in.
- Nx86 MUST store media files locally only after explicit user/provider action.
- Nx86 MUST keep local paths out of shareable profiles.
- Nx86 MUST allow users to refresh metadata.
- Nx86 MUST allow users to override bad metadata later.
- Nx86 MUST display reasonable fallbacks:
- canonical name if available
- display name from filename if available
- otherwise
Title <TITLE_ID>
- Nx86 MUST NOT infer authenticity of commercial content from metadata.
- Nx86 MUST NOT treat metadata provider results as proof that a title is valid, legal, decrypted, bootable, or compilable.
- Nx86 MAY parse only plaintext container structure (PFS0/HFS0 partition file tables) with bounded reads and no decryption, to recover title identity (e.g. the title ID from a ticket file name). Recovering metadata by decrypting commercial content is permitted only through the explicitly separate, opt-in, user-provided-key mode described below — never as part of the default import path.
Nx86 recovers title metadata from these sources, in decreasing trust:
- User sidecar — a user-authored metadata sidecar under the title folder.
- User-provided-key extraction — opt-in, local-only decryption of the user's own content with their own keys (see the keys section below).
- Bundled/local database — a user-imported community title database
(
metadata-local.json). Nx86 ships no such data. - Optional online provider — explicit, opt-in network lookup that may also
download poster/icon/banner media into the per-title
media/folder. - Filename-derived — the display name and title ID tokens from the file name.
- Unknown/fallback —
Title <TITLE_ID>.
Structural title-ID recovery (rule 16 above) reconciles a wrong or renamed file name against the container's plaintext ticket, and records a warning when they disagree.
- Nx86 MUST NOT ship proprietary firmware, console keys, title keys, tickets, certificates, or SDK blobs.
- Nx86 MUST NOT require firmware or keys for import, or for the default (keyless) metadata enrichment path.
- Key/firmware handling MUST live in a crate/mode that is explicitly separate from the default import metadata path and OFF by default.
- Any user-provided firmware/key compatibility mode must be explicitly separate from import metadata.
- Such support MUST be opt-in, local-only, non-distributive, use only user-supplied keys, and MUST NOT provide key/firmware acquisition or extraction instructions.
- Metadata provider results MUST NOT be used as proof of entitlement, authenticity, or decryptability.
- The project should continue to support homebrew/synthetic testing without firmware or keys.
- Media and names recovered from a user's own content (by keys or online) are stored locally only, kept out of shareable profiles (rule 10 above), and are never redistributed by Nx86.
Nx86 SHOULD use a multi-process architecture.
The GUI process handles:
- library UI
- title settings
- compile progress
- runtime status
- profile management
- cache management
- crash display
- user input to the app
- process supervision
The GUI process SHOULD NOT directly execute guest game code.
The compiler SHOULD run in a separate worker process.
Reasons:
- compiler crashes do not kill GUI
- memory usage is isolated
- long tasks can be restarted
- checkpointing is easier
- progress updates can stream over IPC
- future multi-worker compilation becomes easier
Each launched title MUST run in an isolated runtime process/state.
Reasons:
- stable VMM layout
- better crash isolation
- no cross-title memory corruption
- simpler process cleanup
- cleaner debugging
- safer native code execution
Nx86 MUST NOT support multiple games running simultaneously.
Nx86 SHOULD use a structured IPC layer between:
- GUI process
- compiler process
- runtime process
- profile/indexing process if separated later
IPC messages SHOULD be versioned.
IPC should support:
- progress events
- log events
- crash events
- compile task commands
- runtime launch commands
- profile upload/download commands
- cache operations
- cancellation
- pause/resume
Example IPC event:
CompileProgress {
title_id,
phase,
percent,
current_module,
functions_discovered,
functions_compiled,
native_coverage_estimate,
cache_size_bytes
}
Nx86 uses compile-before-play.
Initial compilation MUST:
- scan the title
- identify executable modules
- hash executable pages
- decode AArch64
- recover control flow
- lift to NxIR
- verify NxIR
- optimize NxIR
- generate x86_64-v4 native code
- emit many small native objects
- generate guard/deopt metadata
- compile shaders where possible
- prepare pipeline cache where possible
- write cache metadata
- write compile report
- estimate Native Coverage
The compiler SHOULD use all CPU cores by default.
Nx86 MUST warn the user before doing so.
The user MUST be able to cap compile thread count.
Compilation MUST be pausable.
Compilation MUST be resumable.
Compilation SHOULD checkpoint:
- title scan state
- hash state
- decoded instruction ranges
- discovered functions
- CFG recovery
- NxIR lifting state
- optimization state
- emitted object state
- shader compilation state
- profile ingestion state
- verification state
Compilation may produce:
- decoded instruction database
- function table
- CFG table
- NxIR dumps in debug/research
- native objects
- relocation tables
- guard tables
- deopt tables
- code maps
- shader objects
- pipeline cache data
- reports
Optimized NxIR SHOULD NOT be cached by default because native objects are the main persistent output.
Native Coverage is the main progress metric.
Native Coverage measures how much functional game code and GPU/shader/pipeline work has been compiled and prepared for use outside the full Nx86 emulator environment.
It is not merely “bytes compiled.”
Native Coverage answers:
How close is this title to being usable as Pure AOT native output?
Nx86 SHOULD track:
- CPU static coverage
- CPU executed coverage
- shader readiness
- pipeline readiness
- fastmem coverage
- slowmem count
- runtime helper count
- JIT fallback count
- deopt count
- interpreter usage
The main user-facing percentage SHOULD represent functional readiness toward Pure AOT.
Developer views MAY show detailed sub-metrics.
| Coverage | Label |
|---|---|
| 0.00% – 59.99% | Terrible |
| 60.00% – 89.99% | Poor |
| 90.00% – 97.99% | Great |
| 98.00% – 99.99% | Excellent |
| 100.00% | Perfect |
Perfect requires:
- 100% required CPU native readiness
- 100% shader/pipeline readiness
- no JIT requirement
- no interpreter requirement
- no unresolved runtime code paths
- no slowmem-dependent game logic paths that prevent Pure AOT
- valid Pure AOT folder generation
Fastmem is the ideal memory path.
Fastmem means a guest memory operation becomes a direct native host memory operation.
Conceptual path:
guest load/store
↓
native x86 load/store
Fastmem is considered native-ready.
Slowmem is runtime-checked memory access.
Conceptual path:
guest load/store
↓
call Nx86 memory helper
↓
check page tables/permissions/MMIO/state
↓
perform access or fault
Slowmem handles:
- MMIO
- protected pages
- unmapped pages
- page-boundary edge cases
- debug checks
- poison checks
- invalid access reports
- special service regions
Slowmem counts against Native Coverage because it depends on Nx86 runtime helper logic rather than pure native direct execution.
Nx86 SHOULD report:
- slowmem call count
- slowmem hot addresses
- slowmem source blocks
- slowmem reason
- slowmem-to-fastmem promotion opportunities
Pure AOT is the hidden endgame.
Pure AOT does not exist until 100% readiness is possible.
Pure AOT means:
No JIT.
No interpreter.
No full Nx86 emulator application required.
Native PC executable/folder output.
The current goal is:
folder with native code, copied local content, config, shaders, minimal runtime libraries, and launcher
The future goal is:
true PC-port-style executable
Pure AOT may still require bundled native Nx86 runtime libraries.
Examples:
- input/gamepad library
- windowing library
- GPU runtime library
- audio library
- filesystem shim
- service replacement library
- per-title special behavior library
These libraries replace the need for the full Nx86 emulator app.
Example:
Nx86PureAOT/
└── 0100ABCD12345678/
├── legal.txt
├── launch.sh
├── title.nxmeta
├── bin/
│ ├── game
│ ├── libnx86_runtime.so
│ ├── libnx86_input.so
│ ├── libnx86_gpu.so
│ ├── libnx86_audio.so
│ └── libnx86_services.so
├── native/
│ ├── main.so
│ ├── sdk.so
│ ├── subsdk0.so
│ └── objects/
├── content/
├── shaders/
├── pipelines/
├── config/
├── profiles/
└── reports/
Pure AOT MUST require:
- 100% Native Coverage
- no JIT
- no interpreter
- shader/pipeline readiness
- no unresolved guest code
- no unresolved runtime code path
- bundled minimal runtime libraries
- legal.txt
- validated content layout
- reproducible launch
Pure AOT SHOULD be hidden under advanced per-title settings.
Nx86 distinguishes between active compiler cache size and final Pure AOT output size.
The active Nx86 cache MAY be large. It may contain native objects, promoted JIT objects, shader caches, pipeline caches, profile logs, guard metadata, deopt metadata, rollback generations, debug maps, and compile reports.
Pure AOT output MUST be size-disciplined.
Pure AOT export SHOULD remove:
- unused native objects
- stale promoted JIT objects
- old profile logs
- rollback generations
- debug dumps
- temporary compiler data
- unused shader variants
- unused pipeline variants
- unused title profile data
- redundant metadata
Pure AOT export SHOULD apply:
- dead code elimination
- duplicate thunk merging
- unused runtime service pruning
- shader/pipeline pruning
- symbol stripping
- optional debug-symbol sidecar output
- object layout compaction
- runtime library deduplication
Nx86 SHOULD allow separate modes for:
- development cache
- release cache
- Pure AOT export
- Pure AOT debug export
The normal Nx86 cache is allowed to be large because it is a compiler workspace.
The Pure AOT folder should be as small as practical while preserving correctness, performance, and legal local-use boundaries.
Continuous Dynamic Compilation is the core Nx86 technique.
Initial compile
↓
Launch
↓
Runtime profile
↓
Emergency JIT if needed
↓
Log missing paths
↓
Promote discoveries
↓
Passive rebuild
↓
Higher Native Coverage
Nx86 records:
- indirect branch targets
- hidden entrypoints
- guard failures
- deopt events
- emergency JIT blocks
- runtime helper calls
- slowmem events
- executable writes
- scheduler events
- crashes
- shader usage
- pipeline usage
- hot blocks
- hot traces
- compatibility patches used
Passive rebuild SHOULD:
- read runtime profiles
- sanitize profile data
- identify new AOT candidates
- promote JIT blocks
- improve guards
- compile missing shader/pipeline data
- reduce slowmem use
- rebuild affected objects
- improve Native Coverage
- write reports
JIT is allowed but not primary.
Emergency JIT initially compiles:
single basic blocks
This prioritizes compile speed.
JIT uses the same IR/backend pipeline as AOT.
JIT prioritizes compile speed over maximum optimization.
JIT MAY patch AOT code.
Patching MUST happen at safe points.
Safe points include:
- block boundaries
- frame boundaries
- deopt boundaries
- runtime service boundaries
- scheduler yield points
JIT activity SHOULD be visible in an easy-to-access developer overlay.
Casual users should not be spammed with JIT activity.
Deoptimization allows speculative native code to recover when assumptions fail.
Nx86 MUST enforce:
No speculation without deopt.
No guard without recovery.
Deopt MUST reconstruct complete guest-visible state.
This includes:
- general registers
- SP
- PC
- NZCV flags
- lazy flag state
- FP registers
- SIMD registers
- FPCR
- FPSR
- thread state
- pending exception state
- service call state
- memory side-effect boundary
- active guard metadata
Deopt metadata SHOULD exist:
- inside native object files
- in sidecar files
Object metadata is for runtime.
Sidecar metadata is for GUI/debugging.
If deopt fails, Nx86 MUST crash loudly.
It MUST NOT continue with corrupted state.
NxIR is Nx86’s intermediate representation.
NxIR MUST:
- be close to AArch64 semantics
- preserve guest instruction boundaries
- support high-level operations
- track side effects explicitly
- support lazy flags
- support atomics
- support barriers
- support FP/SIMD
- support guards
- support deopt points
- support runtime helpers
- support debug annotations
- support serialization
- support verification
NxIR MUST preserve guest instruction boundaries for:
- debugging
- crash reports
- deopt
- differential testing
- GUI inspection
- native mapping
- profile feedback
- executable invalidation
NxIR SHOULD support high-level operations such as:
- memcpy
- memmove
- memset
- atomic wait
- atomic wake
- service call
- shader dispatch metadata
- runtime helper call
- sqrt
- vector shuffle
- memory fence
- block guard
- deopt checkpoint
NxIR MUST model side effects including:
- memory reads
- memory writes
- atomics
- barriers
- service calls
- MMIO
- exceptions
- FP status changes
- thread synchronization
- executable page writes
- guard dependencies
- deopt boundaries
The NxIR verifier MUST run after every optimization pass in debug and research modes.
It SHOULD be stripped from release builds.
The verifier checks:
- SSA correctness
- type correctness
- side-effect ordering
- legal terminators
- block validity
- guard/deopt validity
- instruction boundary mapping
- memory dependency validity
- backend-lowerable forms
The decoder MUST:
- decode AArch64 instructions
- classify instruction groups
- provide disassembly
- expose instruction metadata
- support fuzzing
- support exact byte-to-instruction mapping
The lifter MUST:
- convert decoded instructions to NxIR
- preserve instruction boundaries
- emit side effects
- emit lazy flags
- emit memory operations
- emit atomics
- emit barriers
- emit FP/SIMD operations
- emit system instruction behavior
- emit traps/helpers for unsupported cases
Nx86 MUST eventually support:
- integer arithmetic
- logical operations
- branches
- calls
- returns
- indirect branches
- loads/stores
- paired loads/stores
- atomics
- barriers
- FP scalar
- NEON/SIMD
- system instructions
- exception-related behavior
- service call boundaries
Nx86 MUST aim for exact guest-visible behavior.
Floating-point behavior MUST aim for bit-perfect Switch behavior.
Host math shortcuts MUST be disabled in accuracy mode unless proven exact.
Nx86 uses a custom backend.
NxIR
↓
legalization
↓
instruction selection
↓
register allocation
↓
machine optimization
↓
hot/cold splitting
↓
block layout
↓
internal assembler
↓
machine code encoding
↓
relocation
↓
object/JIT emission
The first register allocator SHOULD be simple.
The long-term allocator SHOULD become advanced and profile-guided.
Backend priority:
fastest generated code
size be damned
Nx86 MUST include an integrated x86_64 assembler.
The assembler MUST support:
- x86_64 encoding
- x86_64-v4 instructions
- vector instructions
- mask registers
- labels
- relocations
- patch sites
- guard patching
- block chain patching
- native dumps
- debug/unwind metadata hooks
The backend MUST support hot/cold splitting.
Cold code SHOULD NOT automatically receive lower optimization.
Debug builds SHOULD emit human-readable assembly dumps.
Native dumps SHOULD be deleted after successful runs unless preservation is requested.
Nx86 emits many small native objects.
Native objects SHOULD contain:
- object header
- compiler version
- backend version
- CPU target
- title ID
- title version
- executable hash dependencies
- code bytes
- relocation table
- block table
- function table
- guest-to-native map
- native-to-guest map
- guard table
- deopt table
- page dependency table
- hot/cold layout
- debug/unwind info
- validation hash
- profile counters
Objects MAY be:
- memory-mapped from disk
- loaded into RAM
- handled differently depending on mode
Native objects do not need to be standalone.
They may depend on:
- other native objects
- runtime libraries
- metadata tables
- relocation tables
- service thunks
- shader/pipeline state
- profile data
Nx86 includes a VMM from day one.
Nx86 MUST reserve a 64 GB virtual address arena at startup.
The arena supports:
- guest memory
- fastmem
- mirrored memory regions
- codegen assumptions
- stable address layout
The VMM MUST support:
- guest virtual memory
- page mapping
- page unmapping
- page permissions
- host page protections
- software permission tables
- fastmem
- slowmem
- memory mirroring
- guard pages
- MMIO explicit checks
- executable page hashes
- executable page generations
- self-modifying code detection
- invalidation callbacks
- debug poisoning
- thread-safe updates
- crash reports
Memory mirroring SHOULD be enabled in release mode.
Memory mirroring SHOULD be disabled in debug mode.
VMM faults MUST pause execution and show a crash report.
Crash reports SHOULD include:
- faulting address
- access type
- guest PC
- guest thread
- source block
- call stack
- native object
- page permissions
- page generation
- recent executable writes
- scheduler context
Nx86 MUST support self-modifying code.
When guest code writes to executable memory, Nx86 MUST:
- log the write
- include call stack
- include source block
- mark page dirty
- increment page generation
- invalidate dependent objects
- remove unsafe block chains
- route future execution through dispatcher/JIT
- feed event into profile data
Self-modifying code MUST NOT trigger visible gameplay warnings by default.
It SHOULD be visible in developer tools and crash reports.
Nx86 supports guest threading from day one.
Nx86 SHOULD support:
- 1:1 guest-to-host threads
- optional fiber/task mode
- deterministic developer scheduler
- crash-window replay logs
The GUI SHOULD show:
- active guest threads
- per-thread CPU usage
- thread state
- current block/function if available
- scheduler status in developer mode
Replay logs SHOULD capture crash windows.
Replay logs MUST have a size cap.
Replay logs SHOULD be analyzed to improve future rebuilds.
Auto-parallelization is experimental.
It MUST be per-title opt-in.
It MAY change frame timing.
It MUST NOT be enabled globally by default.
Nx86 MUST implement atomics correctly from day one.
Atomic support includes:
- exclusive loads
- exclusive stores
- acquire loads
- release stores
- compare-and-swap behavior
- atomic read-modify-write
- failure behavior
- thread-visible ordering
- page fault interactions
- deopt interactions
Barriers MUST be optimized semantically.
Nx86 MUST NOT blindly delete barriers.
Barrier lowering must consider:
- normal memory
- MMIO
- service boundaries
- executable memory
- self-modifying code
- thread synchronization
- debug validation
- replay determinism
GSO means:
Guarded Speculative Optimization
GSO allows Nx86 to:
- predict indirect branch targets
- optimize vtable dispatch
- optimize callback paths
- specialize hot callsites
- inline likely targets
- reduce dispatcher overhead
- patch fast paths
- deopt safely when wrong
- use runtime feedback to improve future AOT
GSO profiles SHOULD be auto-generated.
Advanced developers MAY create manual overrides.
Official GSO code MAY be compiled into Nx86.
Official GSO code MUST:
- be original code
- avoid copyrighted code
- be reviewed
- be documented
- be linked to title/version/hash when title-specific
- improve performance, fix bugs, or allow title execution
- be safe enough for official inclusion
Nx86 supports title behavior patches.
Behavior patches may:
- improve compatibility
- fix title-specific bugs
- allow titles to run
- implement runtime-level FPS unlock
- patch service behavior
- patch scheduling behavior
- patch GPU behavior
Required compatibility patches MAY be enabled by default and undisableable.
Built-in required patches do not lower compatibility status.
Profile sharing is opt-in.
Profile downloads require user approval.
Profile uploads ask every time.
Verified profiles SHOULD be signed.
Profile distribution MAY be centralized, decentralized, or both.
Profiles may contain:
- title ID
- title version
- executable hashes
- branch target addresses
- hot block data
- guard data
- shader hashes
- pipeline hashes
- performance ratings by hardware class
- sanitized crash signatures
- GSO suggestions
Profiles MUST NOT contain:
- game assets
- copied executable bytes
- binary blobs
- save data
- screenshots
- personal paths
- usernames
- personal data
- memory dumps containing copyrighted data
Nx86 MUST include a profile sanitizer.
The sanitizer MUST reject or strip:
- binary blobs
- copied game bytes
- assets
- saves
- screenshots
- personal paths
- personal identifiers
- suspicious payloads
- raw memory dumps
Nx86 compatibility status is based on:
- user reports
- official testing
- automated profile data
- Native Coverage
- crash reports
- performance reports
Compatibility and Native Coverage may be combined.
Perfect compatibility MUST require 100% Native Coverage.
Built-in required patches do not lower compatibility status.
Nx86 SHOULD use ash for the Vulkan backend.
ash is preferred because Nx86 requires low-level Vulkan control for shader translation, pipeline cache management, descriptor layout control, synchronization, command buffer recording, memory management, debug tooling, and future vendor-specific optimization.
Nx86 MUST wrap ash behind an internal nx86-vulkan abstraction. Raw Vulkan handles and unsafe Vulkan calls SHOULD NOT leak into higher-level emulator crates.
Higher-level graphics crates such as wgpu or vulkano are not preferred for the core renderer because Nx86 needs explicit Vulkan behavior rather than a portability abstraction.
Initial backend:
Vulkan
Future backend:
D3D12
Shader AOT happens during initial compile.
Shared profiles MAY assist shader AOT.
Shader data SHOULD live in the title folder, separate from CPU cache.
Nx86 does not show separate GPU coverage by default.
GPU readiness is included in Native Coverage.
Developer tools MAY show shader and pipeline breakdowns.
Nx86 supports:
- runtime-level FPS unlock
- per-title FPS behavior
- global resolution scaling
- per-title resolution overrides
Pure AOT may require bundled runtime libraries.
Libraries may provide:
- gamepad support
- input translation
- windowing
- audio
- graphics
- filesystem shims
- service implementations
- title-specific compatibility services
These libraries replace the need for the full Nx86 emulator app.
Nx86 includes an Inspector.
The Inspector displays:
- title structure
- title ID
- versions
- updates
- DLC
- executable modules
- sections
- disassembly
- recovered functions
- recovered CFG
- NxIR
- native mapping
- guards
- deopt points
- Native Coverage
- profile events
- executable write logs
- shader/pipeline data
Nx86 SHOULD include:
- First Launch Wizard
- Library
- Title Details
- Compile Screen
- Runtime Screen
- Settings
- Cache Manager
- Profile Manager
- Inspector
- Disassembler
- Developer Tools
- Crash Analyzer
- Compatibility Reports
The compile screen is visual-first.
It shows compact logs with a “see more” button.
It SHOULD display:
- current phase
- progress
- Native Coverage estimate
- code objects generated
- functions discovered
- functions compiled
- guards inserted
- deopt points
- shader AOT status
- cache size
- warnings
- compact logs
The developer overlay SHOULD show:
- AOT activity
- emergency JIT events
- Native Coverage
- slowmem events
- runtime helpers
- guest threads
- per-thread CPU usage
- shader/pipeline events
- guard failures
- deopt events
Nx86 supports opt-in sanitized telemetry/profile sharing.
Nx86 MUST:
- never upload automatically without consent
- ask every time before uploading
- sanitize before export
- show what will be shared
- avoid personal data
- avoid copyrighted blobs
- avoid saves
- allow disabling sharing entirely
Nx86 requires a serious test suite.
Tests should run on:
- synthetic ARM64 environment
- Nx86 interpreter
- Nx86 JIT
- Nx86 AOT
- optimized Nx86 AOT
- homebrew on real hardware where possible
Test categories include:
- integer arithmetic
- flags
- branches
- calls
- indirect branches
- loads/stores
- unaligned memory
- atomics
- barriers
- FP
- SIMD
- system instructions
- service calls
- VMM faults
- self-modifying code
- threading
- scheduler replay
- shader AOT
- pipeline cache
- Pure AOT folder behavior
Nx86 SHOULD compare:
interpreter result
JIT result
AOT result
optimized AOT result
real hardware result where available
Compared state includes:
- general registers
- flags
- vector registers
- FP status
- memory
- thread-visible behavior
- service behavior
- exception behavior
Nx86 development should include ongoing research into:
- Arm memory model
- AArch64 barriers
- AArch64 SIMD/FP behavior
- emulator JIT designs
- binary translation
- deoptimization systems
- JavaScript VM optimization strategies
- profile-guided optimization
- Vulkan pipeline caching
- shader translation
- x86_64-v4 codegen
- AVX-512 register allocation
- fastmem/slowmem designs
- scheduler replay systems
- self-modifying code invalidation
Research findings should be folded back into the spec.
Nx86 uses a Rust monorepo.
Suggested layout:
nx86/
├── README.md
├── SPEC.md
├── Cargo.toml
├── crates/
│ ├── nx86-app/
│ ├── nx86-gui/
│ ├── nx86-core/
│ ├── nx86-title-db/
│ ├── nx86-import/
│ ├── nx86-inspector/
│ ├── nx86-arm64-decode/
│ ├── nx86-arm64-lift/
│ ├── nx86-ir/
│ ├── nx86-ir-opt/
│ ├── nx86-backend/
│ ├── nx86-x64-asm/
│ ├── nx86-x64-v4/
│ ├── nx86-regalloc/
│ ├── nx86-object/
│ ├── nx86-jit/
│ ├── nx86-runtime/
│ ├── nx86-vmm/
│ ├── nx86-scheduler/
│ ├── nx86-hle/
│ ├── nx86-input/
│ ├── nx86-audio/
│ ├── nx86-gpu/
│ ├── nx86-vulkan/
│ ├── nx86-shader/
│ ├── nx86-profile/
│ ├── nx86-gso/
│ ├── nx86-title-profiles/
│ ├── nx86-cache/
│ ├── nx86-debug/
│ ├── nx86-testsuite/
│ └── nx86-fuzz/
├── docs/
│ ├── phases/
│ ├── research/
│ ├── adr/
│ └── developer/
└── tools/
Nx86 should include issue templates for:
- compiler bug
- backend bug
- runtime bug
- game compatibility bug
- shader/graphics bug
- profile bug
- crash report
- performance issue
- documentation issue
- feature request
This roadmap is intentionally granular.
Each phase should produce a working, testable step.
Goals:
- define project goals
- define terminology
- research Arm semantics
- research x86_64-v4 codegen
- research Vulkan pipeline behavior
- research emulator memory models
- write SPEC.md
- write README.md skeleton
Exit criteria:
- SPEC.md exists
- README.md exists
- crate plan exists
- first prototype target is defined
Goals:
- create Rust workspace
- add crate skeletons
- add formatting/lint config
- add CI placeholder
- add issue templates
- add docs folder
- add basic logging crate
Exit criteria:
- workspace builds
- empty app launches
- CI can compile empty project
Goals:
- create egui app
- create main window
- create theme system
- create navigation shell
- create empty Library screen
- create empty Settings screen
- create empty Compile screen
Exit criteria:
- Nx86 opens a GUI window
- navigation works
- settings persist
Goals:
- library folder picker
- cache folder picker
- profile folder picker
- CPU target selection
- compile thread cap
- all-core warning
- profile sharing opt-in
- default graphics backend selection
Exit criteria:
- wizard runs on first launch
- config is saved
- app boots into Library after wizard
Goals:
- SQLite database setup
- sidecar metadata system
- title folder creation
- cache folder creation
- profile folder creation
- migration system
Exit criteria:
- Nx86 can create and list title entries
- title folders are deterministic
- database survives restart
Goals:
- background job model
- compiler worker process skeleton
- runtime process skeleton
- IPC message format
- progress events
- cancellation events
Exit criteria:
- GUI can launch worker process
- worker sends progress events
- GUI displays progress
Goals:
- define simple synthetic test file format
- support raw ARM64 bytes
- support expected register output
- support expected memory output
- support tiny metadata header
Exit criteria:
- synthetic test files can be loaded
- expected results can be displayed
Goals:
- define general registers
- define SP/PC
- define NZCV
- define FP/SIMD registers
- define FPCR/FPSR
- define thread-local state
- define serialization for debug
Exit criteria:
- CpuState can be created
- CpuState can be dumped
- test harness can compare CpuState
Goals:
- decode small instruction subset
- print disassembly
- classify instruction types
- expose raw bytes
- support decoder errors
Exit criteria:
- MOV/ADD/SUB/B/SVC decode
- GUI can show decoded instructions
Goals:
- execute tiny integer subset
- update registers
- update PC
- handle basic branch
- handle halt/SVC test exit
Exit criteria:
- synthetic ARM64 add program executes
- expected register values match
Goals:
- reserve 64 GB arena
- create page table structure
- map/unmap pages
- implement read/write helpers
- implement debug memory dump
Exit criteria:
- synthetic tests can read/write guest memory
- VMM faults produce errors
Goals:
- define synthetic framebuffer region
- allow ARM64 test to write pixels
- display framebuffer in GUI
- support simple color output
Exit criteria:
- ARM64 synthetic program draws something simple
Goals:
- define IR module/function/block
- define values/types
- define integer ops
- define branch ops
- define memory ops
- preserve instruction boundaries
Exit criteria:
- decoded ARM64 can be lifted into simple NxIR
Goals:
- SSA checks
- type checks
- block terminator checks
- side-effect checks
- instruction boundary checks
Exit criteria:
- verifier catches invalid IR
- verifier runs after lifting
Goals:
- lift MOV
- lift ADD/SUB
- lift logical ops
- lift branches
- lift loads/stores
- lift SVC test exit
Exit criteria:
- synthetic integer programs lift to NxIR
- interpreter and NxIR semantics agree
Goals:
- define lazy NZCV expressions
- lift ADDS/SUBS/CMP
- eliminate unused flags
- materialize flags when needed
Exit criteria:
- condition branches work through lazy flags
- tests cover overwritten flags
Goals:
- internal assembler API
- labels
- basic mov/add/sub/cmp/jmp
- function prologue/epilogue
- code buffer
- disassembly dump placeholder
Exit criteria:
- assembler emits callable x86_64 code
Goals:
- allocate executable memory
- write code
- set permissions
- free safely
- support code pointers
Exit criteria:
- generated native function can be called from Rust
Goals:
- lower tiny NxIR block to x86_64
- call native block
- compare result with interpreter
- show success in GUI
Exit criteria:
- ARM64 add program runs as native x86_64 code
Goals:
- implement simple allocator
- handle spills
- map guest values
- handle block-local temporaries
Exit criteria:
- multi-instruction native blocks run correctly
Goals:
- define
.nxoobject header - store code bytes
- store guest mapping
- store validation hash
- load object from disk
Exit criteria:
- compiled block persists across restart
Goals:
- cache manifest
- shallow check
- full check placeholder
- cache deletion UI
- cache size accounting
Exit criteria:
- GUI shows cache status
- compiled object loads from cache
Goals:
- guest PC lookup
- native block call
- block exit handling
- branch target routing
- missing block handling
Exit criteria:
- multiple native blocks execute through dispatcher
Goals:
- compile missing basic block
- insert into code cache
- log JIT event
- continue execution
Exit criteria:
- missing block can be JITed and executed
Goals:
- profile file format
- log JIT blocks
- log branch targets
- log helper calls
- log slowmem events
Exit criteria:
- runtime produces profile data
Goals:
- read runtime profile
- identify JIT block candidates
- promote block to AOT object
- update Native Coverage
Exit criteria:
- second run uses promoted native object
Goals:
- recursive traversal
- direct branch following
- function candidate discovery
- basic block table
- CFG display
Exit criteria:
- synthetic programs produce CFG
Goals:
- disassembly view
- function list
- block list
- NxIR view
- native mapping view
Exit criteria:
- user can inspect synthetic program
Goals:
- define guard IR op
- define deopt point
- store deopt metadata
- handle guard failure
- crash on deopt failure
Exit criteria:
- failed guard routes to deopt handler
Goals:
- direct chaining
- table chaining
- invalidation hooks
- disable in debug
Exit criteria:
- hot loop executes with block chaining
Goals:
- direct memory lowering
- memory base register
- fast load/store
- fallback to slowmem
Exit criteria:
- synthetic memory tests run through fastmem
Goals:
- runtime load/store helpers
- permission checks
- fault reporting
- slowmem counters
- Native Coverage penalty
Exit criteria:
- invalid access pauses and shows crash report
Goals:
- mirrored region design
- release-mode enablement
- debug-mode disablement
- correctness tests
Exit criteria:
- release can use mirrored fast paths
Goals:
- executable page write detection
- page generation increment
- object invalidation
- chain invalidation
- profile event logging
Exit criteria:
- synthetic self-modifying test invalidates old code
Goals:
- exclusive monitor model
- LDXR/STXR subset
- acquire/release subset
- atomic tests
- thread interaction tests
Exit criteria:
- basic atomic synthetic tests pass
Goals:
- represent DMB/DSB/ISB
- semantic lowering
- debug validation
- threading tests
Exit criteria:
- barriers behave correctly in synthetic tests
Deferred barrier work after Phase 35:
-
Native backend lowering: Map preserved NxIR BarrierOp values to correct host fence/compiler ordering behavior.
-
Threading semantics: Define how DMB/DSB/ISB interact with Nx86 guest thread scheduling, atomics, shared memory, and synchronization.
-
MMIO/services ordering: Define barrier effects around guest-visible device/service/MMIO operations.
-
Executable memory / SMC: Define how ISB/DSB/DMB interact with code cache invalidation, self-modifying code, and generated native blocks.
-
Optimizer rules: Define which memory/code operations may or may not move across each barrier kind/domain.
-
Debug/replay: Preserve barrier events in traces/replay logs so deterministic replay and validation can reason about ordering.
Phase 35 is complete only when it preserves enough NxIR information for all of the above future work.
Goals:
- guest thread model
- host thread mapping
- thread state
- thread GUI view
- per-thread CPU use
Exit criteria:
- synthetic multi-thread program runs
Goals:
- crash-window replay logs
- size cap
- replay metadata
- developer UI
Exit criteria:
- crash window can be replay-analyzed
Goals:
- fiber/task scheduler skeleton
- optional mode
- synthetic test support
- comparison with host threads
Exit criteria:
- synthetic guest threads can run under fiber mode
Goals:
- FP registers
- FP add/sub/mul/div
- FP comparisons
- FPCR/FPSR basics
- exactness tests
Exit criteria:
- scalar FP synthetic tests pass
Goals:
- vector register model
- basic NEON integer ops
- basic NEON FP ops
- x86_64-v4 lowering
- debug validation
Exit criteria:
- basic NEON tests pass
Goals:
- vector register mapping
- mask register use
- shuffle lowering
- compare lowering
- spill strategy
Exit criteria:
- NEON-heavy tests run efficiently
Goals:
- profile hot blocks
- split cold paths
- layout hot loops
- update native mapping
Exit criteria:
- hot code layout changes based on profile
Goals:
- functional coverage metric
- static coverage metric
- executed coverage metric
- fastmem coverage
- slowmem penalty
- GUI display
Exit criteria:
- compile/runtime screen shows Native Coverage
Goals:
- load simple homebrew
- basic module metadata
- entrypoint handling
- minimal services
Exit criteria:
- simple homebrew boots
Goals:
- service call dispatch
- filesystem skeleton
- thread service skeleton
- memory service skeleton
- input service skeleton
Exit criteria:
- simple homebrew can call basic services
Goals:
- gamepad abstraction
- keyboard mapping
- controller config UI
- runtime input service
Exit criteria:
- homebrew receives input
Goals:
- guest service IPC v0
- audio output abstraction
- buffer model
- audio service skeleton
- timing tests
Exit criteria:
- simple audio test works through a guest IPC audio command buffer
Goals:
- Vulkan device setup
- swapchain
- basic frame rendering
- GUI/runtime separation
- error handling
Exit criteria:
- runtime displays a rendered frame
Goals:
- shader metadata model
- shader hash model
- placeholder translation path
- shader cache folder
Exit criteria:
- synthetic shader path compiles/caches placeholder
Goals:
- compile shaders during initial compile
- store shader cache
- use shared profile hints
- report shader readiness
Exit criteria:
- shader AOT contributes to Native Coverage
Goals:
- pipeline profile format
- pipeline cache save/load
- initial compile integration
- runtime miss logging
Exit criteria:
- pipeline cache persists across runs
Goals:
- log shader usage
- log pipeline usage
- promote runtime-discovered pipeline data
- feed passive rebuild
Exit criteria:
- graphics profile improves next run
Goals:
- patch metadata format
- built-in required patches
- undisableable compatibility patches
- patch reporting
Exit criteria:
- synthetic title patch modifies behavior intentionally
Goals:
- guard profile format
- speculative target metadata
- auto-generated GSO profile
- manual local override
Exit criteria:
- indirect target can become guarded native fast path
Goals:
- title profile crate
- profile registry
- title hash matching
- compatibility notes
- GSO integration
Exit criteria:
- local title profile applies to test title
Goals:
- strip personal paths
- reject blobs
- reject saves
- reject screenshots
- validate shared profile format
Exit criteria:
- unsafe profile export is blocked
Goals:
- signed profile format
- download approval UI
- upload approval UI
- decentralized source support
- hardware class ratings
Exit criteria:
- sanitized profile can be imported/exported
Goals:
- compatibility labels
- Native Coverage integration
- reports
- title status UI
Exit criteria:
- title compatibility status displays in library
Goals:
- legal user-provided title import
- title ID detection
- update/DLC metadata
- compile refusal for unsupported cases
- Inspector support
Exit criteria:
- commercial title appears in library and Inspector
Goals:
- plaintext container structure parsing (PFS0/HFS0) for authoritative title ID
- wired metadata resolver: sidecar → local DB → online → filename → fallback
- user-imported local title database (offline) and opt-in online provider
- poster/icon/banner media download into the per-title
media/folder - library icon thumbnails and a per-title metadata/media detail pane
- separate, opt-in, user-provided-key extraction of real name + icon (no keys shipped)
Exit criteria:
- an imported title shows a recovered name and icon in the library
- keyless import never requires network or keys; online/keys are explicit opt-in
Goals:
- execute early title startup
- service logging
- missing instruction logging
- JIT emergency path
- crash reports
Exit criteria:
- simple commercial title reaches early boot path
Goals:
- improve services
- improve GPU
- improve scheduler
- improve memory behavior
- improve profile rebuild
- improve Native Coverage
Exit criteria:
- complex commercial title reaches visible graphics
Goals:
- handle large open-world title complexity
- handle heavy shader/pipeline use
- handle complex threading
- handle large memory behavior
- handle deep profile-guided recompilation
Exit criteria:
- architecture proves it can target TOTK-class workloads
Goals:
- aggressive GSO
- helper inlining
- deeper superblocks
- cross-function optimization
- advanced register allocation
- huge cache mode
Exit criteria:
- “I Paid For My Computer” mode produces faster native output
Goals:
- dependency analysis
- per-title opt-in
- frame timing warnings
- synthetic workload split
- rollback if unsafe
Exit criteria:
- synthetic single-threaded workload can be split safely
Goals:
- generate folder
- include native objects
- include minimal runtime libraries
- include content copy/reference
- include legal.txt
- launch without full GUI
Exit criteria:
- synthetic title launches from Pure AOT folder
Goals:
- homebrew Pure AOT folder
- bundled runtime services
- shader/pipeline readiness
- no JIT
- no interpreter
Exit criteria:
- homebrew runs without full Nx86 app
Goals:
- title-specific native folder
- copied local content
- minimal runtime libraries
- compatibility patches
- no full Nx86 GUI
Exit criteria:
- selected title launches from generated native folder
Goals:
- backend target abstraction
- v3 lowering
- reduced vector register strategy
- handheld performance work
Exit criteria:
- synthetic tests pass on x86_64-v3 backend
Goals:
- baseline lowering
- compatibility mode
- feature detection
- slower fallback paths
Exit criteria:
- synthetic tests pass on generic x86_64
Goals:
- Windows process model
- Windows VMM support
- D3D12 prep
- Windows input/audio
- cache path handling
Exit criteria:
- Nx86 GUI and synthetic tests run on Windows
Goals:
- D3D12 device setup
- shader path adaptation
- pipeline cache equivalent
- backend selection
Exit criteria:
- synthetic graphics test runs on D3D12
Goals:
- host backend abstraction
- ARM64 native backend research
- Apple Silicon/Linux ARM notes
- future feasibility
Exit criteria:
- ARM64 host backend plan exists
NDX, short for N Dynamic X, is Nx86's built-in native mod system. NDX is not a traditional emulator runtime modloader. Its purpose is to convert, validate, resolve, and bake mods ahead of time into deterministic game builds so that minimal work happens at runtime.
NDX SHOULD be treated as a core long-term feature of Nx86. Normal game compatibility comes first.
NDX mods are build-time inputs, not loose runtime-loaded mod folders.
Normal launch flow MUST NOT scan raw mod folders, parse arbitrary external layouts, resolve conflicts, or decide cache invalidation at runtime. These operations belong in the NDX import/bake pipeline.
The intended flow is:
User-provided game content
+ update/DLC
+ built-in GSO/GSC compatibility behavior
+ selected .ndx source mods
↓
NDX validation and bake step
↓
effective .nci content image
+ internal .ndxb baked profile/cache artifact
+ generated runtime module
+ native code cache
↓
launch through Nx86 or standalone minimal runtime
Runtime SHOULD mostly load prepared artifacts and execute already-planned hooks/patches.
.ndx = NDX source mod package users download/import/install
.ndxb = internal baked NDX build/profile cache artifact
.nci = Nx86 Content Image containing the effective game content
GSO = Game-Specific Optimizations
GSC = Game-Specific Code / compatibility modules
.ndx is the source package. Users MAY download or install .ndx mods.
.ndxb is internal baked output/cache. It is not the primary user-facing package format.
.nci contains the entire effective game content image for the selected game build. Game assets SHOULD be stored in the .nci. Compiled code remains in Nx86's existing compiled-code/cache system.
Nx86 SHOULD bake only when something relevant changed.
Relevant changes include:
- selected mods changed
- mod metadata changed
- game content changed
- update/DLC changed
- GSO/GSC changed
- compiler backend changed
- cache format changed
- Nx86 version requires cache invalidation
- cheat state requires rebake or cache update
- content image is stale
If nothing relevant changed, Nx86 SHOULD launch the existing baked build.
Stale or unsafe baked profiles MUST always be hard-blocked. Nx86 MUST NOT allow stale native cache or stale baked mod output to launch.
Profiles are supported, but they are not the preferred normal-user concept.
The normal UX SHOULD show one active Game Build.
Advanced users and modders MAY access profile-like behavior under advanced settings, but the ordinary flow SHOULD be:
Game → Current Build → Mods → Bake if needed → Launch
Profiles MAY still exist internally or for advanced use, but Nx86 SHOULD NOT force users to manage profiles for ordinary modding.
NDX is its own native mod system. Nx86 MUST NOT directly load Eden/Yuzu/Ryujinx/Atmosphère folders at runtime.
External emulator mod layouts are import/conversion sources only.
Nx86 SHOULD support importing from:
Eden-style mod folders
Yuzu-style mod folders
Ryujinx-style mod folders
Atmosphère-style contents folders
.zip / .7z / .rar / .tar / .tar.gz archives
existing .ndx packages
When importing a non-.ndx mod, Nx86 MUST convert it into an .ndx source package.
The original downloaded archive/folder MUST remain untouched wherever the user downloaded it. Nx86 MAY process it in memory and/or temporary storage, but raw external-format leftovers MUST NOT remain inside the per-title Nx86 mod folder after conversion. Temporary processed files SHOULD be flushed from memory/temp storage after conversion.
Converted mods MUST become normalized .ndx packages with required metadata.
If an external mod cannot be cleanly converted, Nx86 SHOULD open a conversion wizard where the user can fill missing information or fix ambiguous mappings.
.ndx is the native Nx86 mod package format.
Every installed .ndx mod MUST include or produce an nxmod.toml.
A .ndx package MAY contain:
nxmod.toml
romfs/
romfs_ext/
exefs/
patches/
cheats/
assets/
scripts/
README.md
LICENSE
Lua/Luau scripting is optional glue only. Lua/Luau is not the mod format.
Ordinary mods SHOULD work without scripting. File replacement, patch declaration, cheat declaration, metadata, cache planning, and install/import behavior SHOULD be declarative through .ndx structure and TOML metadata.
.ndx is the package users download, import, install, and keep for rebuilds/edits.
.ndxb is internal baked cache output generated from selected .ndx mods, game content, GSO/GSC state, and compiler/cache state.
.ndxb MUST NOT be treated as the user's installed mod package.
.ndx source packages SHOULD remain installed after baking unless the user removes the mod.
When a user removes a mod, Nx86 SHOULD remove:
- installed
.ndx - related
.ndxbbaked artifacts - generated runtime module data affected by the mod
- affected
.ncicontent image output - validation records
- active build references
- temporary generated state
- cache entries specific to that mod, when safe
Nx86 SHOULD then rebuild/recompile only affected parts when possible.
If removing a mod only affects content, Nx86 SHOULD avoid recompiling unrelated code.
If removing a mod affects executable/code state, Nx86 SHOULD prefer partial recompilation. If safe partial recompilation cannot be proven, Nx86 MUST fall back to full rebuild.
NDX SHOULD include a development mode.
Development mode SHOULD provide:
- fast rebake
- verbose logs
- conversion diagnostics
nxmod.tomlvalidation- conflict diagnostics
- cache impact explanation
- content image inspection
- patch planning output
- hook table/debug output when relevant
Development mode MAY be more dynamic than normal user mode, but normal launch SHOULD still prefer baked artifacts.
The NDX bake pipeline SHOULD perform:
- read installed
.ndxsource packages - validate
nxmod.toml - apply built-in GSO/GSC compatibility behavior first
- apply selected user mods after GSO/GSC
- resolve conflicts
- validate Title ID and Build ID
- classify content, patches, cheats, scripts, and assets
- compute file hashes
- compute cache impact
- generate the effective
.ncicontent image - generate internal
.ndxbbaked output/cache metadata - generate one profile/build runtime module
- update native code cache, using partial recompilation where safe
- hard-block launch if output is stale or unsafe
Built-in GSO/GSC MUST apply before user mods.
User mods MUST NOT override GSO/GSC behavior.
GSO/GSC exists to ensure compatibility, performance, resolution upgrades, FPS behavior, and game-specific fixes. Because these systems protect game correctness and user experience, they always win over user mods.
NDX SHOULD expose GSO/GSC interactions in advanced diagnostics where useful, but users MUST NOT be able to disable or override required compatibility behavior through mods.
Every baked Game Build SHOULD produce one generated runtime module.
Examples:
game_build.ndx.so
game_build.ndx.dll
game_build.ndx.dylib
This generated module represents the entire baked build/profile. It is not one dynamic library per individual mod.
The generated runtime module MAY contain:
- hook table
- patch table
- cheat table
- asset/content redirect table
- runtime config
- baked metadata
- compiled bake-time script results if applicable
- compatibility metadata
- cache identity metadata
The runtime module MUST be generated by Nx86/NDX, not downloaded directly from random mods.
Nx86 MUST NOT silently load arbitrary .dll, .so, or .dylib files from mod folders.
Nx86 SHOULD support a hybrid launch model:
- When launched from the Nx86 menu, Nx86 acts as the launcher and loads the generated runtime module for the selected Game Build.
- For standalone exported game bundles, a minimal Nx86 runtime SHOULD load the generated module and prepared content/code artifacts.
Standalone game bundles are a later export goal, not required before baked Game Builds work.
Statically linked output SHOULD remain an option.
Nx86 MAY support:
- dynamic generated runtime modules
- mostly/static linked game runtime bundles
- platform-specific app bundle/export formats
The spec MUST NOT force all builds to use dynamic libraries forever.
.nci means Nx86 Content Image.
.nci SHOULD contain the entire effective game content image for the selected Game Build.
This includes base game content, update content, DLC content where applicable, GSO/GSC content transformations if any, and selected user mod content.
All game assets SHOULD be stored in the .nci.
Code SHOULD remain in Nx86's compiled-code/native-cache system rather than being treated as ordinary content assets.
Linux MAY use a SquashFS-like backend for .nci, but .nci SHOULD be an abstraction, not hardcoded to SquashFS forever. Windows and macOS MAY use different internal content image backends.
Nx86 SHOULD prefer partial recompilation whenever safe.
If a change affects only assets/content, Nx86 SHOULD avoid native code recompilation.
If a change affects code, patches, executable metadata, hook tables, or compiler assumptions, Nx86 SHOULD determine affected regions and recompile only those regions when possible.
If safe partial recompilation is uncertain, Nx86 MUST fall back to full rebuild.
Nx86 MUST NOT use risky stale cache output.
NDX SHOULD support a full runtime cheat manager.
Cheats are part of NDX, but unlike most mod content, they MAY need runtime toggling.
Runtime cheat toggling SHOULD still be planned and validated ahead of time where possible. The cheat manager MUST NOT become a loophole for arbitrary unvalidated runtime patching.
Cheats SHOULD validate:
- Title ID
- Build ID when applicable
- game version/update version when applicable
- memory/code target compatibility
- conflict with other cheats
- conflict with GSO/GSC or required compatibility behavior
Cheats MAY be toggled at runtime through the Nx86 UI if validated.
Luau MAY be used as optional scripting glue, not as the core modding system.
Luau scripts SHOULD run only during bake/compile time.
Normal runtime MUST NOT execute Luau scripts.
Use cases for Luau MAY include:
- generating patch tables during bake
- generating randomized data during bake
- build-time mod configuration logic
- generating derived content
- validating or transforming mod assets
- producing bake-time metadata
Luau SHOULD NOT be required for ordinary .ndx mods.
Nx86 MAY support user-added mod repositories and an official curated/mirrored index.
Repository support SHOULD provide .ndx packages or metadata needed to install .ndx packages.
External downloaded mods SHOULD still pass through the NDX import/conversion/validation pipeline.
Nx86 MUST NOT distribute, fetch, generate, or assist with obtaining:
- Nintendo keys
- title keys
- firmware
- copyrighted game dumps
- copyrighted Nintendo system files
- leaked SDK content
- suspicious payloads
NDX MUST reject or block:
- path traversal in archives
- suspicious executables
- unexpected native libraries
- arbitrary scripts intended to run at runtime
- keys/title keys
- firmware files
- copyrighted system blobs
- malformed archives
- mod payloads that try to overwrite unrelated user files
- raw external-format leftovers inside per-title mod folders after conversion
NDX MUST NOT mutate the user's original downloaded archive/folder.
NDX MUST NOT mutate original imported game/update/DLC files.
The per-game UI SHOULD present a Current Build view.
It SHOULD show:
- installed
.ndxmods - active/inactive state
- cache impact
- build freshness
- whether bake is needed
- whether
.nciis current - whether native cache is current
- cheat manager
- GSO/GSC status
- conversion status
- validation errors
- rebuild/rebake button
- remove mod button
- development mode tools in advanced mode
Primary buttons/actions:
Import Mod
Bake/Rebuild Build
Launch
Validate
Remove Mod
Open Build Folder
Reset to Clean Build
Open Conversion Wizard
Open Development Diagnostics
If an external mod cannot be cleanly converted into .ndx, Nx86 SHOULD open a conversion wizard.
The wizard SHOULD help the user provide:
- target game / Title ID
- game version
- Build ID if needed
- mod name
- mod type
- content mapping
- cache impact
- patch type
- cheat mapping
- conflict resolution
- missing metadata
- author/license/source if known
The wizard SHOULD generate a valid nxmod.toml.
Suggested Rust module layout:
nx86-ndx/
import/
archive.rs
external_layout.rs
conversion_wizard.rs
package/
ndx.rs
manifest.rs
metadata.rs
bake/
planner.rs
resolver.rs
content_image.rs
baked_profile.rs
runtime_module.rs
cache_plan.rs
mods/
romfs.rs
romfs_ext.rs
patches.rs
cheats.rs
scripts.rs
safety/
validator.rs
trust.rs
scanner.rs
ui/
build_model.rs
diagnostics.rs
cheat_manager.rs
Responsibilities:
archive.rs: safe archive extraction/importexternal_layout.rs: detect Eden/Yuzu/Ryujinx/Atmosphère-style layoutsconversion_wizard.rs: user-assisted conversion to.ndxndx.rs: read/write/install.ndxpackagesmanifest.rs: parse and validatenxmod.tomlplanner.rs: build high-level bake planresolver.rs: resolve selected mods and conflictscontent_image.rs: emit.ncibaked_profile.rs: emit.ndxbruntime_module.rs: generate one runtime module for the selected buildcache_plan.rs: decide no rebuild, partial rebuild, or full rebuildcheats.rs: full runtime cheat managerscripts.rs: bake-time Luau support onlyvalidator.rs: safety and correctness validationbuild_model.rs: UI model for Current Builddiagnostics.rs: dev-mode logs and explanations
- NDX is Nx86's native mod system.
- NDX is not traditional runtime mod loading.
.ndxsource packages are build-time inputs..ndxbis internal baked cache output..ncicontains the full effective game content image.- Runtime SHOULD do minimal work and mostly load prepared artifacts.
- External emulator mod folders are import/conversion sources only.
- Nx86 MUST NOT directly load raw Eden/Yuzu/Ryujinx/Atmosphère folders at runtime.
- Normal launch bakes only when relevant state changed.
- Stale or unsafe baked output is always hard-blocked.
- Every baked Game Build emits one generated runtime module, not one module per mod.
- Generated runtime modules are produced by Nx86/NDX.
- Nx86 MUST NOT load arbitrary native libraries from mod folders.
- GSO/GSC applies before user mods.
- User mods cannot override GSO/GSC.
- Partial recompilation is preferred whenever safe.
- If partial recompilation safety is uncertain, fall back to full rebuild.
- Luau scripts are bake-time only.
- Cheats MAY have a runtime manager, but MUST be validated ahead of time.
- The user's original downloaded mod files MUST remain untouched.
- Raw converted external-format leftovers MUST NOT remain in per-title mod folders.
- Removing a mod removes its
.ndx, related baked artifacts, generated runtime output, affected.nci, and related traces. - Normal UX SHOULD show Current Build; profiles are advanced/supporting behavior, not the preferred normal workflow.
- Standalone/single-executable/app-bundle export is a later feature, with Linux/AppImage-style export first and Windows/macOS later.
- Statically linked runtime output SHOULD remain an option.
.ndxpackage format- required
nxmod.toml - drag-and-drop import
- safe archive import
- external layout detection
- conversion to
.ndx - conversion wizard for ambiguous mods
- per-title installed mod storage
- Current Build UI
- bake planner
- validation pipeline
- GSO/GSC-first ordering
- conflict detection
- cache impact calculation
- hard-block stale output
- full effective content image
- RomFS/RomFS_ext baking
- content hashing
- content image invalidation
- content-only rebuilds without unnecessary code recompilation
- internal baked profile artifacts
- one generated runtime module per baked build
- hook/patch/cheat table emission
- Nx86 launcher integration
- minimal runtime loading path
- code-affecting mod support
- patch planning
- affected-region analysis
- partial native recompilation
- full rebuild fallback when needed
- full runtime cheat manager
- Build ID validation
- dev mode fast rebake
- diagnostics/logs
- bake-time Luau scripting support
- minimal Nx86 runtime for standalone bundles
- Linux/AppImage-style export first
.ncibundled with runtime/cache- optional static linking
- Windows/macOS export later
Nx86 is a game-running monster built around native recompilation.
It starts with synthetic ARM64 programs, grows into homebrew support, then targets commercial title compatibility, with TOTK-class workloads as the v1 ambition.
Nx86 accepts long compilation, large caches, aggressive x86_64-v4 code generation, shader AOT, profile sharing, guarded speculation, behavior patches, and deep runtime feedback because its goal is not simply to emulate.
Its goal is:
Compile the game into something that behaves like the original,
runs like native software,
and eventually no longer needs the full emulator around it.
Nx86 is not a normal JIT emulator.
Nx86 is Continuous Dynamic Compilation for Switch software.