finished phase 2a
This commit is contained in:
@@ -52,14 +52,21 @@ REWEIGHTED ROADMAP: priority is now building the rest of the NES hardware so gam
|
||||
Phases in order:
|
||||
|
||||
1. NMI/IRQ servicing - DONE (see Done section). cpu_interrupts.nes verification deferred to the last milestone (needs APU frame-counter IRQ)
|
||||
2. PPU-1 rendering core (new src/ppu.rs): registers $2000-$2007 routed in bus (currently stubbed 0), VRAM (nametables, pattern tables, palettes), background rendering into 256x240 framebuffer of palette indices, $2002 status with vblank flag, mirroring from cart, vblank raises NMI. Acceptance: SMB title screen renders, verified headless by framebuffer dump. NEXT
|
||||
2. PPU-1 rendering core (new src/ppu.rs): registers $2000-$2007 routed in bus (currently stubbed 0), VRAM (nametables, pattern tables, palettes), background rendering into 256x240 framebuffer of palette indices, $2002 status with vblank flag, mirroring from cart, vblank raises NMI. Acceptance: SMB title screen renders, verified headless by framebuffer dump. NEXT. Confirmed decisions: full dot-accurate scanline model (sprites in PPU-2 need cycle timing, MMC3 needs scanline IRQ), scroll registers $2005/$2006 correct now (v/t/x/w loopy system), Cartridge passed as a parameter to read/write/tick (no Rc/RefCell). Build steps:
|
||||
|
||||
2a. DONE - palette.rs (64-color 2C02 SYSTEM_PALETTE in index order + index_to_rgb with & 0x3F mask) and render.rs (trait Renderer with present(framebuffer, width, height) + PpmRenderer + pure ppm_bytes for testability). 4 unit tests pass (known palette values, index masking, PPM header, per-pixel RGB routing). Note: 2C02 chosen over composite palettes - we render the raw PPU output. src/ppu.rs exists as an empty placeholder
|
||||
2b. Ppu struct + registers $2000-$2007 + VRAM routing ($0000-$1FFF = cart CHR via cart.read_chr/write_chr, $2000-$2FFF = nametables in vram[0x800] with cart.mirroring(), $3F00-$3FFF = palette[32] with $3F10-$3F1F mirror) + bus wiring ($2000-$3FFF reads/writes via disjoint-field borrows). Verify with a debug harness writing $2006/$2007 and reading back. NEXT
|
||||
2c. Frame timing + vblank + NMI: 341 dots/scanline, 262 scanlines/frame, 3 PPU dots per CPU cycle. tick(cycles) advances cycles*3 dots. Scanline 241 dot 0 sets vblank flag + nmi_pending. Frame loop bridges: take_nmi() -> cpu.set_nmi(). Verify $2002 flag toggles and NMI fires
|
||||
2d. Static background render at scroll 0: nametable -> attribute -> pattern -> palette into 256x240 framebuffer. May show messy SMB output before scroll lands - expected
|
||||
2e. Scroll registers v/t/x/w (loopy system) + the dot-by-dot background pipeline: shift registers (bg_pattern_lo/hi 16-bit, bg_attr 16-bit, tile_latch, attr_latch), 4 fetch stages per 8-dot group (nametable, attribute, pattern low, pattern high), coarse X increment every 8 dots with nametable flip, coarse Y/fine Y wrap at scanline end. The densest code in the project
|
||||
2f. Acceptance: SMB title screen renders recognizable, dumped to PPM
|
||||
3. PPU-2 sprites + scrolling + $4014 OAM DMA: makes SMB actually playable
|
||||
4. GUI (egui + winit, first external deps): display framebuffer, 60fps loop, keyboard -> controller ($4016/$4017). First "games running on screen" moment
|
||||
5. Mappers: 2 (UNROM), 7 (AOROM) simple; 4 (MMC3) complex - includes scanline IRQ counter required for SMB3 status bar. Verified by running the real backups
|
||||
6. APU audio: 5 channels, frame counter -> IRQ, mixing. Verified with SMB
|
||||
7. LAST: blargg full suite (screen output becomes observable) + illegal-opcode phase for the full 8991-line nestest pass
|
||||
|
||||
Design note for PPU: PPU needs &mut Cartridge (CHR via read_chr/write_chr, mirroring) and &mut Cpu (raise NMI). Plan a main-frame loop that owns bus + cpu and drives both, rather than PPU holding references (borrow-checker friction). Framebuffer = palette indices (1 byte/pixel), RGB conversion happens in the GUI.
|
||||
Design note for PPU: PPU takes &mut Cartridge as a parameter to read/write/tick (CHR via cart.read_chr/write_chr, mirroring via cart.mirroring). Frame loop owns bus + cpu + renderer and drives all three - loop bridges NMI via ppu.take_nmi() -> cpu.set_nmi(), so neither PPU nor bus holds a &mut Cpu. Framebuffer = palette indices (1 byte/pixel), RGB conversion happens in the Renderer (PPM now, GUI later).
|
||||
|
||||
Blargg/illegal background: ~76 illegal opcodes in the nestest log (23 undocumented NOPs, SLO/RLA/SRE/RRA, LAX/SAX, DCP/ISC, EB=SBC alias). Reference: nesdev wiki. Not needed for the backup library but wanted for the full log pass.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user