diff --git a/Sources/CPU/CPU.swift b/Sources/CPU/CPU.swift index d74fba9..465e218 100644 --- a/Sources/CPU/CPU.swift +++ b/Sources/CPU/CPU.swift @@ -131,7 +131,6 @@ class CPU { status = [.interruptDisable, .break2] programCounter = self.memReadU16(0xFFFC) - print(programCounter) } //func loadAndRun(_ program: [UInt8]) { @@ -158,9 +157,7 @@ class CPU { let opcodes = OPCODES_MAP while true { if bus.pollNMI() != nil { - print(programCounter) interrupt(.NMI) - print(programCounter) } processOpcodes(onCycle: onCycle, opcodes: opcodes) { onComplete() @@ -197,7 +194,6 @@ class CPU { let programCounterState = programCounter guard let opcode = opcodes[code] else {fatalError("OpCode \(code) not recgonized!")} - // print(programCounter, opcode.mnemonic) switch code { /// LDA diff --git a/Sources/PPU/NesPPU.swift b/Sources/PPU/NesPPU.swift index 0c17616..f160e15 100644 --- a/Sources/PPU/NesPPU.swift +++ b/Sources/PPU/NesPPU.swift @@ -28,7 +28,6 @@ class NesPPU { func tick(_ cycles: UInt8) -> Bool { self.cycles += Int(cycles) if self.cycles >= 341 { - //print(self.cycles) self.cycles = self.cycles - 341 self.scanline += 1 @@ -37,7 +36,6 @@ class NesPPU { status.setSpriteZeroHit(false) if ctrl.generateVblankNMI() { nmiInterrupt = 1 - print("interrupt") } } @@ -116,7 +114,6 @@ class NesPPU { func writeToData(_ data: UInt8) { let addr = addr.get() - print("\(addr): \(data)") switch addr { case 0...0x1fff: print("Attempt to write to chr rom space \(addr)!") diff --git a/Sources/PPU/Registers/ControlRegister.swift b/Sources/PPU/Registers/ControlRegister.swift index 0010757..f4430fc 100644 --- a/Sources/PPU/Registers/ControlRegister.swift +++ b/Sources/PPU/Registers/ControlRegister.swift @@ -46,4 +46,28 @@ struct ControlRegister: OptionSet { 0x1000 } } + + func spritePatternAddr() -> Int { + if !self.contains(.SPRITE_PATTERN_ADDR) { + 0 + } else { + 0x1000 + } + } + + func spriteSize() -> Int { + if !self.contains(.SPRITE_SIZE) { + 8 + } else { + 16 + } + } + + func masterSlaveSelect() -> Int { + if !self.contains(.SPRITE_SIZE) { + 0 + } else { + 1 + } + } } diff --git a/Sources/Render/Render.swift b/Sources/Render/Render.swift index a7eaedd..fc7031e 100644 --- a/Sources/Render/Render.swift +++ b/Sources/Render/Render.swift @@ -4,11 +4,11 @@ class Render { for i in 0..<0x03c0 { // FIXME: For now, just use first nametable let tileAddr = UInt16(ppu.vram[i]) - //print(ppu.vram) let tileLoc = (col: i % 32, row: i / 32) let tile = ppu.chrRom[(bank + Int(tileAddr) * 16)...(bank + Int(tileAddr) * 16 + 15)] - let palette = getBgPallete(ppu, tileLoc: tileLoc) + let bgPalette = getBgPalette(ppu, tileLoc: tileLoc) + // MARK: Draw Background for y in 0...7 { var upper = tile[tile.startIndex + y] var lower = tile[tile.startIndex + y + 8] @@ -21,21 +21,71 @@ class Render { case 0: NESColor.SYSTEM_PALLETE[Int(ppu.paletteTable[0])] case 1: - NESColor.SYSTEM_PALLETE[Int(palette[1])] + NESColor.SYSTEM_PALLETE[Int(bgPalette[1])] case 2: - NESColor.SYSTEM_PALLETE[Int(palette[2])] + NESColor.SYSTEM_PALLETE[Int(bgPalette[2])] case 3: - NESColor.SYSTEM_PALLETE[Int(palette[3])] + NESColor.SYSTEM_PALLETE[Int(bgPalette[3])] default: fatalError("Invalid Pallete Color type") } frame.setPixel((tileLoc.col * 8 + x, tileLoc.row * 8 + y), rgb) } } + + // MARK: Draw Sprites + for i in stride(from: 0, to: ppu.oamData.count, by: 4) { + let tileIndex = UInt16(ppu.oamData[i + 1]) + let tileX = Int(ppu.oamData[i + 3]) + let tileY = Int(ppu.oamData[i]) + + let flipVert = ppu.oamData[i + 2] >> 7 & 1 == 1 + let flipHori = ppu.oamData[i + 2] >> 6 & 1 == 1 + + let paletteIndex = ppu.oamData[i + 2] & 0b11 + let spritePallete = getSpritePalette(ppu, paletteIndex: paletteIndex) + + let bank = ppu.ctrl.spritePatternAddr() + let tile = ppu.chrRom[(bank + Int(tileIndex) * 16)...(bank + Int(tileIndex) * 16 + 15)] + + for y in 0...7 { + var upper = tile[tile.startIndex + y] + var lower = tile[tile.startIndex + y + 8] + + for x in (0...7).reversed() { + let value = (1 & lower) << 1 | (1 & upper) + upper = upper >> 1 + lower = lower >> 1 + if (value == 0) { + continue // skip coloring this pixel, it's transparent + } + let rgb = switch value { + case 1: + NESColor.SYSTEM_PALLETE[Int(spritePallete[1])] + case 2: + NESColor.SYSTEM_PALLETE[Int(spritePallete[2])] + case 3: + NESColor.SYSTEM_PALLETE[Int(spritePallete[3])] + default: + fatalError("Invalid Pallete Color type") + } + switch (flipHori, flipVert) { + case (false, false): + frame.setPixel((tileX + x, tileY + y), rgb) + case (true, false): + frame.setPixel((tileX + 7 - x, tileY + y), rgb) + case (false, true): + frame.setPixel((tileX + x, tileY + 7 - y), rgb) + case (true, true): + frame.setPixel((tileX + 7 - x, tileY + 7 - y), rgb) + } + } + } + } } } - static func getBgPallete(_ ppu: NesPPU, tileLoc: (col: Int, row: Int)) -> [UInt8] { + static func getBgPalette(_ ppu: NesPPU, tileLoc: (col: Int, row: Int)) -> [UInt8] { let attrTableIndex = tileLoc.row / 4 * 8 + tileLoc.col / 4 let attrByte = ppu.vram[0x3c0 + attrTableIndex] // FIXME: still using hardcoded first nametable @@ -55,4 +105,14 @@ class Render { let palleteStartIndex = 1 + Int(palleteIndex) * 4 return [ppu.paletteTable[0], ppu.paletteTable[palleteStartIndex], ppu.paletteTable[palleteStartIndex + 1], ppu.paletteTable[palleteStartIndex + 2]] } + + static func getSpritePalette(_ ppu: NesPPU, paletteIndex: UInt8) -> [UInt8] { + let start = 0x11 + Int(paletteIndex * 4) + return [ + 0, + ppu.paletteTable[start], + ppu.paletteTable[start + 1], + ppu.paletteTable[start + 2] + ] + } }