# How SharpEmu Handles PS5 NID Dispatch: A Two-Stage Resolution System

> Discover how SharpEmu manages PS5 NID dispatch using a two-stage resolution system. Learn about symbol catalog loading and HLE method registration to optimize your PlayStation Suite development.

- Repository: [Berk/sharpemu](https://github.com/par274/sharpemu)
- Tags: internals
- Published: 2026-07-13

---

**SharpEmu resolves PlayStation Suite (PSS) function calls by loading a symbol catalog from `aerolib.bin`, registering HLE methods via attributes, and dispatching them through a concurrent dictionary that maps NIDs to delegates.**

The **par274/sharpemu** project implements a clean two-stage mechanism to handle PS5 NID dispatch, bridging the gap between numeric function identifiers in emulated PlayStation binaries and their high-level emulated (HLE) implementations in .NET. This architecture separates symbol resolution from runtime dispatch, enabling efficient lookup of PSS functions during emulation.

## Stage 1: Symbol Catalog Resolution via Aerolib

At initialization, SharpEmu loads the embedded binary resource `aerolib.bin` through the `Aerolib.LoadFromEmbeddedBinary` method. This file contains the canonical mapping of **NIDs** (numeric IDs) to export names for all PlayStation Suite functions.

The `Aerolib` class implements the `ISymbolCatalog` interface and exposes two critical lookup methods:

- `TryGetByNid(string nid, out SysAbiSymbol)` – Retrieves the full symbol record using the numeric identifier.
- `TryGetByExportName(string name, out SysAbiSymbol)` – Performs reverse lookup from function name to NID.

The catalog is globally accessible via `Aerolib.Instance`, allowing any HLE module to resolve symbol information without hardcoding NIDs. This abstraction ensures that symbol management remains centralized and maintainable as the emulator's compatibility layer expands.

## Stage 2: Module Registration and Runtime Dispatch

When the emulator loads a .NET assembly containing HLE implementations, `ModuleManager.RegisterFromAssembly` scans all types and methods for the `[SysAbiExport]` attribute. This process builds the runtime dispatch infrastructure through three sequential steps:

1. **Resolution**: `ResolveExportInfo` queries the supplied `ISymbolCatalog` (typically `Aerolib.Instance`) to fill missing NIDs for methods that specify only export names, or vice versa.
2. **Registration**: The resolved NID and a compiled delegate accepting `CpuContext` are stored in the concurrent dictionary `_dispatchTable`.
3. **Invocation**: When the CPU backend encounters a PSS call, it extracts the import NID and invokes `ModuleManager.TryDispatch(nid, context, out result)` to execute the corresponding HLE method.

If the NID exists in `_dispatchTable`, the associated `SysAbiFunction` delegate executes immediately. Otherwise, the emulator returns an "NID not found" error to the guest system.

## Implementation Example

The following code demonstrates how HLE methods are defined, registered, and dispatched in the SharpEmu architecture:

```csharp
// HLE method implementation with explicit NID attribution
[SysAbiExport(Nid = "scePssAudCreateSourcePlayer")]
public static int CreateSourcePlayer(CpuContext ctx)
{
    // Audio subsystem emulation logic...
    return (int)OrbisGen2Result.ORBIS_GEN2_SUCCESS;
}

```

```csharp
// Registration during emulator startup
var runtime = new SharpEmuRuntime(...);
runtime.ModuleManager.RegisterFromAssembly(
    typeof(PssAudioExports).Assembly,  // Assembly containing HLE exports
    Generation.Gen5,                   // Target PS5 generation
    Aerolib.Instance);                 // Symbol catalog for NID resolution

```

```csharp
// Runtime dispatch from the CPU backend
string nid = "scePssAudCreateSourcePlayer";
if (moduleManager.TryDispatch(nid, cpuContext, out var result))
{
    // HLE method executed; result contains return value
}
else
{
    // Handle missing NID error
}

```

## Key Source Files

Understanding PS5 NID dispatch requires familiarity with these specific components in the **par274/sharpemu** repository:

| File | Role |
|------|------|
| [`src/SharpEmu.HLE/ModuleManager.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/ModuleManager.cs) | Contains the central `_dispatchTable` and the `TryDispatch` logic that routes NIDs to HLE delegates. |
| [`src/SharpEmu.HLE/Aerolib/Aerolib.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/Aerolib/Aerolib.cs) | Implements `ISymbolCatalog` and loads the NID-to-export-name mappings from the embedded `aerolib.bin` resource. |
| [`src/SharpEmu.HLE/ISymbolCatalog.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/ISymbolCatalog.cs) | Defines the interface contract for symbol lookup used by the module registration system. |
| [`src/SharpEmu.Core/Runtime/SharpEmuRuntime.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Runtime/SharpEmuRuntime.cs) | Orchestrates initialization, wiring the `ModuleManager` with the `Aerolib` catalog at startup. |

## Summary

- **SharpEmu** uses a decoupled two-stage architecture for PS5 NID dispatch: symbol catalog loading and runtime dispatch table management.
- The **`Aerolib`** class provides authoritative NID-to-name mappings via `TryGetByNid` and `TryGetByExportName`, sourcing data from `aerolib.bin`.
- **`ModuleManager.RegisterFromAssembly`** automatically discovers HLE methods marked with `[SysAbiExport]` and populates the `_dispatchTable` with resolved NIDs.
- **`ModuleManager.TryDispatch`** serves as the hot path for the CPU backend, executing the correct HLE delegate in constant time via concurrent dictionary lookup.
- This design allows the emulator to handle PSS function calls without embedding NID constants directly in the HLE implementation code.

## Frequently Asked Questions

### What is the purpose of the `aerolib.bin` file in SharpEmu?

The `aerolib.bin` file is an embedded binary resource containing the official mapping between PlayStation Suite NIDs (numeric identifiers) and their corresponding export names. SharpEmu loads this via `Aerolib.LoadFromEmbeddedBinary` at startup to ensure accurate symbol resolution without hardcoding thousands of NID strings throughout the codebase.

### How does SharpEmu handle methods that only specify an export name without a NID?

When `ModuleManager.RegisterFromAssembly` processes a method annotated with `[SysAbiExport]` that lacks a NID parameter, it invokes `ResolveExportInfo` to query the `ISymbolCatalog` (typically `Aerolib.Instance`). The catalog's `TryGetByExportName` method retrieves the corresponding NID, ensuring every registered function has a resolved numeric identifier before entering the dispatch table.

### What happens when the emulator encounters an unknown NID during execution?

If the CPU backend calls `ModuleManager.TryDispatch` with a NID that does not exist in the `_dispatchTable`, the method returns `false` and the emulator reports an "NID not found" error to the guest system. This typically indicates that the HLE module for that specific PlayStation Suite function has not yet been implemented or registered.

### Can the symbol catalog be replaced or extended for different PlayStation generations?

Yes. While `Aerolib` is the default implementation used for PS5 (Generation.Gen5), the `ModuleManager` accepts any `ISymbolCatalog` implementation. This allows the emulator to support multiple PlayStation generations by supplying different catalog instances during the `RegisterFromAssembly` call, making the architecture flexible for PS4 or future generation compatibility layers.