OpenSNES
Modern Open-Source SNES Development SDK
Loading...
Searching...
No Matches
main.c File Reference

Raw HDMA table in C — per-scanline wave, krom-style. More...

#include <snes.h>
#include <snes/hdma.h>

Macros

#define ENTRY_BYTES   3
 Bytes per HDMA entry in 1REG_2X mode: count + 16-bit value.
#define VRAM_BG1_GFX   0x0000
 VRAM word address of BG1 tile graphics (image start).
#define VRAM_BG1_GFX2   0x4000
 VRAM word address of the second tile half (bytes 32768+).
#define VRAM_BG1_MAP   0x7C00
 VRAM word address of BG1 tilemap — above the 57 KB of tiles, krom's layout (his BG1SC put the map at VRAM byte $F800).
#define WAVE_WRAP   672
 Wrap length of the start-pointer animation, in table entries. krom's exact value: his sine's quasi-period is ~25.8 lines (non- integer), so his seamless wrap needs 672 entries; the table holds 224 more so any start phase has a full screen of valid lines.

Functions

int main (void)
 Entry point — raw HDMA wave demo.

Variables

u8 palette []
u8 palette_end []
u8 tilemap []
u8 tilemap_end []
u8 tiles []
 Mode 3 image data (from data.asm; generated original art).
u8 tiles2 []
u8 tiles2_end []
u8 tiles_end []
static u16 wave_phase
 Current wave phase in table entries (start of the table).
u8 wavetable []
 krom's exact HDMA table, in ROM (data.asm, bank 2).

Detailed Description

Raw HDMA table in C — per-scanline wave, krom-style.

Builds an HDMA table BY HAND in C and animates it the way the original assembler demo does: the table is written once, and each VBlank the table START POINTER advances one entry — the ripple pattern flows up the screen (line L reads entry phase+L, so each crest sits at X0-phase) without a single byte of the table being rewritten. This is the classic per-scanline effect that plain DMA cannot do: one BG1 horizontal scroll value per line, traced along a sine.

The companion example hdma_wave shows the same visual through the library's high-level engine (hdmaWaveH / hdmaWaveUpdate, double-buffered RAM tables). THIS example is the low-level counterpart: it teaches the HDMA table FORMAT itself — [line-count, value...] entries, terminator, and the repoint-per-frame animation idiom.

C port of "SNES Wave HDMA Demo" by krom (Peter Lemon), github.com/PeterLemon/SNES, PPU/HDMA/WaveHDMA — technique reproduced on the snes/hdma.h API in the original demo configuration (BG Mode 3, full-screen 256-color image). Art is original: procedurally generated water caustics (res/water.bmp), no krom assets.

SNES Concepts
  • HDMA table format: count byte (1 = apply to one scanline) followed by the register payload (2 bytes for a write-twice register), then a 0x00 terminator byte
  • HDMA_MODE_1REG_2X: one register written twice per line — exactly what the 16-bit scroll registers ($210D BG1HOFS low/high) expect
  • Animation by START-POINTER repoint (hdmaSetup once per frame with table + phase*3): the table itself is immutable, so HDMA never observes a partially rewritten entry — no tearing, ~zero CPU cost
  • BG Mode 3 (8bpp, 256 colors) with a full-screen image — the same configuration as the original demo (~57 KB of unique tiles, split across two ROM banks; the tilemap sits above them at VRAM $7C00, mirroring krom's layout)
What to Observe
  • A water image distorted into tight sine ripples flowing UPWARD at one scanline per frame — krom's exact TABLE (896 entries extracted verbatim) and exact cadence (wrap at 672), so the displacement field is byte-identical to the original demo's
  • White horizontal ruler lines every 64px stay perfectly straight (HOFS only shifts lines horizontally) while the verticals undulate
  • No flicker or black lines: the table always covers 224 lines from any start phase
Modules Used
console, dma, background, hdma
See also
hdma.h, examples/hdma/hdma_wave (high-level engine)

Macro Definition Documentation

◆ ENTRY_BYTES

#define ENTRY_BYTES   3

Bytes per HDMA entry in 1REG_2X mode: count + 16-bit value.

◆ VRAM_BG1_GFX

#define VRAM_BG1_GFX   0x0000

VRAM word address of BG1 tile graphics (image start).

◆ VRAM_BG1_GFX2

#define VRAM_BG1_GFX2   0x4000

VRAM word address of the second tile half (bytes 32768+).

◆ VRAM_BG1_MAP

#define VRAM_BG1_MAP   0x7C00

VRAM word address of BG1 tilemap — above the 57 KB of tiles, krom's layout (his BG1SC put the map at VRAM byte $F800).

◆ WAVE_WRAP

#define WAVE_WRAP   672

Wrap length of the start-pointer animation, in table entries. krom's exact value: his sine's quasi-period is ~25.8 lines (non- integer), so his seamless wrap needs 672 entries; the table holds 224 more so any start phase has a full screen of valid lines.

Function Documentation

◆ main()

int main ( void )

Entry point — raw HDMA wave demo.

Init order per the SDK convention: console, mode, palette, tiles, tilemap, BG pointers, HDMA setup, screen on. The main loop is the krom idiom: one hdmaSetup() repoint per VBlank, nothing else.

Returns
Never returns (infinite loop)

Variable Documentation

◆ palette

u8 palette[]
extern

◆ palette_end

u8 palette_end[]

◆ tilemap

u8 tilemap[]
extern

◆ tilemap_end

u8 tilemap_end[]

◆ tiles

u8 tiles[]
extern

Mode 3 image data (from data.asm; generated original art).

◆ tiles2

u8 tiles2[]
extern

◆ tiles2_end

u8 tiles2_end[]

◆ tiles_end

u8 tiles_end[]

◆ wave_phase

u16 wave_phase
static

Current wave phase in table entries (start of the table).

◆ wavetable

u8 wavetable[]
extern

krom's exact HDMA table, in ROM (data.asm, bank 2).

896 entries of [1][offset16] + terminator, extracted verbatim from the original demo: entry values are round(10*sin) samples with a quasi-period of ~25.8 lines. The table lives in ROM exactly like krom's (his in bank 0, ours in bank 2 — hdmaSetup reads the bank from the far pointer), and is never written: the animation only moves the start pointer.