Skip to content

Commit

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

/// The address of the PPU's OAMDATA register in the CPU's address space.
static let OAMDATAAddress: Address = 0x2004

/// The address of the PPU's PPUSCROLL register in the CPU's address space.
static let PPUSCROLLAddress: Address = 0x2005
}

/// Maps CPU memory addresses to PPU registers.
Expand Down Expand Up @@ -131,6 +134,10 @@ private extension PPU {
defer { didWriteOAMDATA() }

OAMDATA = value
case Address.PPUSCROLLAddress:
defer { didWritePPUSCROLL() }

PPUSCROLL = value
default:
fatalError("Attempt to write illegal PPU register address \(format(address)).")
}
Expand Down
20 changes: 20 additions & 0 deletions NES/PPU.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ internal final class PPU {
}
}

/// The PPU scrolling position register.
var PPUSCROLL: UInt8 = 0

/// Holds the last value written to any of the above registers.
///
/// Setting this will also affect the five lowest bits of PPUSTATUS.
Expand All @@ -36,6 +39,10 @@ internal final class PPU {
}
}

var temporaryVRAMAddress: Address = 0

var horizontalScrollPosition: UInt8 = 0

/// Toggled by writing to PPUSCROLL or PPUADDR, cleared by reading
/// PPUSTATUS.
var secondWrite: Bool = false
Expand Down Expand Up @@ -74,4 +81,17 @@ internal final class PPU {
func didWriteOAMDATA() {
OAMADDR = OAMADDR &+ 1
}

/// Must be called after the CPU has written PPUSCROLL.
func didWritePPUSCROLL() {
if !secondWrite {
temporaryVRAMAddress = (temporaryVRAMAddress & 0xFFE0) | (UInt16(PPUSCROLL) >> 3)
horizontalScrollPosition = PPUSCROLL & 0x07
} else {
temporaryVRAMAddress = (temporaryVRAMAddress & 0x8FFF) | UInt16(PPUSCROLL & 0x07) << 12
temporaryVRAMAddress = (temporaryVRAMAddress & 0xFC1F) | UInt16(PPUSCROLL & 0xF8) << 2
}

secondWrite = !secondWrite
}
}
24 changes: 24 additions & 0 deletions Specs/PPUSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,5 +168,29 @@ class PPUSpec: QuickSpec {
expect(CPU.read(.OAMDATAAddress)).to(equal(0xFF))
}
}

describe("Having the CPU write to the PPUSCROLL register once") {
beforeEach {
CPU.write(.PPUSCROLLAddress, 0x7D)
}

it("should enabled the write latch") {
expect(PPU.secondWrite).to(beTrue())
}

describe("and again") {
beforeEach {
CPU.write(.PPUSCROLLAddress, 0x5E)
}

it("should update the horizontal scroll position") {
expect(PPU.horizontalScrollPosition).to(equal(0x05))
}

it("should update the temporary VRAM address") {
expect(PPU.temporaryVRAMAddress).to(equal(0x616F))
}
}
}
}
}

0 comments on commit 2aafe54

Please sign in to comment.