Master the fundamental concepts of emulation through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksThe Picture Processing Unit renders 256x240 frames from nametables, pattern tables, palettes, and sprites. CPU emulators stay blind without PPU timing; many ROM tests fail on scanline timing alone.
Key structures:
Rendering walks scanlines, fetches background tiles, evaluates sprite 0 hits, and outputs pixels through a palette lookup.
For example, writing \`0x80\` to \`PPUCTRL\` enables NMI at vblank, which games use to update tiles safely.
\`\`\` vblank -> NMI -> game updates OAM/nametable -> next frame \`\`\`
Nametable mirroring mode depends on the cartridge mapper wiring, not just PPU registers. Vertical versus horizontal mirroring changes which physical VRAM backs each name table address.
This exercise asks you to implement PPU register stubs and a framebuffer renderer. You will simulate vblank timing and draw background tiles so CPU test ROMs can progress past boot.
You will use the same mental model here when reading production interpreter source later in the track. Sketch one concrete input on paper, predict the outcome, then confirm with code. That discipline catches logic errors early and makes debugging far faster when you extend the implementation in follow-on tasks.
Model the NES PPU (picture processing unit) closely enough to render a frame:
Print regions of the 256×240 frame as NES colour numbers.
One command per line (; starts a comment):
cLoading…
Every table starts zeroed, except OAM, which is filled with $FF (off-screen).
$23C0 + (ty/4)·8 + tx/4 covers 32×32 px. Within it, the 16×16 quadrant (top-left, top-right, bottom-left, bottom-right) uses bits 0-1, 2-3, 4-5 and 6-7. attr prints attribute $ADDR = $VV.$3F00 + 4p + v. Sprite palettes live at $3F10, using bits 0-1 of ATTR. Every value-0 pixel shows the backdrop $3F00. $3F10/$3F14/$3F18/$3F1C mirror $3F00/$3F04/$3F08/$3F0C for both reads and writes.sprite overflow on line L (N sprites).sprite 0 hit at x=X y=Y or sprite 0 hit: none.cLoading…
$ADDR = $VV. Other addresses print peek $ADDR: unmapped in this model.tile: N (0-255) and 16 hex bytesnt: X (0-31) Y (0-29) TILE...attr: MX (0-15) MY (0-14) PALETTE (0-3)palette: ADDR ($3F00-$3F1F) COLOURS..., or palette: colours are 00-3F (the colours before the bad one are kept)sprite: N (0-63) Y TILE ATTR Xrender: X Y W H (at most 32x32, inside 256x240)unknown command XInput:
cLoading…
Output:
cLoading…
Hidden tests cover sprite flips, behind-background priority, sprite 0 hit, scrolling, the 8-sprites-per-line limit with overflow, palette mirroring, and every usage error.