Repository navigation
DSP HLE Fix Examples and Testing
Experimental development work, not a complete DSP replacement. The running xemu HLE mode still uses the DSP JIT for unsupported work. Some files below are uncommitted worktree-only changes, unavailable at public source links. A match against xemu's JIT is not Xbox-hardware, Dolby, 5.1 or full game-audio proof.
Operation and DSP-PC inventory · Current results and complete measurement tables
These short excerpts are from the local source snapshot on 2026-11-03. DSP PCs identify instructions in an identified emulated program; they are not guest audio API command IDs.
| Fix | Location | Purpose and limit |
|---|---|---|
| Program and filter guard |
gp-filter-hle.c, gp_filter_hle_try_run
|
Admit a known program and selected filter positions; otherwise keep the DSP route. |
| Saturated 24-bit gain |
gp-gain-hle.h, gp_gain_hle (worktree-only) |
Compute 16 output samples in native code, staging output until input validation succeeds. |
| Native EP program validation |
ep-native-engine.h, ep_native_engine_validate_program (worktree-only) |
Clear prior approval before checking current program memory; changes revoke verification. |
| Transactional EP FIFO |
ep-native-engine.h, ep_native_engine_process_fifo (worktree-only) |
Stage engine state and PCM; commit the staged state only after the all-or-nothing FIFO callback succeeds. |
| DMA side effects |
dsp-replay.c, dsp_replay_native_dma_start (worktree-only changes) |
Invoke the existing peripheral and re-read state before restoring it, so DMA changes are preserved. |
| GP frame entry |
gp-frame-entry-project.h, gp_frame_entry_project (worktree-only) |
Project one guarded start-frame acknowledgement in offline replay. Strict replay next reaches an unhandled PC. |
| GP frame counter |
gp-frame-entry-project.h, gp_frame_counter_project (worktree-only) |
Read the existing emulated counter at 0xffffb3 and project the guarded write to X:0x7f. |
| GP frame DMA setup |
gp-frame-entry-project.h, gp_frame_setup_project (worktree-only) |
Project setup from 0x31 to 0x10a before native DMA stop/freeze. |
| GP DMA handoff |
gp-frame-entry-project.h, gp_frame_dma_prepare_project (worktree-only) |
Prepare DMA next-block from 0x112 to 0x118; strict replay executes the native sequence. |
| GP DMA completion |
gp-frame-entry-project.h, gp_frame_dma_complete_project (worktree-only) |
Project guarded end-of-list acknowledgement and return from 0x120 to 0x12c. |
| GP frame return |
gp-frame-entry-project.h, gp_frame_return_project (worktree-only) |
Project the zero X:4 branch from 0x12c to 0x33, or the nonzero branch to 0x66. |
| GP filter-entry handoff |
gp-frame-entry-project.h, gp_frame_filter_entry_project (worktree-only) |
Project 0x33 to 0x185 for odd X:0x84; even values are rejected. |
| GP first-filter bridge |
gp-filter-hle.c, gp_filter_hle_start_verified, gp_filter_hle_tail_verified (worktree-only changes) |
Bridge the first filter's entry and tail to existing native slices in offline strict replay. |
| GP eight-channel filter |
gp-filter-hle.c and gp-frame-entry-project.h, gp_filter_transition_project (worktree-only changes) |
Generalize first/tail handling across eight channels and project seven active-channel transitions. Inactive channels remain unqualified. |
| GP meter entry |
gp-frame-entry-project.h, gp_frame_meter_entry_project (worktree-only) |
Project post-filter setup for odd and even control paths before the meter. |
| GP meter transition |
gp-frame-entry-project.h, gp_meter_transition_project (worktree-only) |
Store the completed meter and prepare the next channel. |
| GP final meter exit |
gp-frame-entry-project.h, gp_meter_final_project (worktree-only) |
Write the last meter and restore loop/stack state when LC = 1. |
| GP post-meter dispatch |
gp-frame-entry-project.h, gp_post_meter_dispatch_project (worktree-only) |
Guard the X:0x1df = 3 route and project stack setup to 0x8d1; other control routes remain unsupported. |
| GP post-meter DMA return |
gp-frame-entry-project.h, gp_dma_return_project (worktree-only) |
Project 0x8d9 to 0x8df; replay writes the verified DMA next-block through the existing peripheral before the native sequence. |
| GP DMA return to gain |
gp-frame-entry-project.h, gp_dma_to_gain_project (worktree-only) |
Set six address-modulo registers and load the gain buffer pointer before the native gain entry at 0x493. |
| GP first gain return |
gp-frame-entry-project.h, gp_gain_next_project (worktree-only) |
Project the first 0x498 return back to 0x493. |
| GP gain to feedback |
gp-frame-entry-project.h, gp_gain_to_feedback_project (worktree-only) |
Project the second 0x498 return to native feedback entry 0x788. |
| GP first feedback return |
gp-frame-entry-project.h, gp_feedback_next_project (worktree-only) |
Project the first 0x792 return back to 0x788. |
| GP feedback-to-copy and stride copy |
gp-frame-entry-project.h, gp_feedback_to_copy_project, gp_stride_copy_project (worktree-only) |
Project the second feedback return and preserve ordered in-place copy behavior; guarded to the tested alias-buffer range and state. |
| GP copy acknowledgement and mix setup |
gp-frame-entry-project.h, gp_copy_ack_project, gp_ack_to_mix_project (worktree-only) |
Acknowledge DMA EOL through the existing peripheral, then prepare the tested mixing loop. |
| GP interpolation/mix loop |
gp-frame-entry-project.h, gp_mix_loop_project (worktree-only) |
Project six fixed-point values and accumulator/flags; reject overlap or unqualified clipping/delta. |
| GP mix-end dispatch |
gp-frame-entry-project.h, gp_mix_end_control_project (worktree-only) |
Follow two guarded control branches after the mixing loop. |
| GP control to ramp |
gp-frame-entry-project.h, gp_control_to_ramp_project, gp_ramp_loop_project (worktree-only) |
Prepare and execute the tested 16-sample gain ramp, including signed clipping. |
| GP special controls |
gp-frame-entry-project.h, gp_control_100_project, gp_control_zero_project (worktree-only) |
Handle a tested control-0x100 effect transition and zero-control ramp reset. |
| GP ramp to add |
gp-frame-entry-project.h, gp_ramp_to_add_project (worktree-only) |
Write completed gain/control, restore loop stack and set up the existing native add. |
| GP add continuation and MAC setup |
gp-frame-entry-project.h, gp_add_next_project, gp_add_final_to_mac_project (worktree-only) |
Continue the guarded add loop and set up the tested multiply-accumulate route. |
| GP MAC continuation and exit |
gp-frame-entry-project.h, gp_mac_next_project, gp_mac_final_project (worktree-only) |
Return to the next MAC or restore loop stack and flags on the guarded final exit. |
| GP second MAC setup |
gp-frame-entry-project.h, gp_mac_second_setup_project (worktree-only) |
Prepare tested buffer pointer, gain, nested loop and stack for the next native MAC. |
| GP nested MAC continuation |
gp-frame-entry-project.h, gp_mac_nested_next_project (worktree-only) |
Load the next gain and restore destination pointer and nested stack on the guarded return. |
| GP outer MAC continuation |
gp-frame-entry-project.h, gp_mac_outer_next_project (worktree-only) |
Exit the inner loop, advance source/destination pointers and set the next gain and stack. |
| GP outer MAC final exit |
gp-frame-entry-project.h, gp_mac_outer_final_project (worktree-only) |
Finish the guarded nested loops, read XRAM, advance pointer and restore stack and LF/FV flags. |
| GP three-pointer mix |
gp-frame-entry-project.h, gp_mix3_setup_project, gp_mix3_loop_project (worktree-only) |
Set up three pointers and sum 16 signed input pairs; reject clipping and output/input overlap. |
| GP mix return handoffs |
gp-frame-entry-project.h, gp_mix3_next_project, gp_mix3_to_add_project (worktree-only) |
Select by return address, reload buffers and enter the existing mixer or add. |
| GP post-mix add returns |
gp-frame-entry-project.h, gp_post_mix_add_next_project (worktree-only) |
Recognize three return addresses and reload guarded pointers for the next add. |
| GP add to mix |
gp-frame-entry-project.h, gp_add_to_mix3_project (worktree-only) |
Reload three audio buffer pointers and loop state before the tested mix. |
| GP mix to gain |
gp-frame-entry-project.h, gp_mix3_to_gain_project (worktree-only) |
Reload buffer/gain and enter the existing native gain. |
| GP post-mix gain returns |
gp-frame-entry-project.h, gp_post_mix_gain_next_project (worktree-only) |
Handle tested return sites 0x663 and 0x669 by reloading gain/buffer or continuing directly. |
| GP post-gain add handoffs |
gp-frame-entry-project.h, gp_post_gain_add_project (worktree-only) |
Enter add through tested return sites 0x66b and 0x671, with pointer reload or direct continuation. |
| GP post-gain copy |
gp-frame-entry-project.h, gp_post_gain_copy_setup_project, gp_post_gain_copy_loop_project (worktree-only) |
Set up and perform a guarded 16-sample copy, preserving ordered overlap and recognized aliases. |
| GP post-gain copy continuation |
gp-frame-entry-project.h, gp_post_gain_copy_next_project (worktree-only) |
Set loop state for the next copy at the tested return site. |
| GP copy to feedback |
gp-frame-entry-project.h, gp_copy_to_feedback_project (worktree-only) |
Reload audio and set feedback pointer, accumulator, flags and return stack. |
| GP post-copy feedback returns |
gp-frame-entry-project.h, gp_post_copy_feedback_next_project (worktree-only) |
Handle two tested return sites; the second sets up a three-block feedback loop. |
| GP feedback loop returns |
gp-frame-entry-project.h, gp_feedback_loop_next_project (worktree-only) |
Advance buffer/state pointers and restore loop stack for tested continuation and final exit. |
| GP feedback to matrix |
gp-frame-entry-project.h, gp_feedback_to_matrix_project (worktree-only) |
Prepare guarded buffer/coefficient pointers and four-iteration matrix setup. |
| GP matrix loop returns |
gp-frame-entry-project.h, gp_matrix_loop_next_project (worktree-only) |
Preserve coefficient, buffer and loop state through tested matrix continuations and final exit. |
| GP matrix-to-add setup |
gp-frame-entry-project.h, gp_matrix_add_setup_project (worktree-only) |
Load two buffers and set the guarded four-channel loop and return stack. |
| GP matrix add returns |
gp-frame-entry-project.h, gp_matrix_add_next_project (worktree-only) |
Continue the four-channel add and restore the loop stack on exit. |
| GP matrix-to-feedback setup |
gp-frame-entry-project.h, gp_matrix_feedback_setup_project (worktree-only) |
Set buffer, feedback state pointer and loop stack; reject unverified accumulator states. |
| GP matrix feedback loop returns |
gp-frame-entry-project.h, gp_matrix_feedback_next_project (worktree-only) |
Advance feedback state, continue the loop or restore the saved stack at its exit. |
| GP matrix feedback to copy |
gp-frame-entry-project.h, gp_matrix_copy_setup_project (worktree-only) |
Load guarded source and destination pointers and prepare the existing 16-sample copy loop. |
| GP matrix sample-copy return |
gp-frame-entry-project.h, gp_matrix_copy_return_project (worktree-only) |
Restore the return stack and reload four pointers for subsequent work. |
| GP matrix mixer dispatch |
gp-frame-entry-project.h, gp_matrix_mix_dispatch_project (worktree-only) |
Load mixer gains and choose the observed control-4 branch. Other controls are rejected. |
| GP matrix mixer continuation |
gp-frame-entry-project.h, gp_matrix_mix_next_project (worktree-only) |
Restore pointers and gains and choose the tested control-4 path for a second mix. |
| GP second mixer to copy |
gp-frame-entry-project.h, gp_matrix_mix_to_copy_project (worktree-only) |
Load buffers and prepare the copy loop after the second mixer. |
| GP duplicate-sample copy |
gp-frame-entry-project.h, gp_matrix_duplicate_copy_project (worktree-only) |
Copy each of 16 input samples twice in DSP order, preserving overlap behavior. |
| GP duplicate-copy return |
gp-frame-entry-project.h, gp_matrix_duplicate_return_project (worktree-only) |
Restore the verified return stack and prepare the next add. |
| GP post-duplicate add returns |
gp-frame-entry-project.h, gp_matrix_post_duplicate_add_project (worktree-only) |
Continue the add or prepare the next duplicate-sample copy. |
| GP late DMA wait entry |
gp-frame-entry-project.h, gp_late_dma_wait_entry_project (worktree-only) |
Enter the existing DMA completion wait without executing the preceding DSP return. |
| GP late DMA completion |
gp-frame-entry-project.h, gp_late_dma_wait_complete_project (worktree-only) |
Acknowledge completed DMA and restore the return stack; reject incomplete transfers. |
| GP post-DMA audio entry |
gp-frame-entry-project.h, gp_post_dma_audio_entry_project (worktree-only) |
Select the verified active control path and initialize DSP address modes. |
| GP post-DMA delay setup |
gp-frame-entry-project.h, gp_post_dma_delay_entry_project (worktree-only) |
Load delay pointers and coefficients and restore verified status flags. |
| GP post-DMA next delay |
gp-frame-entry-project.h, gp_post_dma_delay_next_project (worktree-only) |
Save the first delay state and set pointers and coefficients for the second channel. |
| GP post-DMA final delay return |
gp-frame-entry-project.h, gp_post_dma_delay_final_project (worktree-only) |
Save the second delay state and choose the observed active next stage. |
| GP decimation setup |
gp-frame-entry-project.h, gp_decimate_setup_project (worktree-only) |
Load tested pointers, phase and gain and project DSP flags before the native decimator. |
| GP decimation DMA handoff |
gp-frame-entry-project.h, gp_decimate_dma_entry_project (worktree-only) |
Save phase and output count before entering the existing DMA routine. |
| GP decimation DMA stop call and return |
gp-frame-entry-project.h, gp_decimate_dma_stop_entry_project, gp_decimate_dma_stop_return_project (worktree-only) |
Preserve the call stack around the existing native DMA stop/freeze operation. |
| GP decimation DMA descriptor setup |
gp-frame-entry-project.h, gp_decimate_dma_prepare_project (worktree-only) |
Update status and stack, then write the next descriptor through the DMA peripheral. |
| GP decimation DMA completion |
gp-frame-entry-project.h, gp_decimate_dma_wait_entry_project, gp_decimate_dma_wait_complete_project (worktree-only) |
Enter the wait and acknowledge completed transfers through the DMA peripheral. |
| GP next decimation channel |
gp-frame-entry-project.h, gp_decimate_next_channel_project (worktree-only) |
Select the tested active channel and prepare pointers, gain, phase and status. |
| GP decimation frame exit |
gp-frame-entry-project.h, gp_decimate_frame_exit_project (worktree-only) |
Return from the fourth channel to the frame tail. |
| GP frame-tail counter |
gp-frame-entry-project.h, gp_frame_tail_counter_project (worktree-only) |
Read the emulated counter and prepare a comparison; only zero is qualified. |
| GP frame-tail comparison and DMA |
gp-frame-entry-project.h, gp_frame_tail_dispatch_project, gp_frame_tail_dma_prepare_project, gp_frame_tail_dma_complete_project, gp_frame_tail_second_dma_project (worktree-only) |
Compare, dispatch and complete two DMA transfers using the existing peripheral. |
| GP frame-tail finish and halt |
gp-frame-entry-project.h, gp_frame_tail_finish_project, gp_frame_tail_halt_project (worktree-only) |
Complete both tested comparison branches and request halt through the existing peripheral. |
| GP native-state replay |
dsp-replay.c, dsp_init_gp_native_state (worktree-only) |
Run the candidate frame without creating a DSP JIT; compare separately with a JIT-backed reference. |
From the committed file:
if (!hle || cycles != 1000 || cpu->pc < 0x185 || cpu->pc > 0x413) {
return false;
}From the uncommitted gp-gain-hle.h:
int64_t word = gp_mix2_floor_shift(product, 24);
word = word < -0x800000 ? -0x800000 :
word > 0x7fffff ? 0x7fffff : word;
staged[i] = (uint32_t)word & 0xffffff;These excerpts are from uncommitted gp-frame-entry-project.h, after program and state guards. For control 0x100, the path clears the control and prepares the add loop:
after->jit.xram[0x3da] = 0;
after->jit.xram[0x3d9] = 0x2000;
after->jit.cpu.pc = 0x4a0;For zero control, the tested path prepares a decreasing gain ramp:
after->jit.cpu.registers[DSP_REG_Y0] = 0xff0000;
after->jit.cpu.registers[DSP_REG_A1] = 0x7f0000;
after->jit.cpu.registers[DSP_REG_B1] = 0x7f0000;These snippets show only part of each operation; guards, memory writes, flags and stack setup remain necessary. The guarded 0x80 path is now supported for the tested inputs in offline replay; unqualified inputs are rejected.
For control 0x80, the worktree-only effect helper computes the tested bounded wrap in native code:
uint32_t loops = delta < 0 ? ((uint32_t)(-delta) + stride - 1) / stride : 0;
int64_t final = (int64_t)delta + (int64_t)loops * stride;
if (loops > 4096 || final < 0 || final > 0x7fffff) return false;This excerpt omits the program/state guards and DSP register updates. It does not establish correctness for rejected inputs or live playback.
The 16-sample MAC uses signed 24-bit inputs, fixed-point rounding and saturated output. This excerpt is from the worktree-only gp-mac-hle.h; the full function also validates inputs and stages its output.
int64_t acc = 2 * gain * gp_mix2_signed24(src[i]) +
gp_mix2_signed24(dst[i]) * 0x1000000;
int64_t word = gp_mix2_floor_shift(gp_mix2_round24(acc), 24);This observed 32-sample route selects output by phase and applies signed gain. This is a fragment of worktree-only gp-decimate-hle.h, not the complete operation; it also clamps samples and returns the next phase.
if (phase >= 6) {
int32_t sample = input[i] & 0x800000 ?
(int32_t)input[i] - 0x1000000 :
(int32_t)input[i];
int64_t product = (int64_t)sample * signed_gain;The guarded setup at 0x97e is now included in offline strict replay. The math helper does not prove that every decimation route or its following DMA works.
Program validation, from the uncommitted ep-native-engine.h:
engine->program_verified = false;
if (!check) {
return false;
}
engine->program_verified = check(opaque, engine->state.jit.pram);Meter transition, from the uncommitted gp-frame-entry-project.h:
after->jit.xram[dest] = r[DSP_REG_A1];
after->jit.cpu.pc = 0x431;
after->jit.cpu.pc_advance = 1;
after->jit.cpu.cycle_count += 12;Final meter exit, from the same uncommitted file:
after->jit.xram[0x1c9] = r[DSP_REG_A1];
after->jit.cpu.pc = 0x422;
after->jit.cpu.pc_advance = 0;
after->jit.cpu.cycle_count += 8;Add continuation, from the same uncommitted file:
after->jit.cpu.pc = 0x4a0;
after->jit.cpu.pc_advance = 0;
after->jit.cpu.cycle_count += 12;Matrix-to-add setup, from the uncommitted gp-frame-entry-project.h (after the program and state guards):
after->jit.cpu.pc = 0x4a0;
after->jit.cpu.cycle_count += 16;
after->jit.cpu.registers[DSP_REG_R1] = before->jit.xram[0x1eb];
after->jit.cpu.registers[DSP_REG_R0] = before->jit.xram[0x1f1];| Saved-input check | Result | CPU / wall | Peak child RSS |
|---|---|---|---|
Control 0x80, entry / effect / ramp setup / signed ramp |
256 / 512 / 256 / 256 varied cases matched | Included below | Included below |
| JIT-free candidate full frames | 16 / 16 matched recorded final state and I/O with zero DSP steps | Included below | Included below |
| Mixed full frames | 16 / 16 matched; zero DSP steps | 1.128 / 1.161 s | 30,392 KiB |
These are combined offline test costs, not a native-versus-DSP performance comparison. The full progression and resource measurements are in the evidence archive. The resource figures are from a combined offline test campaign and are not comparable to earlier campaigns. The JIT-backed strict run completed all 16 frames, and the separate native-state candidate matched its status, state and I/O without constructing a JIT.
A FIFO probe must be side-effect-free and its commit must either write every byte or write none. The offline engine is not connected to the live device; the separate experimental JIT-backed EP route has focused guest-RAM FIFO tests.
The following commands require the experimental worktree and an existing configured build/. Some targets and scripts below are uncommitted and will not exist at the public commit. Build configuration and DSP provider dependencies follow the local project setup.
ninja -C build test-xbox-ep-mix-hle test-xbox-ep-native-engine \
test-xbox-gp-gain-hle test-xbox-gp-mac-hle test-xbox-mcpx-apu-dsp-replay
build/test-xbox-ep-mix-hle
build/test-xbox-ep-native-engine
build/test-xbox-gp-gain-hle
build/test-xbox-gp-mac-hleUse existing private captures for replay; they can contain game program and audio data. The strict mode stops at the first unhandled operation instead of executing a DSP instruction, but still constructs a JIT backend for state and DMA.
build/test-xbox-mcpx-apu-dsp-replay --replay-gp-hle-strict /path/to/private/gp-frame
build/test-xbox-mcpx-apu-dsp-replay --replay-native-ep-candidate /path/to/private/ep-frame
build/test-xbox-mcpx-apu-dsp-replay --replay-native-ep-sequence \
--repeat 100 /path/to/private/ep-frame.bin.*Offline DSP-vs-native synthetic checks require private host-ABI GP pairs and use the DSP JIT as the reference. Rejected cases are unsupported, not matches.
build/test-xbox-mcpx-apu-dsp-replay --fuzz-gp-gain /path/to/private/gain-pairs --variants 4096
build/test-xbox-mcpx-apu-dsp-replay --fuzz-gp-mac /path/to/private/mac-pairs --variants 4096
build/test-xbox-mcpx-apu-dsp-replay --fuzz-gp-decimate /path/to/private/decimate-pairs --variants 4096These measurements have different scopes and are not interchangeable. The following earlier results are retained for context, not proof of current-head performance:
| Offline test | Median CPU | Sampled process peak RSS | Scope |
|---|---|---|---|
| EP standalone mixer, 256 stereo frames | 2.6056 µs/block | 1,612 KiB | Native-only fixture, five runs; no DSP baseline. |
| GP gain, 16 samples | 0.7893 µs/projection | 1,776 KiB | Native full-state projection, fixed input; no DSP baseline. |
| GP multiply-accumulate, 16 samples | 0.7797 µs/projection | 1,804 KiB | Native full-state projection, fixed input; no DSP baseline. |
| EP verified 64-frame chain | 36.32 µs/frame | 30,004 KiB | Linked replay process, including verification; no DSP execution or baseline. |
A separate synthetic FIFO microbenchmark measured 86.86 → 115.39 ns/write, an increase of 28.52 ns / 32.83% cost, with mock dirty marking. It is not an overall emulator or game comparison. See the overview for all workloads, earlier results, variations and limitations.
DSP tooling guide and navigation updated November 2, 2026 for experimental PR #384, source 8f51d237. Capture/replay usage and limits.
The earlier wiki-wide review was published November 1, 2026. Emulator source: b7140848. Reviewed wiki content: 1d2b671. Current status · Release availability · Publication process.
- Home
- Current status
- Stable versus main
- Implemented mechanisms
- Controls and defaults
- Measured results and limits
- Complete change register
- System
- CPU and vCPU
- Memory and DMA
- Graphics / NV2A
- APU and audio
- Timing and timers
- Platform and I/O
- Hardware observations
- Fidelity boundaries
- Methodology
- PGR2 routes
- Debugging lag / hot paths
- Tools and commands
- DSP capture, replay and fuzzing
- HLE readiness and public XISO proof
- Concurrent DSP shadow and OpenAL proof
- DSP HLE operation inventory
- DSP HLE fix examples and testing
- Development
- Upstream shortlist
- Wiki maintenance
- Research / retired work
- Optimization catalog
- Hot-path shortcuts
- Researched experiments
- Unproven proposal directory
- PR lessons
- September26 snapshot
Repository · PRs · Issues