Loading...
Searching...
No Matches
hdma.h File Reference

SNES HDMA (Horizontal-blanking DMA) More...

#include <snes/types.h>

Go to the source code of this file.

Macros

#define HDMA_CHANNEL_0   0
 HDMA channel 0 (conflicts with common DMA usage)
 
#define HDMA_CHANNEL_1   1
 HDMA channel 1.
 
#define HDMA_CHANNEL_2   2
 HDMA channel 2.
 
#define HDMA_CHANNEL_3   3
 HDMA channel 3.
 
#define HDMA_CHANNEL_4   4
 HDMA channel 4.
 
#define HDMA_CHANNEL_5   5
 HDMA channel 5.
 
#define HDMA_CHANNEL_6   6
 HDMA channel 6 (recommended for HDMA)
 
#define HDMA_CHANNEL_7   7
 HDMA channel 7 (recommended for HDMA)
 
#define HDMA_DEST_BG1HOFS   0x0D
 Destination: BG1 H scroll ($210D)
 
#define HDMA_DEST_BG1VOFS   0x0E
 Destination: BG1 V scroll ($210E)
 
#define HDMA_DEST_BG2HOFS   0x0F
 Destination: BG2 H scroll ($210F)
 
#define HDMA_DEST_BG2VOFS   0x10
 Destination: BG2 V scroll ($2110)
 
#define HDMA_DEST_BG3HOFS   0x11
 Destination: BG3 H scroll ($2111)
 
#define HDMA_DEST_BG3VOFS   0x12
 Destination: BG3 V scroll ($2112)
 
#define HDMA_DEST_CGADD   0x21
 Destination: CGRAM address ($2121) - for palette effects.
 
#define HDMA_DEST_CGDATA   0x22
 Destination: CGRAM data ($2122) - for color effects.
 
#define HDMA_DEST_COLDATA   0x32
 Destination: Fixed color ($2132)
 
#define HDMA_DEST_INIDISP   0x00
 Destination: INIDISP brightness ($2100)
 
#define HDMA_DEST_M7A   0x1B
 Destination: Mode 7 matrix A ($211B)
 
#define HDMA_DEST_WH0   0x26
 Destination: Window 1 left ($2126)
 
#define HDMA_DEST_WH1   0x27
 Destination: Window 1 right ($2127)
 
#define HDMA_INDIRECT   0x40
 Indirect HDMA flag (OR with mode)
 
#define HDMA_MODE_1REG   0x00
 HDMA mode: 1 register, 1 byte.
 
#define HDMA_MODE_1REG_2X   0x02
 HDMA mode: 1 register, 2 bytes written twice.
 
#define HDMA_MODE_2REG   0x01
 HDMA mode: 2 registers, 2 bytes (low/high)
 
#define HDMA_MODE_2REG_2X   0x03
 HDMA mode: 2 registers, 4 bytes (2 to each)
 
#define HDMA_MODE_4REG   0x04
 HDMA mode: 4 registers, 4 bytes.
 

Functions

void hdmaBrightnessGradient (u8 channel, u8 topBrightness, u8 bottomBrightness)
 Create a vertical brightness gradient.
 
void hdmaBrightnessGradientStop (u8 channel)
 Stop brightness gradient and restore full brightness.
 
void hdmaColorGradient (u8 channel, u8 colorIndex, u16 topColor, u16 bottomColor)
 Create a per-scanline CGRAM color gradient.
 
void hdmaColorGradientStop (u8 channel)
 Stop color gradient effect.
 
void hdmaDisable (u8 channelMask)
 Disable HDMA channel(s)
 
void hdmaDisableAll (void)
 Disable all HDMA channels.
 
void hdmaEnable (u8 channelMask)
 Enable HDMA channel(s)
 
u8 hdmaGetEnabled (void)
 Get currently enabled HDMA channels.
 
void hdmaGradient (u8 channel, const void *colorTable)
 Set up a fixed color gradient effect.
 
void hdmaIrisWipe (u8 channel, u8 layers, u8 centerX, u8 centerY, u8 radius)
 Create a circular window mask (iris/spotlight effect)
 
void hdmaIrisWipeStop (u8 channel)
 Stop iris wipe effect and restore window registers.
 
void hdmaParallax (u8 channel, u8 bg, const void *scrollTable)
 Set up a background parallax scroll effect.
 
void hdmaSetTable (u8 channel, const void *table)
 Update HDMA table pointer (for dynamic effects)
 
void hdmaSetup (u8 channel, u8 mode, u8 destReg, const void *table)
 Set up an HDMA channel.
 
void hdmaSetupBank (u8 channel, u8 mode, u8 destReg, const void *table, u8 bank)
 Set up an HDMA channel with explicit source bank byte.
 
void hdmaWaterRipple (u8 channel, u8 bg, u8 amplitude, u8 speed)
 Create a water ripple distortion effect.
 
void hdmaWaveH (u8 channel, u8 bg, u8 amplitude, u8 frequency)
 Set up horizontal wave effect (water reflection)
 
void hdmaWaveInit (void)
 Initialize HDMA wave effect system.
 
void hdmaWaveSetSpeed (u8 speed)
 Set wave speed.
 
void hdmaWaveStop (void)
 Stop wave effect and disable HDMA channel.
 
void hdmaWaveUpdate (void)
 Update wave animation.
 
void hdmaWindowShape (u8 channel, const void *windowTable)
 Set up window position HDMA for shape effects.
 

Detailed Description

SNES HDMA (Horizontal-blanking DMA)

HDMA transfers data to PPU registers once per scanline during HBlank, enabling effects like color gradients, parallax scrolling, and wave distortion that change across the screen.

How HDMA Works

HDMA uses a table in memory that specifies:

  • How many scanlines to apply a value
  • The value(s) to write to the destination register

Each entry in the table is:

  • 1 byte: Line count (bit 7 = repeat mode, bits 0-6 = count)
  • N bytes: Data to write (1-4 bytes depending on transfer mode)

Table Format

Non-repeat mode (bit 7 = 0): Write data ONCE, then skip N-1 scanlines

.db 32 ; Write data once, hold for 32 scanlines
.db $1F, $00 ; Data (2 bytes for transfer mode 1)
.db 16 ; Write data once, hold for 16 scanlines
.db $1F, $08 ; Data
.db 0 ; End of table

Use for registers that hold their value (COLDATA, CGADD). Efficient: 1 data set per group, regardless of line count.

Repeat mode (bit 7 = 1): Write same data EVERY scanline for N lines

.db $82 ; Write data every scanline for 2 lines ($80 | 2)
.db $1F, $00 ; Data written on each of the 2 scanlines
.db $85 ; Write data every scanline for 5 lines
.db $1F, $08 ; Data
.db 0 ; End of table

REQUIRED for scroll registers (BG1HOFS, etc.) and other write-twice/ latched registers that need re-writing every scanline.

Usage Example

// Define HDMA table in ROM
const u8 gradient_table[] = {
32, 0x00, // 32 lines: color 0
32, 0x08, // 32 lines: color 8
32, 0x10, // 32 lines: color 16
0 // End
};
// Set up HDMA channel 6 to write to fixed color register
hdmaSetup(HDMA_CHANNEL_6, HDMA_MODE_1REG, 0x32, gradient_table);
// In main loop, HDMA runs automatically each frame
unsigned char u8
8-bit unsigned integer (0 to 255)
Definition types.h:46
void hdmaEnable(u8 channelMask)
Enable HDMA channel(s)
#define HDMA_MODE_1REG
HDMA mode: 1 register, 1 byte.
Definition hdma.h:134
void hdmaSetup(u8 channel, u8 mode, u8 destReg, const void *table)
Set up an HDMA channel.
#define HDMA_CHANNEL_6
HDMA channel 6 (recommended for HDMA)
Definition hdma.h:120
Warning
Do NOT use HDMA_CHANNEL_7 — the NMI handler uses DMA channel 7 for OAM transfers every frame, which destroys any HDMA setup on that channel. Safe HDMA channels: 1-6 (channel 0 is used by dmaCopyVram).
Note
HDMA tables must be in ROM or bank $7E RAM.

Bank Byte Limitation

hdmaSetup() hardcodes bank $00 for ROM addresses (>= $8000). If the linker places a SUPERFREE table in bank $01+, HDMA will read wrong data. Use hdmaSetupBank() with an explicit bank byte for ROM tables, or use RAM-based tables (always bank $00) for dynamic effects.

IMPORTANT: Scroll Registers Require Repeat Mode

BG scroll registers (BG1HOFS, BG1VOFS, etc.) are latched registers that require being written EVERY scanline to maintain their value. Use REPEAT mode (bit 7 = 1) in the HDMA line count for these registers.

Non-repeat mode (bit 7 = 0) writes data only ONCE per group, so the scroll value is lost on subsequent scanlines — causing visible glitches.

// WRONG - Non-repeat writes once then skips, scroll value lost:
.db 32, $20, $00 ; Writes on line 1 only, lines 2-32 get stale value
// CORRECT - Repeat writes every scanline, scroll value maintained:
.db $A0, $20, $00 ; $A0 = $80 | 32 = write every scanline for 32 lines

Summary:

  • COLDATA ($2132), CGADD/CGDATA: non-repeat OK (registers hold value)
  • BG scroll, window, Mode 7 matrix: MUST use repeat mode
Author
OpenSNES Team

Macro Definition Documentation

◆ HDMA_CHANNEL_0

#define HDMA_CHANNEL_0   0

HDMA channel 0 (conflicts with common DMA usage)

◆ HDMA_CHANNEL_1

#define HDMA_CHANNEL_1   1

HDMA channel 1.

◆ HDMA_CHANNEL_2

#define HDMA_CHANNEL_2   2

HDMA channel 2.

◆ HDMA_CHANNEL_3

#define HDMA_CHANNEL_3   3

HDMA channel 3.

◆ HDMA_CHANNEL_4

#define HDMA_CHANNEL_4   4

HDMA channel 4.

◆ HDMA_CHANNEL_5

#define HDMA_CHANNEL_5   5

HDMA channel 5.

◆ HDMA_CHANNEL_6

#define HDMA_CHANNEL_6   6

HDMA channel 6 (recommended for HDMA)

◆ HDMA_CHANNEL_7

#define HDMA_CHANNEL_7   7

HDMA channel 7 (recommended for HDMA)

◆ HDMA_DEST_BG1HOFS

#define HDMA_DEST_BG1HOFS   0x0D

Destination: BG1 H scroll ($210D)

◆ HDMA_DEST_BG1VOFS

#define HDMA_DEST_BG1VOFS   0x0E

Destination: BG1 V scroll ($210E)

◆ HDMA_DEST_BG2HOFS

#define HDMA_DEST_BG2HOFS   0x0F

Destination: BG2 H scroll ($210F)

◆ HDMA_DEST_BG2VOFS

#define HDMA_DEST_BG2VOFS   0x10

Destination: BG2 V scroll ($2110)

◆ HDMA_DEST_BG3HOFS

#define HDMA_DEST_BG3HOFS   0x11

Destination: BG3 H scroll ($2111)

◆ HDMA_DEST_BG3VOFS

#define HDMA_DEST_BG3VOFS   0x12

Destination: BG3 V scroll ($2112)

◆ HDMA_DEST_CGADD

#define HDMA_DEST_CGADD   0x21

Destination: CGRAM address ($2121) - for palette effects.

◆ HDMA_DEST_CGDATA

#define HDMA_DEST_CGDATA   0x22

Destination: CGRAM data ($2122) - for color effects.

◆ HDMA_DEST_COLDATA

#define HDMA_DEST_COLDATA   0x32

Destination: Fixed color ($2132)

◆ HDMA_DEST_INIDISP

#define HDMA_DEST_INIDISP   0x00

Destination: INIDISP brightness ($2100)

◆ HDMA_DEST_M7A

#define HDMA_DEST_M7A   0x1B

Destination: Mode 7 matrix A ($211B)

◆ HDMA_DEST_WH0

#define HDMA_DEST_WH0   0x26

Destination: Window 1 left ($2126)

◆ HDMA_DEST_WH1

#define HDMA_DEST_WH1   0x27

Destination: Window 1 right ($2127)

◆ HDMA_INDIRECT

#define HDMA_INDIRECT   0x40

Indirect HDMA flag (OR with mode)

When set, table contains pointers to data instead of data itself. Useful for large tables or dynamic data.

◆ HDMA_MODE_1REG

#define HDMA_MODE_1REG   0x00

HDMA mode: 1 register, 1 byte.

Writes 1 byte to destination register each scanline. Table entry: 1 byte line count + 1 byte data

◆ HDMA_MODE_1REG_2X

#define HDMA_MODE_1REG_2X   0x02

HDMA mode: 1 register, 2 bytes written twice.

Writes 2 bytes to same register (for double-write registers). Table entry: 1 byte line count + 2 bytes data

◆ HDMA_MODE_2REG

#define HDMA_MODE_2REG   0x01

HDMA mode: 2 registers, 2 bytes (low/high)

Writes 2 bytes to consecutive registers (e.g., scroll low/high). Table entry: 1 byte line count + 2 bytes data

◆ HDMA_MODE_2REG_2X

#define HDMA_MODE_2REG_2X   0x03

HDMA mode: 2 registers, 4 bytes (2 to each)

Writes 4 bytes: 2 to dest, 2 to dest+1. Table entry: 1 byte line count + 4 bytes data

◆ HDMA_MODE_4REG

#define HDMA_MODE_4REG   0x04

HDMA mode: 4 registers, 4 bytes.

Writes 4 bytes to 4 consecutive registers. Table entry: 1 byte line count + 4 bytes data

Function Documentation

◆ hdmaBrightnessGradient()

void hdmaBrightnessGradient ( u8  channel,
u8  topBrightness,
u8  bottomBrightness 
)

Create a vertical brightness gradient.

Smoothly fades screen brightness from top to bottom using HDMA on the INIDISP register ($2100). Useful for:

  • Fade-to-black at screen bottom
  • Spotlight / vignette effects
  • Underwater depth dimming
Parameters
channelHDMA channel (6 or 7 recommended)
topBrightnessBrightness at top of screen (0-15, 15=full)
bottomBrightnessBrightness at bottom of screen (0-15)
hdmaBrightnessGradient(HDMA_CHANNEL_7, 15, 0); // Fade to black
void hdmaBrightnessGradient(u8 channel, u8 topBrightness, u8 bottomBrightness)
Create a vertical brightness gradient.
#define HDMA_CHANNEL_7
HDMA channel 7 (recommended for HDMA)
Definition hdma.h:122

◆ hdmaBrightnessGradientStop()

void hdmaBrightnessGradientStop ( u8  channel)

Stop brightness gradient and restore full brightness.

Parameters
channelThe channel used for the gradient

◆ hdmaColorGradient()

void hdmaColorGradient ( u8  channel,
u8  colorIndex,
u16  topColor,
u16  bottomColor 
)

Create a per-scanline CGRAM color gradient.

Smoothly interpolates a palette color from one value to another across the screen. Uses HDMA to rewrite a CGRAM entry per scanline. Useful for:

  • Sky color gradients (blue to orange sunset)
  • Water depth color shifts
  • Background atmosphere effects
Parameters
channelHDMA channel (6 or 7 recommended)
colorIndexCGRAM color index to modify (0-255)
topColor15-bit SNES color at top of screen (use RGB() macro)
bottomColor15-bit SNES color at bottom of screen
// Blue sky fading to orange at horizon
RGB(4, 8, 28), // Deep blue
RGB(28, 16, 4)); // Orange
void hdmaColorGradient(u8 channel, u8 colorIndex, u16 topColor, u16 bottomColor)
Create a per-scanline CGRAM color gradient.
#define RGB(r, g, b)
Create RGB color value.
Definition video.h:76

◆ hdmaColorGradientStop()

void hdmaColorGradientStop ( u8  channel)

Stop color gradient effect.

Parameters
channelThe channel used for the gradient

◆ hdmaDisable()

void hdmaDisable ( u8  channelMask)

Disable HDMA channel(s)

Disables the specified HDMA channel(s).

Parameters
channelMaskBitmask of channels to disable

◆ hdmaDisableAll()

void hdmaDisableAll ( void  )

Disable all HDMA channels.

Convenience function to stop all HDMA activity.

◆ hdmaEnable()

void hdmaEnable ( u8  channelMask)

Enable HDMA channel(s)

Enables the specified HDMA channel(s). HDMA will start on the next frame.

Parameters
channelMaskBitmask of channels to enable (1 << channel)
hdmaEnable(1 << HDMA_CHANNEL_6); // Enable channel 6
hdmaEnable((1 << HDMA_CHANNEL_6) | (1 << HDMA_CHANNEL_7)); // Enable 6 and 7

◆ hdmaGetEnabled()

u8 hdmaGetEnabled ( void  )

Get currently enabled HDMA channels.

Returns
Bitmask of enabled channels

◆ hdmaGradient()

void hdmaGradient ( u8  channel,
const void *  colorTable 
)

Set up a fixed color gradient effect.

Creates a vertical color gradient by changing the fixed color register per scanline. Useful for sky gradients, underwater effects, etc.

Parameters
channelHDMA channel to use
colorTableHDMA table with COLDATA values
Note
Table format: line count + 1 byte (COLDATA value) per entry
COLDATA format: bits 7-5 = color select (RGB), bits 4-0 = intensity

◆ hdmaIrisWipe()

void hdmaIrisWipe ( u8  channel,
u8  layers,
u8  centerX,
u8  centerY,
u8  radius 
)

Create a circular window mask (iris/spotlight effect)

Uses HDMA to drive window registers (WH0/WH1) per scanline, approximating a circle. Configures all window registers automatically. Useful for:

  • Scene transitions (iris in/out)
  • Spotlight effects
  • Circular vignette
Parameters
channelHDMA channel (6 or 7 recommended)
layersLayer bitmask to apply window masking (TM_BG1, TM_BG2, etc.)
centerXHorizontal center of circle (0-255)
centerYVertical center of circle (0-223)
radiusCircle radius in pixels (0-128)
Note
Call again with a different radius to animate the wipe.
// Iris wipe on BG1, centered on screen
// Animate iris opening
for (r = 0; r < 128; r += 2) {
}
void WaitForVBlank(void)
Wait for next VBlank period.
#define TM_BG1
Definition registers.h:439
void hdmaIrisWipe(u8 channel, u8 layers, u8 centerX, u8 centerY, u8 radius)
Create a circular window mask (iris/spotlight effect)

◆ hdmaIrisWipeStop()

void hdmaIrisWipeStop ( u8  channel)

Stop iris wipe effect and restore window registers.

Disables the HDMA channel and clears all window masking registers (W12SEL, W34SEL, WOBJSEL, TMW) to restore normal display.

Parameters
channelThe channel used for the iris wipe

◆ hdmaParallax()

void hdmaParallax ( u8  channel,
u8  bg,
const void *  scrollTable 
)

Set up a background parallax scroll effect.

Creates horizontal parallax scrolling where each section of the screen scrolls at a different speed based on the scroll table.

Parameters
channelHDMA channel to use
bgBackground layer (0=BG1, 1=BG2, 2=BG3)
scrollTableHDMA table with scroll values
Note
Table format: line count + 2 bytes (scroll low/high) per entry

◆ hdmaSetTable()

void hdmaSetTable ( u8  channel,
const void *  table 
)

Update HDMA table pointer (for dynamic effects)

Changes the table pointer for an already-configured channel. Takes effect on the next frame.

Parameters
channelHDMA channel (0-7)
tableNew table pointer

◆ hdmaSetup()

void hdmaSetup ( u8  channel,
u8  mode,
u8  destReg,
const void *  table 
)

Set up an HDMA channel.

Configures an HDMA channel with the specified parameters. The channel is NOT enabled automatically - call hdmaEnable() to start it.

Parameters
channelHDMA channel (0-7, use HDMA_CHANNEL_6 or _7)
modeTransfer mode (HDMA_MODE_*)
destRegDestination B-bus register (low byte of $21xx address)
tablePointer to HDMA table in ROM or RAM
#define HDMA_DEST_COLDATA
Destination: Fixed color ($2132)
Definition hdma.h:211

◆ hdmaSetupBank()

void hdmaSetupBank ( u8  channel,
u8  mode,
u8  destReg,
const void *  table,
u8  bank 
)

Set up an HDMA channel with explicit source bank byte.

Same as hdmaSetup() but allows specifying the ROM bank for HDMA tables in banks other than $00. Use this when your HDMA table is in a SUPERFREE section that may be placed in bank $01+ by the linker.

Parameters
channelHDMA channel (0-7, use HDMA_CHANNEL_6 or _7)
modeTransfer mode (HDMA_MODE_*)
destRegDestination B-bus register (low byte of $21xx address)
tablePointer to HDMA table in ROM or RAM
bankSource bank byte ($00-$3F for LoROM)

◆ hdmaWaterRipple()

void hdmaWaterRipple ( u8  channel,
u8  bg,
u8  amplitude,
u8  speed 
)

Create a water ripple distortion effect.

Similar to hdmaWaveH but with amplitude that increases from top to bottom, simulating underwater refraction or heat haze. Uses the wave system's double-buffered tables internally.

Parameters
channelHDMA channel (6 or 7 recommended)
bgBackground layer (0=BG1, 1=BG2, 2=BG3)
amplitudeMaximum ripple amplitude at bottom of screen (1-60 pixels, clamped)
speedAnimation speed (1=slow, 4=fast)
Note
Amplitude is clamped to 60 to prevent s16 overflow in sine computation.
Cannot be used simultaneously with hdmaWaveH (shared buffers).
Call hdmaWaveUpdate() each frame to animate.
Call hdmaWaveStop() to stop the effect.
while (1) {
hdmaWaveUpdate(); // Animate ripple
}
void hdmaWaveUpdate(void)
Update wave animation.
void hdmaWaterRipple(u8 channel, u8 bg, u8 amplitude, u8 speed)
Create a water ripple distortion effect.

◆ hdmaWaveH()

void hdmaWaveH ( u8  channel,
u8  bg,
u8  amplitude,
u8  frequency 
)

Set up horizontal wave effect (water reflection)

Creates a wavy horizontal distortion, commonly used for:

  • Water reflections
  • Heat shimmer
  • Dream/flashback sequences
Parameters
channelHDMA channel to use (6 or 7 recommended)
bgBackground layer to affect (0=BG1, 1=BG2, 2=BG3)
amplitudeWave amplitude in pixels (1-60, clamped internally)
frequencyWave frequency (1-16, higher = tighter waves). Period = 256/frequency scanlines.
hdmaWaveH(HDMA_CHANNEL_6, 0, 4, 4); // Gentle water reflection on BG1
while (1) {
hdmaWaveUpdate(); // Animate the wave
}
void hdmaWaveInit(void)
Initialize HDMA wave effect system.
void hdmaWaveH(u8 channel, u8 bg, u8 amplitude, u8 frequency)
Set up horizontal wave effect (water reflection)

◆ hdmaWaveInit()

void hdmaWaveInit ( void  )

Initialize HDMA wave effect system.

Must be called once before using wave effects. Allocates internal buffers and sets up the wave state.

◆ hdmaWaveSetSpeed()

void hdmaWaveSetSpeed ( u8  speed)

Set wave speed.

Parameters
speedAnimation speed (1=slow, 4=fast, default=2)

◆ hdmaWaveStop()

void hdmaWaveStop ( void  )

Stop wave effect and disable HDMA channel.

Disables the wave effect and frees the HDMA channel.

◆ hdmaWaveUpdate()

void hdmaWaveUpdate ( void  )

Update wave animation.

Call this once per frame (after WaitForVBlank) to animate the wave effect. Updates the HDMA table with new wave values.

Note
Only needed if wave effects are active

◆ hdmaWindowShape()

void hdmaWindowShape ( u8  channel,
const void *  windowTable 
)

Set up window position HDMA for shape effects.

Uses HDMA to change window boundaries per scanline, creating shapes like circles, triangles, or custom masks.

Parameters
channelHDMA channel to use
windowTableHDMA table with left/right pairs
Note
Table format: line count + 2 bytes (left, right) per entry
Uses mode 2REG to write both WH0 and WH1