DMG-CPU Research

PPU

locator_ppu

The description is divided into 2 parts (according to the modules), so as not to torment the browser with large pictures.

PPU SoC boundary (external signals)

Interface between the whole PPU (PPU1 + PPU2, treated as one block) and the rest of the die. A net is external when at least one non-PPU block touches it: ClkGen, SM83Core/Arbiter, MMIO, the OAM RAM macro, pads or a global rail. Nets that run exclusively between PPU1 and PPU2 are excluded from these tables (per-part port tables: PPU1 signals, PPU2 signals).

Directions are from the PPU side. Net names are the dmgcpu.v pin names. The wiring was cross-checked against HDL/soc/dmgcpu.v (all instances); the table rows are grouped by the SoC block on the other end.

Clocks and reset — from ClkGen

Signal Dir Width In PPU Connects to Function
cclk In 1 PPU2 ClkGen.cclk (also APU.cclk) Complement master clock — the PPU dot clock (ppu_clk = cclk, generated inside PPU2)
clk6 In 1 PPU2 ClkGen.clk6 (also SM83Core, MMIO, APU) Clock 6 (INC_CLK_P); in PPU2 only re-buffered as clk6_delay for MMIO
n_reset2 In 1 PPU2 ClkGen.n_reset2 (also Arb, MMIO, APU, Ser) Global reset, active low — source of n_ppu_hard_reset inside PPU2

Clock topology: ClkGen → PPU2 (cclk, clk6, n_reset2). PPU2 then synthesizes the clocks the other side uses: ppu_clk (= cclk) and ppu_rd/ppu_wr (re-driven soc_rd/soc_wr) are sent to PPU1 and MMIO; n_ppu_clk, h_restart, vclk2… stay PPU1↔PPU2 internal. PPU1 has no direct ClkGen contact — every clock/PPU strobe reaches it from PPU2 (ppu_clk, n_ppu_clk, ppu_rd, ppu_wr, n_ppu_hard_reset).

PPU-generated clocks, strobes, resets and interrupts — to MMIO / Arbiter

Signal Dir Width Owner Connects to Function
ppu_clk Out 1 PPU2 MMIO (also PPU1) PPU clock, = cclk (dot clock) — MMIO times its register accesses with it
clk6_delay Out 1 PPU2 MMIO Delayed clock 6, = clk6
n_ppu_hard_reset Out 1 PPU2 MMIO, Arbiter (also PPU1) PPU hard reset, = !n_reset2
ppu_rd / ppu_wr Out 1+1 PPU2 MMIO (also PPU1) PPU read/write strobes, = soc_rd/soc_wr — mark PPU-register accesses for MMIO
ff46 Out 1 PPU1 MMIO DMA register ($FF46) access indicator
ppu_int_stat Out 1 PPU1 MMIO STAT interrupt request (IF bit 1)
ppu_int_vbl Out 1 PPU1 MMIO VBLANK interrupt request (IF bit 0)

CPU bus and address decode — Core / Arbiter / MMIO

Signal Dir Width In PPU Connects to Function
a In 13 / 8 PPU1: a[12:0]; PPU2: a[7:0] die CPU address bus (SM83Core, MMIO, Arb, BootROM, HRAM, APU) Register / VRAM / OAM access address
d Bidir 8 PPU1 + PPU2 die data bus (SM83Core, MMIO, Arb, BootROM, HRAM, APU, Ser, WaveRAM) Register and OAM data, interrupt vector read-back
ffxx In 1 PPU1 Arbiter.ffxx (also MMIO, APU, HRAM) FFxx register-area indicator (from the CPU address decode)
arb_fexx_ffxx In 1 PPU1 Arbiter.arb_fexx_ffxx FExx (VRAM/OAM) vs FFxx (registers) arbitration select

VRAM interface — Arbiter, MA/MD pads (external LH5164 SRAM)

Signal Dir Width Owner Connects to Function
md Bidir 8 PPU1 + PPU2 Arbiter (buffers to the MD pads → external VRAM SRAM) VRAM data bus; VRAM→OAM DMA source
n_ma Out 13 PPU1 MA pads (pad_ma0..12 → external VRAM SRAM) External VRAM address, inverse-hold form of nma
ppu_mode3 Out 1 PPU1 Arbiter (also PPU2) Mode 3 (pixel transfer) — VRAM contention with CPU
sp_bp_cys Out 1 PPU1 Arbiter (also PPU2) Sprite buffer page cycle (VRAM slot)
tm_bp_cys Out 1 PPU1 Arbiter Tile-map buffer page cycle
n_sp_bp_mrd Out 1 PPU1 Arbiter Sprite buffer page memory read, active low
n_tm_bp_cys Out 1 PPU1 Arbiter Tile-map buffer page cycle, active low

The PPU-internal VRAM address bus nma[12:0] is PPU1↔PPU2 only (both halves drive it with inverting tristates) — the chip pins carry n_ma (PPU1 → MA pads), which is the inverse-hold version of the same address.

DMA and OAM-access control — MMIO / Arbiter

Signal Dir Width In PPU Connects to Function
n_dma_phi In 1 PPU1 + PPU2 MMIO DMA clock, inverted
vram_to_oam In 1 PPU1 + PPU2 MMIO (also Arb) VRAM→OAM DMA in progress
n_vram_to_oam Out 1 PPU2 Arbiter VRAM→OAM DMA, = !vram_to_oam
dma_a In 13 PPU2 MMIO (also APU: low 8) DMA address bus (VRAM source)
dma_run In 1 PPU2 MMIO DMA run (gates mode 2, the oa mux and the OAM write decode)
dma_addr_ext In 1 PPU2 MMIO (also Arb, APU) DMA from external memory — selects the oam_din write-data group
soc_rd / soc_wr In 1+1 PPU2 MMIO (also Arb, HRAM, APU) SoC read/write strobes — re-driven as ppu_rd/ppu_wr
oam_dma_wr In 1 PPU2 MMIO OAM DMA write strobe
cpu_vram_oam_rd In 1 PPU2 MMIO (also Arb) CPU VRAM/OAM read strobe (selects the returned OAM port byte)
oam_din In 8 PPU2 Arbiter OAM write data (DMA-from-external cases, CPU OAM writes via Arb)

OAM RAM macro — PPU2 only (chip-internal RAM block, HDL/soc/oam.v)

PPU2 is the sole master of the OAM RAM: the nets below run exclusively between PPU2 and OAM (no CPU/MMIO direct access).

Signal Dir Width Function
oa Out 7 OAM address bits 7:1 (bit 0 unused); four sources: CPU/DMA/scan/store
n_oam_rd Out 1 OAM read enable, active low (mode 2, mode 3, CPU reads)
n_oama_wr / n_oamb_wr Out 1+1 OAM port A/B write enables, active low
oam_bl_pch Out 1 OAM bitline precharge (also the attribute-latch enable window)
n_oama Bidir 8 OAM port A data bus, inverse hold (attribute byte)
n_oamb Bidir 8 OAM port B data bus, inverse hold (Y byte; CPU read-back port)

LCD driver — PPU1 to pads

Signal Dir Width Function
n_lcd_ld0, n_lcd_ld1 Out 1+1 Pixel data to the LCD panel (LD0/LD1 pads), active low
n_lcd_cp, n_lcd_cpg Out 1+1 Dot clock / clock-gate (CP, CPG pads)
n_lcd_cpl Out 1 Line clock (CPL pad)
n_lcd_st, n_lcd_s Out 1+1 Start / shift (ST, S pads)
n_lcd_fr Out 1 Frame (FR pad)

Global rails

Signal Dir Width Connects to Function
CONST0 Bidir 1 every large module + pads (APU, Arb, MMIO, …) Chip-wide constant-0 rail; each module has its own const cell driving it

Excluded — PPU1 ↔ PPU2 internal nets (reference)

Nets that never leave the PPU pair (also listed in the per-part tables):

Clock cadence checks (testbench)

Simulation

A regression testbench that runs the real PPU1/PPU2 netlists (with behavioral VRAM/OAM models) lives in HDL/soc/icarus/ppu — see its Readme and waves.md.