aboutsummaryrefslogtreecommitdiff
path: root/nes
diff options
context:
space:
mode:
Diffstat (limited to 'nes')
-rw-r--r--nes/bus.go4
-rw-r--r--nes/nes.go20
2 files changed, 23 insertions, 1 deletions
diff --git a/nes/bus.go b/nes/bus.go
index eeb96b0..af4f242 100644
--- a/nes/bus.go
+++ b/nes/bus.go
@@ -22,6 +22,8 @@ func (n *Console) Read(addr uint16) uint8 {
switch {
case addr < 0x2000: // internal RAM and mirrors
return n.RAM[addr&0x7FF]
+ case addr < 0x4000: // PPU registers, mirrored every 8 bytes
+ return n.PPU.ReadRegister(addr)
case addr >= 0x4020: // cartridge
return n.Cart.Mapper.CPURead(addr)
default:
@@ -33,6 +35,8 @@ func (n *Console) Write(addr uint16, v uint8) {
switch {
case addr < 0x2000:
n.RAM[addr&0x7FF] = v
+ case addr < 0x4000:
+ n.PPU.WriteRegister(addr, v)
case addr >= 0x4020:
n.Cart.Mapper.CPUWrite(addr, v)
}
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
}