From 0be10a289132f7ed9b42d5949db844227075e7ce Mon Sep 17 00:00:00 2001 From: crecher Date: Mon, 12 Oct 2026 16:30:32 +0200 Subject: ITS ALIVE (not rly no image yet) --- nes/nes.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'nes/nes.go') diff --git a/nes/nes.go b/nes/nes.go index 7f36b1a..e3845f6 100644 --- a/nes/nes.go +++ b/nes/nes.go @@ -3,26 +3,44 @@ package nes import ( "crecher.net/gones/v2/cart" "crecher.net/gones/v2/cpu" + "crecher.net/gones/v2/ppu" ) type Console struct { CPU *cpu.CPU + PPU *ppu.PPU Cart *cart.Cartridge RAM [0x800]uint8 - // PPU, APU, controllers once they exist + // APU, controllers once they exist cycles uint64 } func New(c *cart.Cartridge) *Console { n := &Console{Cart: c} + n.PPU = ppu.New(c.Mapper, c.Mirroring) n.CPU = cpu.NewCPU(n) n.CPU.Reset() return n } +// Step runs one CPU instruction and the PPU dots (3 per CPU cycle) that +// elapse alongside it, firing NMI on a PPUCTRL/vblank edge. PPU state seen +// by bus accesses mid-instruction still lags behind by up to one +// instruction's worth of dots, since the CPU isn't cycle-stepped yet (see +// README: "CPU stall hook and proper IRQ/NMI line (polled between +// instructions)") - timing-sensitive register logic (the $2002 race window, +// NMI edge detection) is implemented to the real dot granularity and is +// exercised directly in the ppu package's tests, but end-to-end precision +// against real games/test ROMs needs that CPU work to land too. func (n *Console) Step() int { cycles := n.CPU.Step() n.cycles += uint64(cycles) + for i := 0; i < cycles*3; i++ { + n.PPU.Tick() + if n.PPU.PollNMI() { + n.CPU.NMI() + } + } return cycles } -- cgit v1.2.3