SharpEmu Gen4 vs Gen5 Handling: Differences Between PS4 and PS5 Emulation
SharpEmu distinguishes PlayStation 4 and PlayStation 5 emulation through a [Flags] enum called Generation, attaching platform targets to every high-level emulation (HLE) function and filtering exports at runtime based on the guest ELF header.
The par274/sharpemu repository implements a clean architectural separation between console generations using bitwise flags. This design allows the emulator to support both legacy PS4 (Gen4) and modern PS5 (Gen5, also referred to as GenS or PSS) software within a single codebase while maintaining accurate system-call semantics for each platform.
The Generation Flag Architecture
Defining Console Generations
At the core of SharpEmu’s platform abstraction lies the Generation enum defined in SharpEmu.HLE/Generation.cs. This enumeration uses the [Flags] attribute to support bitwise combination:
[Flags]
public enum Generation
{
Gen4 = 1 << 0, // PlayStation 4 family
Gen5 = 1 << 1, // PlayStation 5 family (GenS/PSS)
}
Only two values exist: Generation.Gen4 representing the PS4 family, and Generation.Gen5 representing the PS5 family.
Multi-Target Support with Bitwise Flags
Because the enum is marked with [Flags], a single export can target one or both generations by combining values with a bitwise OR operation:
Generation.Gen4 | Generation.Gen5
This flexibility allows developers to mark universal functions that work across both consoles while reserving specific implementations for generation-exclusive features.
Export Registration and Runtime Filtering
SysAbiExportAttribute Target Property
Each HLE function in SharpEmu is decorated with SysAbiExportAttribute, which contains a Target property of type Generation. This property determines which console generation(s) can access the function:
// Example of a sys-abi export that works on both generations
[SysAbiExport(
Nid = "Zxa0VhQVTsk",
ExportName = "sceKernelWaitSema",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libKernel")]
public static int KernelWaitSema(int semaId, int timeout) { /* ... */ }
Registry Filtering in SysAbiExportRegistry
During startup, the SysAbiExportRegistry (generated from the source analysis) builds a dictionary of exports filtered by the current generation. Only exports whose Target flag matches the running generation are made available to the guest OS. This filtering is verified by test suites in SysAbiExportGeneratorTests.cs and SysAbiRegistryTests.cs.
// Runtime selection (simplified)
var gen = guestImage.DetectGeneration(); // → Generation.Gen4 or Generation.Gen5
var exports = SysAbiExportRegistry.CreateExports(gen);
host.RegisterExports(exports);
Platform-Specific Implementation Differences
Shared vs. Divergent Code Paths
Inside library source files such as VideoOutExports.cs, UserServiceExports.cs, and RtcExports.cs, method bodies are often reused for both generations. However, some functions contain conditional logic that checks the Generation flag to handle differences in system-call signatures, data structures, or behavior that changed between PS4 and PS5.
Generation-Exclusive Features
When a function applies only to one generation, its Target is set to that single flag. For example, PS5-only features like new audio pipelines use Generation.Gen5 exclusively:
// PS5-only export (GenS / PSS)
[SysAbiExport(
Nid = "abc123...",
ExportName = "sceAudioOutOpenExt",
Target = Generation.Gen5,
LibraryName = "libAudioOut")]
public static int AudioOutOpenExt(/* ... */) { /* ... */ }
Conversely, legacy PS4 behavior remains isolated in classes guarded by Gen4 checks within the SharpEmu.HLE.Host.* namespace.
Runtime Generation Detection
ELF Header Analysis
When the emulator launches a guest image, it determines the target generation from the ELF header using SharpEmu.Core.Loader.ElfHeader.cs. This detected value is stored in the emulated CPU context and supplied to the HLE layer.
CPU Context and HLE Layer Integration
The CPU context propagates the generation information to the HLE layer, which then selects the appropriate export set. If a guest requests a function not present for its generation, the emulator returns the standard SCE_ERROR_NOT_FOUND error, maintaining correct error semantics for each platform.
Testing Generation Isolation
The test suite verifies both generations separately to ensure no cross-contamination of exports. For example, SysAbiExportGeneratorTests.cs creates exports with Target = Generation.Gen4 | Generation.Gen5 and asserts that the registry correctly filters them when called with Generation.Gen4 versus Generation.Gen5. This ensures that PS4 games cannot access PS5-specific syscalls and vice versa.
Summary
- SharpEmu uses the
Generationflag enum (Gen4for PS4,Gen5for PS5) to separate platform-specific code paths. - SysAbiExportAttribute attaches a
Targetproperty to every HLE function, determining which generation(s) can access it. - SysAbiExportRegistry filters exports at runtime based on the detected generation, ensuring only compatible functions are exposed.
- ElfHeader.cs analyzes the guest binary to determine the target generation from the ELF header.
- Generation-exclusive features (like
sceAudioOutOpenExt) target onlyGen5, while shared functions useGeneration.Gen4 | Generation.Gen5. - Missing functions for a specific generation return
SCE_ERROR_NOT_FOUNDto maintain accurate emulation semantics.
Frequently Asked Questions
How does SharpEmu determine whether to use Gen4 or Gen5 mode?
SharpEmu detects the target generation by analyzing the guest binary's ELF header through SharpEmu.Core.Loader.ElfHeader.cs. This value is stored in the emulated CPU context and supplied to the HLE layer, which then filters the available exports accordingly.
Can a single HLE function target both PS4 and PS5?
Yes. Developers can mark functions with Target = Generation.Gen4 | Generation.Gen5 using the bitwise OR operator. This is common for stable system calls like sceKernelWaitSema that maintain compatible signatures across both console generations.
What happens when a PS4 game calls a PS5-exclusive function?
If a guest requests a function not present for its detected generation, the emulator returns SCE_ERROR_NOT_FOUND. This mirrors the behavior of actual hardware, where incompatible system calls are not implemented for that platform.
Where is the Generation enum defined in the SharpEmu source?
The Generation enum is defined in /SharpEmu.HLE/Generation.cs as a [Flags] enumeration with two values: Gen4 (1 << 0) for PlayStation 4 and Gen5 (1 << 1) for PlayStation 5 (also referred to as GenS or PSS).
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →