Sprites showcase — a bouncing swarm, and the OAM throughput ceiling.
The finale of the sprites family, and an honest one. The SNES has 128 hardware sprites and one OAM DMA per frame to move them — but computing and writing 128 positions in C every frame does not fit a 60 fps budget on the base CPU. The OAM buffer lives in bank $7E (every write is a slow long address) and cc65816 spills registers in a busy loop, so the smooth ceiling for per-sprite C motion is around three dozen sprites.
So this swarm runs a comfortable 32 dots at a rock-steady 60 fps, each bouncing independently — and that number is the lesson:
moving sprites is cheap in principle (one OAM DMA), but touching each one from C is not free. For all 128 you either move the work off the main CPU — chips/sa1_starfield runs 128 birds of Lissajous trig on the SA-1 at 10.74 MHz — or hand-write the update loop in assembly.
Motion is deliberately cheap (integer add + edge bounce, no multiply or trig) so the cost you see is the OAM update itself, not the maths. Positions go straight into oamMemory[]; one oam_update_flag lets the NMI's DMA push them all. Four palettes tint the cloud. Zero assets.
ROM mode: LoROM (project default).
- SNES Concepts
- 128 hardware sprites; OAM is a RAM buffer (oamMemory[]) DMA'd to the PPU once per frame — set oam_update_flag, the NMI does the transfer
- Direct oamMemory[] writes: the fastest per-sprite update, two bytes (X, Y) when tile/palette/attributes were set once at init
- The per-sprite update budget: ~32 sprites of C motion fit 60 fps; the ceiling is OAM writes (bank $7E long addressing) + loop overhead, not the sprite hardware. sa1_starfield shows the coprocessor way past it
- What to Observe
- 32 colourful dots bounce around at a steady 60 fps. swarm_frame (probe oracle) advances every frame.
- Modules Used
- console, dma, background, sprite
- See also
- lib/include/snes/sprite.h — oamSetFast, oamMemory, oam_update_flag
-
examples/chips/sa1_starfield — 128 sprites of trig, offloaded to the SA-1