Skip to content

Commit

Permalink
Add PPUDATA register
Browse files Browse the repository at this point in the history
  • Loading branch information
robb committed May 25, 2016
1 parent 46e28b2 commit 046325d
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 0 deletions.
11 changes: 11 additions & 0 deletions NES/CPU+IO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ internal extension Address {

/// The address of the PPU's PPUADDR register in the CPU's address space.
static let PPUADDRAddress: Address = 0x2006

/// The address of the PPU's PPUDATA register in the CPU's address space.
static let PPUDATAAddress: Address = 0x2007
}

/// Maps CPU memory addresses to PPU registers.
Expand All @@ -118,6 +121,10 @@ private extension PPU {
return PPUSTATUS
case Address.OAMDATAAddress:
return OAMDATA
case Address.PPUDATAAddress:
defer { didReadPPUDATA() }

return bufferedPPUDATA
default:
return register
}
Expand Down Expand Up @@ -145,6 +152,10 @@ private extension PPU {
defer { didWritePPUADDR() }

PPUADDR = value
case Address.PPUDATAAddress:
defer { didWritePPUDATA() }

PPUDATA = value
default:
fatalError("Attempt to write illegal PPU register address \(format(address)).")
}
Expand Down
38 changes: 38 additions & 0 deletions NES/PPU.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,34 @@ internal final class PPU {
/// The PPU address register.
var PPUADDR: UInt8 = 0

/// The PPU data port.
///
/// This property proxies the PPU's VRAM at the address held by VRAMAddress.
var PPUDATA: UInt8 {
get {
return read(VRAMAddress)
}
set {
write(VRAMAddress, newValue)
}
}

/// This value holds buffered reads from PPUDATA.
var VRAMBuffer: UInt8 = 0

/// The buffered PPU data port.
var bufferedPPUDATA: UInt8 {
var data = PPUDATA

if VRAMAddress < 0x3F00 {
swap(&data, &VRAMBuffer)
} else {
VRAMBuffer = read(VRAMAddress &- 0x1000)
}

return data
}

/// Holds the last value written to any of the above registers.
///
/// Setting this will also affect the five lowest bits of PPUSTATUS.
Expand Down Expand Up @@ -111,4 +139,14 @@ internal final class PPU {

secondWrite = !secondWrite
}

/// Must be called after the CPU has read PPUDATA.
func didReadPPUDATA() {
VRAMAddress += VRAMAddressIncrement
}

/// Must be called after the CPU has written PPUDATA.
func didWritePPUDATA() {
VRAMAddress += VRAMAddressIncrement
}
}
75 changes: 75 additions & 0 deletions Specs/PPUSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -206,5 +206,80 @@ class PPUSpec: QuickSpec {
expect(PPU.VRAMAddress).to(equal(0x3DF0))
}
}

describe("Having the CPU read PPUDATA") {
beforeEach {
PPU.VRAMAddress = 0x0000
PPU.VRAMBuffer = 0xFF

PPU.write(PPU.VRAMAddress, 0x12)
}

it("should return the buffered value first") {
expect(CPU.read(.PPUDATAAddress)).to(equal(0xFF))
}

it("should update the buffer") {
CPU.read(.PPUDATAAddress)

expect(PPU.VRAMBuffer).to(equal(0x12))
}

it("should return the value at the current VRAM address on the second read") {
CPU.read(.PPUDATAAddress)

expect(CPU.read(.PPUDATAAddress)).to(equal(0x12))
}

describe("if the VRAM increment flag is not set") {
beforeEach {
PPU.PPUCTRL[2] = false
}

it("should increment the VRAM address by 1") {
CPU.read(.PPUDATAAddress)

expect(PPU.VRAMAddress).to(equal(0x0001))
}
}

describe("if the VRAM increment flag is set") {
beforeEach {
PPU.PPUCTRL[2] = true
}

it("should increment the VRAM address by 32") {
CPU.read(.PPUDATAAddress)

expect(PPU.VRAMAddress).to(equal(0x0020))
}
}
}

describe("Having the CPU write to PPUDATA") {
describe("if the VRAM increment flag is not set") {
beforeEach {
PPU.PPUCTRL[2] = false
}

it("should increment the VRAM address by 1") {
CPU.write(.PPUDATAAddress, 0x12)

expect(PPU.VRAMAddress).to(equal(0x0001))
}
}

describe("if the VRAM increment flag is set") {
beforeEach {
PPU.PPUCTRL[2] = true
}

it("should increment the VRAM address by 32") {
CPU.write(.PPUDATAAddress, 0x12)

expect(PPU.VRAMAddress).to(equal(0x0020))
}
}
}
}
}

0 comments on commit 046325d

Please sign in to comment.