HDMA
The Super NES's horizontal-blank DMA, which writes a table of values to a video register line by line with no CPU time, for effects such as gradients and ripples.
On this page
HDMA turns a raster effect into data. Each of the 8 DMA channels can run during horizontal blank, writing values from a table to a register, and each table entry either writes once and waits or writes a new value on every line for a count1. An indirect table holds pointers to the values instead of the values1.
- Color gradientSuper Metroid (1994). Ceres station's haze steps a color down the screen in 8-line bands.2
- Scroll waveSuper Metroid (1994). BG2 below the waterline ripples a pixel either way in an 8-line pattern that moves every 6 frames.3
#Super Metroid
- Ripples. In rooms whose water is set to wave, BG2’s scroll goes through an indirect table with one entry per line. Lines below the water walk a ring of 16 scroll values with a displacement of 0, 1, 1, 0, 0, −1, −1, 0 pixels3, so the background shifts a pixel either way; the pattern moves one line every 6 frames3.
- Haze. Ceres station’s haze writes the color used for color math: a 64-line band, then 15 bands of 8 lines whose intensities rise down the screen, filled in over 16 frames as the room fades in2.
Games
| Game | Year | How | Note |
|---|---|---|---|
| Super Metroid | 1994 | Color gradient | Ceres station's haze steps a color down the screen in 8-line bands |
| Super Metroid | 1994 | Scroll wave | BG2 below the waterline ripples a pixel either way in an 8-line pattern that moves every 6 frames |
Every claim about this mechanic, by game (3)
References
- ^ abThe SNES has 8 DMA channels, each of which can run as HDMA, writing values from a table to a PPU register at set scanlines. Each table entry starts with a byte that either writes once and waits that many lines (
$01-$80) or writes a new value on each of the next lines ($81-$FF);$00ends the table. An indirect table holds pointers to the data instead of the data.WikiSNESdev Wiki, “DMA registers”How we know
The SNES also features HDMA (Horizontal-blank DMA) which runs in the background and can be set up to automatically write values to hardware registers at specific scanlines, allowing for effects.
lead · archived copy ↗ The SNES contains 8 separate DMA "channels"
DMA channels · archived copy ↗ $00: Stop processing HDMA on that channel for the rest of the frame. $01-$80: Write once, then wait for X scanlines $81-$FF: Write every scanline for X-$80 scanlines, repeat mode
Line count, repeat mode byte · archived copy ↗ The tables can either directly contain the values (Direct mode) or specify 16-bit pointers that are then used to get the values (Indirect mode).
HDMA table format · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abThe Ceres haze is an indirect HDMA table on the sub-screen backdrop color, used for color math. Its first entry covers 64 lines and 15 more cover 8 lines each; while the room fades in, the routine raises the bands' intensities over 16 frames, ending with 0 at the top and 1 to 15 in the bands below, a gradient down the screen.CodeInsaneFirebat/sm_disassembly
How we know
10016 JSL.L Spawn_HDMAObject ;88DDD0; 10017 db $40,$32 ;88DDD4; 10018 dw InstList_CeresHaze_ColorMathSubScnBackColor_RidleyAlive_0 ;88DDD6;
src/bank_88.asm lines 10011–10018 at 7af131e · upstream ↗ 990;; $32: Colour math subscreen backdrop colour (8-bit, sometimes used with write-twice)src/bank_88.asm lines 979–990 at 7af131e · upstream ↗ 10098PreInstruction_CeresHaze_ColorMathSubScnBackColor_FadingIn: ⋮ 10109 LDA.W HDMAObject_Var0,X ;88DE3F; 10110 CMP.W #$0010 ;88DE42; 10111 BEQ .done ;88DE45; ⋮ 10115 LDA.W HDMAObject_Var1,X ;88DE4B; 10116 STA.B DP_Temp14 ;88DE4E; 10117 LDA.W HDMAObject_Var0,X ;88DE50; 10118 LDX.B #$0F ;88DE53; ⋮ 10120 .loop: 10121 STA.B DP_Temp12 ;88DE55; 10122 ORA.B DP_Temp14 ;88DE57; 10123 STA.L HazeColorMathSubscreenBackdropColorHDMADataTable,X ;88DE59; ⋮
src/bank_88.asm lines 10097–10134 at 7af131e · upstream ↗ 10247IndirectHDMATable_CeresHaze_ColorMathSubScnBackdropColor: 10248 db $40 : dw HazeColorMathSubscreenBackdropColorHDMADataTable ;88DF03; 10249 db $08 : dw HazeColorMathSubscreenBackdropColorHDMADataTable+1 ⋮ 10263 db $08 : dw HazeColorMathSubscreenBackdropColorHDMADataTable+$F 10264 db $00
src/bank_88.asm lines 10246–10264 at 7af131e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^ abcIn rooms whose water is set to wave, an indirect HDMA channel writes BG2's X scroll on every line. Above the water each line points at the plain scroll; below it the lines walk through a ring of 16 values, the scroll plus a displacement of 0, 1, 1, 0, 0, −1, −1, 0 repeating, so the background ripples a pixel either way in an 8-line pattern that shifts one line every 6 frames.CodeInsaneFirebat/sm_disassembly
How we know
LDA.W FX_LiquidOptions … AND.W #$0002 … BEQ .notWavy … JSL.L Spawn_HDMAObject … db $42,$0F … dw InstList_Water_BG2_Xscroll
src/bank_88.asm#L7229-L7234 · upstream ↗ 982;; $0F: BG2 X scroll (16-bit, write-twice)src/bank_88.asm lines 980–982 at 7af131e · upstream ↗ 7303;;; $C46E: Wave displacement table - water ;;; 7304WaveDisplacementTable_Water:
src/bank_88.asm lines 7303–7306 at 7af131e · upstream ↗ 7524Setup_Water_BG2_Xscroll_DataTable_Wavy: ⋮ 7554 .loop:
src/bank_88.asm lines 7523–7570 at 7af131e · upstream ↗ 7468; the calculation 1FFh - [A] at $C5CE is equivalent to FFh + (Y position of screen on FX)src/bank_88.asm lines 7465–7472 at 7af131e · upstream ↗ 8365;;; $CF46: Indirect HDMA table - water BG2 X scroll ;;; 8366IndirectHDMATable_WaterBG2XScroll: ⋮ 8368 db $81 : dw WaterBG2XScrollHDMADataTable-4
src/bank_88.asm lines 8365–8368 at 7af131e · upstream ↗ 8623 db $81 : dw WaterBG2XScrollHDMADataTable ⋮ 8638 db $81 : dw WaterBG2XScrollHDMADataTable+$1E
src/bank_88.asm lines 8623–8638 at 7af131e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
Sources
Code
- InsaneFirebat and P.JBoy. 2026. “sm_disassembly: a relocatable disassembly of Super Metroid.” Commit 7af131e. InsaneFirebat/sm_disassembly @ 7af131e · licence, all uses
Secondary
- SNESdev Wiki contributors. n.d. “DMA registers.” SNESdev Wiki. Version oldid 1503. original · archived · licence, all uses