Skip to content

fix(dmac): drain GIF DMA chains through IRQ tags to the END-tag CHCR readback - #402

Open
LeandroSSB wants to merge 1 commit into
ran-j:mainfrom
LeandroSSB:pr-08-gif-dma-drain-end
Open

LeandroSSB wants to merge 1 commit into
ran-j:mainfrom
LeandroSSB:pr-08-gif-dma-drain-end

Conversation

@LeandroSSB

Copy link
Copy Markdown

Root cause

The generic DMA chain walk suspended the transfer at the first tag with IRQ set when CHCR.TIE = 1. In this runtime DMA is synchronous and the channel interrupt is delivered once at the drain — there is no resume protocol for a suspension. The drain then cleared STR/QWC (channel looks "idle") while CHCR.TAG stayed pinned at the suspending CNT tag (id 1).

Games that poll completion by reading the terminal tag id in CHCR[31:16] — canonical on the EE: the last tag of a chain is END (id 7) and hardware keeps the processed tag in the readback — then spin forever. On MOH:Vanguard the main thread parked for the whole run on ((CHCR >> 28) & 7) == 7 (5M+ reads, 0 hits), starving the entire pipeline behind it.

Fix

The walk no longer ends the chain at irq && tieEnabled; the reason is recorded for diagnostics and the drain continues to the END tag. The channel interrupt still fires once at the drain (queueCompletedDmacCause in processPendingTransfers, unchanged), and the processed tag's upper word still latches into CHCR[31:16] for the readback.

Test

ps2_memory_tests:

  • New: "GIF DMA chain with TIE drains through an IRQ tag to the END-tag readback" — kick with TIE=1 over a CNT+IRQ+END chain: both payloads reach the GS in order and the readback latches id 7.
  • Reworked: the old oracle that consecrated the suspension behavior.

Measured (MOH:Vanguard)

Kick CHCR = 0x90000184 (TIE=1) with a CNT+IRQ chain: before, the drain stopped at the IRQ tag and the game spun on the pinned CNT id; after, the drain crosses the IRQ tag to END and the readback latches id 7 — the sync spin is extinct.

🤖 Generated with Claude Code

Suite evidence

Fresh configure+build of ps2x_tests on this branch (VS 2022, Release): 447/447 passed, 0 failed.

…readback

The generic DMA chain walk suspended the transfer at the first tag with
IRQ set when CHCR.TIE=1. In this runtime DMA is synchronous and the
channel interrupt is delivered once at the drain - there is no resume
protocol for a suspension. The drain cleared STR/QWC (channel "idle")
while CHCR.TAG stayed pinned at the suspending CNT tag. Games that poll
completion by reading the terminal tag id in CHCR[31:16] - canonical on
the EE: the last tag of a chain is END (id 7) and hardware keeps the
processed tag in the readback - then spin forever. On MOH:Vanguard the
main thread parked for the whole run on ((CHCR >> 28) & 7) == 7
(5M+ reads, 0 hits), starving the entire pipeline behind it.

The walk no longer ends the chain at irq && tieEnabled; the channel
interrupt still fires at the drain (queueCompletedDmacCause in
processPendingTransfers, unchanged), and the processed tag's upper word
still latches into CHCR[31:16] for the readback.

Tests: new case "GIF DMA chain with TIE drains through an IRQ tag to the
END-tag readback" (kick with TIE=1 over a CNT+IRQ+END chain: both
payloads reach the GS in order and the readback latches id 7) and a
rework of the old oracle that consecrated the suspension behavior.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant