Emulation Tips, Do’s and Don’ts#
This chapter describes the behaviors to account for when an application runs under emulation on Windows on ARM. The following sections cover CPU feature bits reported in each emulation mode, application compatibility, instruction timing, floating point precision, and memory alignment for atomic operations.
CPU Feature Bits in 64-bit Mode#
Compared to 32-bit mode, 64-bit mode supports the following additional CPU feature bits: AVX, AVX2, RDRAND, MOVBE, BMI1, BMI2, FMA, FC16, XSAVE, OSXSAVE, and CLFLUSH.
Compatibility Considerations for Mixed Binaries#
Applications and games that contain a mix of 32-bit and 64-bit binaries and CPU capabilities must be checked individually for each mode to avoid incorrect behavior. Microsoft’s 32-bit emulation is separate from 64-bit emulation for Windows on ARM, and 64-bit emulation supports AVX (256-bit vectors) and other instructions that 32-bit mode does not. Components that query CPU capabilities in 32-bit mode can see a different result than components that query them in 64-bit mode. Check CPUID and CPU capabilities in the mode in which the application will run.
The XSAVE and OSXSAVE feature bits are not available in 32-bit emulation, even though they are typically exposed on x86/x86_64 hardware. Always check CPU feature bits before executing XGETBV or any AVX or AVX2 instructions. Do not assume that AVX and AVX2 are always present, even in 64-bit emulation. Strictly speaking, x86_64 supports extensions only up to and including SSE2, so check support for every ISA above SSE2.
Application Compatibility#
Windows on Arm emulation can run many existing x86 and x86_64 user-mode applications. Compatibility depends on application behavior, dependencies, and the target configuration, so validate applications on the Windows versions and hardware configurations you support.
Feature Detection#
Query CPU capabilities in the mode in which the code runs. Use documented mechanisms appropriate to the codebase, such as __cpuid and IsProcessorFeaturePresent(), and check each required feature independently. Do not infer one CPU capability from another capability or from a CPU vendor string, because feature combinations can vary between execution modes and platforms. Do not reject an environment solely because it reports an ARM-based processor or an unexpected CPU vendor string.
Drivers and Dependencies#
x86 and x86_64 kernel-mode drivers cannot run on Windows on ARM. Provide an ARM64 driver, or make the driver-dependent feature optional. Verify that application dependencies are available in a binary format compatible with the process and its interoperability boundaries, and test application startup and optional components on the target configuration.
GPU Detection#
Enumerate GPUs through standard graphics APIs. When an application needs to match a documented RTX Spark N1X configuration, use the PCIe device IDs in RTX Spark GPU Identification. Do not use RTX Spark N1X device IDs as a generic integrated-GPU check or make assumptions based on unrelated GPU vendor or device IDs.
Runtime Assumptions#
Do not patch operating-system libraries or identify routines by assuming a particular x86 or x86_64 instruction sequence; use supported APIs and documented extension mechanisms. Avoid manually walking stack frames or assuming a fixed frame layout across interoperability boundaries. Instead, use the platform’s supported unwind, diagnostics, and debugging facilities. Validate code that depends on uncommon instructions, exceptional control flow, or exact processor exception behavior on the target Windows version.
Instruction Timing#
Instruction timings may vary under emulation and even from run to run. Applications and games should not rely on fixed instruction timings for timing loops.
Floating Point Precision#
Avoid x87 floating point instructions because they may not return full 80-bit precision, bit-accurate results, or correct status flags. Use SSE or AVX floating point instructions instead.
Atomic Operations and Memory Alignment#
Interlocked atomics such as XCHG, CMPXCHG, XADD, and LOCK-prefixed instructions may incur heavy penalties when the memory address is not naturally aligned. Ensure that all volatile and synchronization variables are naturally 4- or 8-byte aligned.