blitter: BLTPRI asserts BLS for the whole blit, fencing the CPU off the bus#162
Merged
Conversation
…he bus With BLTPRI set, BBUSY holds the BLS line asserted until BLTDONE, so the CPU is denied every chip-bus cycle for the duration of the blit -- including the pipeline's bus-free micro-cycles (the first empty D phase, fill's extra idle cycle, line-mode Bresenham cycles). The Copper and fixed DMA still use those cycles; only the CPU is fenced. Previously the arbitration returned the bubble cycles as Idle before checking BLTPRI, letting the CPU steal them mid-blit. Software depends on the fence. Jim Power's trackloader MFM-decodes each sector with a blitter pass under BLTPRI: it saves the word below the blit destination, writes BLTSIZE, and restores the word two instructions later, relying on that CPU write being held until after the blit's first D write (pipeline warm-up garbage lands one word below the real output). Granting the CPU the first-D bubble inverted the order: the restore landed first, the blitter then overwrote it, corrupting the last data word of every decoded sector. The depacker consumed the corrupt stream, ended on an odd address, and the game crashed with guru 00000003 (address error) after the level load. - bltpri_stalls_cpu_chip_access_through_blitter_access_cycles now expects the CPU to wait through the whole blit (3 -> 6 cck); the nasty-lockout comment names the BLS behaviour. - blithog_set_blocks_cpu_slowdown_back_pressure_until_blitter_finishes now includes the terminal E/F cycles in the wait (14 -> 16 cck). - timing-test golden row 26 (A->D fill + 3bpl display + BLTPRI) re-blessed 25073 -> 25161 (FS-UAE 25095 / vAmiga 25097). The old -22 proximity was a cancellation: the polling CPU sneaked DMACONR reads into blit bubbles and observed completion early, masking blit-under-display-contention drift that is now visible; noted in timing-test/README.md. - BLTP START slot-trace diag now prints DMACON alongside BLTCON0/1. - Env-gated diagnostics (COPPERLINE_DIAG_SLOTMAP, COPPERLINE_DUMP_BUS_ACCOUNTING) are re-derived from the environment after a save-state load instead of inheriting the saved-off values. - docs/internals/timing.md: CPU-vs-blitter and CPU-contention sections updated to describe the BLS fence.
This was referenced Jul 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
With BLTPRI ("blitter nasty") set, BBUSY holds the BLS line asserted until BLTDONE, so the CPU is denied every chip-bus cycle for the duration of the blit -- including the pipeline's bus-free micro-cycles (the first empty D phase, fill's extra idle cycle, line-mode Bresenham cycles). The Copper and fixed DMA still use those cycles; only the CPU is fenced. Previously
scheduled_dma_owner_after_fixedreturned the bubble cycles asIdlebefore checking BLTPRI, letting the CPU steal them mid-blit.Regression example: Jim Power (guru 00000003 after level load)
The FLT trackloader MFM-decodes each sector with a blitter pass under BLTPRI (
BLTCON0=$FDFC,BLTSIZE=$4041). It saves the word below the blit destination, writes BLTSIZE, and restores the word two instructions later, relying on that CPU write being held until after the blit's first D write (D-pipeline warm-up garbage lands one word below the real output):Granting the CPU the first-D bubble inverted the order: the restore landed first, the blitter then overwrote it, corrupting the last data word ($1FE/$1FF) of every decoded sector. The level depacker consumed the corrupt stream, ended with an odd A5, and
MOVE.L (A5)+,(A6)+address-errored; the Alert re-entry (loc0='HELP') then dropped KS1.3 into the LED-flash deadend. With the fence the loaded data verifies byte-identical against the ADF and the game plays.Test/golden changes
bltpri_stalls_cpu_chip_access_through_blitter_access_cycles: CPU now waits through the whole blit (3 -> 6 cck).blithog_set_blocks_cpu_slowdown_back_pressure_until_blitter_finishes: wait includes the terminal E/F cycles (14 -> 16 cck).Also included
COPPERLINE_DIAG_SLOTMAP,COPPERLINE_DUMP_BUS_ACCOUNTING) are re-derived from the environment after a save-state load instead of inheriting the saved-off values.Verification
cargo test --releasegreen (1361 lib tests + golden suite),cargo clippyandcargo fmt --checkclean.