Sprite runtime pipeline

DS game only γ¨γ‚“γŒγ‚Šγƒœγ‚¦γ‚·γ¨γŠγ—γ‚ƒγ‚Œγͺまほう぀かい The field guide documents the DS game's internals.

From an overlay's sprite-place call to OAM hardware. Shadow-OAM in BSS, VBlank DMA flush, sprite-slot manager.

Companion to 2D Art β€Ί Composition. This page traces a single sprite placement from the overlay code that requested it through the engine's bookkeeping into NDS hardware OAM.

Stage 1 β€” overlay places a sprite

A controller / body overlay calls the engine sprite API in ov137:

FUN_021850D4(
    slot,          // sprite-slot index (allocated earlier via FUN_02184990/FUN_021849AC)
    x, y,          // screen coords
    w, h,          // pixel dimensions
    type,          // 1=BG, 2=OBJ, 4=blend, …
    flags,         // priority, layer, blend mode
    data_ptr       // pointer into the content-cache (NCGR + NCLR bytes)
);

FUN_021850D4 calls func_0x02071E78 (arm9-side sprite emitter). 12 distinct ov137 functions call this entry point.

Stage 2 β€” engine bookkeeping (ov137 internal)

Engine API table:

FunctionRole
FUN_02184990(?, n_tiles)Allocate sprite slot.
FUN_021849AC(?, n_tiles, flag)Allocate sprite slot with flag.
FUN_02185508(size, align)malloc for sprite-related structs.
FUN_0218472C(slot, mask, val, flag)Attribute set.
FUN_021848A8(slot, mask, val)Attribute set.
FUN_02184814(slot, mask, val, flag)Attribute set variant.
FUN_02185154(slot, ?, ?, ?, ?)Sprite position update.
FUN_02185384(?, ?, ?, ?)Write attribute.
FUN_021852A8(?, ?, ?)Tile-data update.
FUN_02184D6C(?, ?, ?, ?, &local, ?)Sprite-list builder.

Stage 3 β€” write to shadow OAM

ov137 writes 8 bytes of OAM data per sprite to a shadow OAM buffer in main RAM (BSS). Sprite-slot address computed by the chain:

oam_slot_addr = *0x021907BC + i * 0x40 + field_offset

  *0x021907BC  β†’ base of sprite-slot array (28 writes observed)
   i * 0x40     β†’ 64 bytes per slot record
   field_offset β†’ 0x00..0x07 holds OAM attr0/attr1/attr2

Stage 4 β€” VBlank DMA flush

At VBlank, the engine DMAs the shadow buffer to hardware OAM. Two VBlank handlers cooperate:

HandlerAddressRole
arm90x0207001CSystem-side VBlank (audio, DMA timing)
ov1370x02185BF8Game-engine VBlank (DMAs shadow OAM/VRAM)

Transfer wrappers

Each wrapper takes (src, dst_off, byte_count) and dispatches to the DMA0 primitive FUN_02017D9C at 0x040000B0..0x040000BC (DMA0 source / dest / count / control).

WrapperDestinationHardware base
0x020769C0OAM main0x07000000 + dst_off
0x02076A00OAM sub0x07000400 + dst_off
0x02076A40OBJ VRAM main0x06400000 + dst_off
0x02076A7COBJ VRAM sub0x06600000 + dst_off

OAM manager pointers (BSS)

AddressRefsRole
0x020A749C42ARM9 OAM manager pointer
0x02190908β€”ov137 OAM manager pointer
0x021907BC28 writesov137 sprite-slot array pointer
0x021A55C0750Game state struct pointer (top-most BSS reference)

Dispatcher (ov137)

FUN_021708CC: command dispatcher with a 10-entry jump table at 0x021708E6. Each opcode handler sits at offset (table[op] + 0x021708E8). Called 98 times across overlays.

Pipeline summary

controller overlay (e.g. ov003)
       β”‚  loads asset via FUN_02009894 β†’ master cache table 0x020AA740
       β–Ό
body overlay (e.g. ov070) walks placement table at .rodata
       β”‚  for each entry: FUN_021850D4(slot, x, y, w, h, type, flags, data)
       β–Ό
ov137 sprite API
       β”‚  STR/STRH into shadow-OAM at *0x021907BC + i*0x40 + offset
       β–Ό
[VBlank fires]
       β”‚
       β–Ό
ov137 VBlank handler @ 0x02185BF8
       β”‚  calls 0x020769C0  (OAM main transfer wrapper)
       β”‚  β†’ FUN_02017D9C  (DMA0 primitive)
       β”‚    β†’ 0x040000B0..BC (DMA registers)
       β–Ό
NDS hardware OAM @ 0x07000000
       β”‚
       β–Ό
GPU rasterises sprites at scanline time

Source