mirror of
https://github.com/Candygoblen123/SwiftNES.git
synced 2024-11-22 09:46:24 -06:00
Compare commits
No commits in common. "f9efe23b0b723ebcb25c9aee4b31c13427b4705b" and "bd12a6133004f81d6c5eed83f4ac7c9d0dd486db" have entirely different histories.
f9efe23b0b
...
bd12a61330
@ -131,7 +131,6 @@ class CPU {
|
|||||||
status = [.interruptDisable, .break2]
|
status = [.interruptDisable, .break2]
|
||||||
|
|
||||||
programCounter = self.memReadU16(0xFFFC)
|
programCounter = self.memReadU16(0xFFFC)
|
||||||
print(programCounter)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//func loadAndRun(_ program: [UInt8]) {
|
//func loadAndRun(_ program: [UInt8]) {
|
||||||
@ -151,16 +150,14 @@ class CPU {
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
func run() {
|
func run() {
|
||||||
run(onCycle: { print(dumpCpuState(self)) }, onComplete: {})
|
run(onCycle: {}, onComplete: {})
|
||||||
}
|
}
|
||||||
|
|
||||||
func run(onCycle: @escaping () -> (), onComplete: @escaping () -> ()) {
|
func run(onCycle: @escaping () -> (), onComplete: @escaping () -> ()) {
|
||||||
let opcodes = OPCODES_MAP
|
let opcodes = OPCODES_MAP
|
||||||
while true {
|
while true {
|
||||||
if bus.pollNMI() != nil {
|
if let _nmi = bus.pollNMI() {
|
||||||
print(programCounter)
|
|
||||||
interrupt(.NMI)
|
interrupt(.NMI)
|
||||||
print(programCounter)
|
|
||||||
}
|
}
|
||||||
processOpcodes(onCycle: onCycle, opcodes: opcodes) {
|
processOpcodes(onCycle: onCycle, opcodes: opcodes) {
|
||||||
onComplete()
|
onComplete()
|
||||||
|
@ -9,7 +9,7 @@ func dumpCpuState(_ cpu: CPU) -> String {
|
|||||||
{
|
{
|
||||||
let (addr, _) = cpu.getAbsoluteAddress(opcode.mode, addr: cpu.programCounter + 1)
|
let (addr, _) = cpu.getAbsoluteAddress(opcode.mode, addr: cpu.programCounter + 1)
|
||||||
|
|
||||||
return (addr, 0)//cpu.memRead(addr))
|
return (addr, cpu.memRead(addr))
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ class Bus {
|
|||||||
var prgRom: [UInt8]
|
var prgRom: [UInt8]
|
||||||
var ppu: NesPPU
|
var ppu: NesPPU
|
||||||
var cycles: Int = 0
|
var cycles: Int = 0
|
||||||
var gameloopCallback: (NesPPU) -> ()
|
|
||||||
|
|
||||||
fileprivate let RAM : UInt16 = 0x0000
|
fileprivate let RAM : UInt16 = 0x0000
|
||||||
fileprivate let RAM_MIRRORS_END: UInt16 = 0x1FFF
|
fileprivate let RAM_MIRRORS_END: UInt16 = 0x1FFF
|
||||||
@ -12,27 +11,18 @@ class Bus {
|
|||||||
fileprivate let ROM_ADDRESS_START: UInt16 = 0x8000
|
fileprivate let ROM_ADDRESS_START: UInt16 = 0x8000
|
||||||
fileprivate let ROM_ADDRESS_END: UInt16 = 0xFFFF
|
fileprivate let ROM_ADDRESS_END: UInt16 = 0xFFFF
|
||||||
|
|
||||||
init(_ rom: Rom, gameloopCallback: @escaping (NesPPU) -> ()) {
|
init(_ rom: Rom) {
|
||||||
ppu = NesPPU(rom.character, rom.screenMirror)
|
ppu = NesPPU(rom.character, rom.screenMirror)
|
||||||
self.prgRom = rom.program
|
self.prgRom = rom.program
|
||||||
self.gameloopCallback = gameloopCallback
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func tick(_ cycles: UInt8) {
|
func tick(_ cycles: UInt8) {
|
||||||
self.cycles += Int(cycles)
|
self.cycles += Int(cycles)
|
||||||
let nmiBefore = ppu.nmiInterrupt != nil
|
|
||||||
//print(nmiBefore)
|
|
||||||
self.ppu.tick(cycles * 3)
|
self.ppu.tick(cycles * 3)
|
||||||
let nmiAfter = ppu.nmiInterrupt != nil
|
|
||||||
//print(nmiAfter)
|
|
||||||
if !nmiBefore && nmiAfter {
|
|
||||||
gameloopCallback(ppu)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func pollNMI() -> UInt8? {
|
func pollNMI() -> UInt8? {
|
||||||
ppu.pollNMI()
|
ppu.nmiInterrupt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,20 +34,13 @@ extension Bus: Memory {
|
|||||||
let mirrorDownAddr = addr & 0b00000111_11111111
|
let mirrorDownAddr = addr & 0b00000111_11111111
|
||||||
return self.cpuVram[Int(mirrorDownAddr)]
|
return self.cpuVram[Int(mirrorDownAddr)]
|
||||||
case 0x2000, 0x2001, 0x2003, 0x2005, 0x2006, 0x4014:
|
case 0x2000, 0x2001, 0x2003, 0x2005, 0x2006, 0x4014:
|
||||||
//fatalError("Attempt to read from write-only PPU address \(addr)")
|
fatalError("Attempt to read from write-only PPU address \(addr)")
|
||||||
return 0
|
|
||||||
case 0x2002:
|
case 0x2002:
|
||||||
return ppu.readStatus()
|
return ppu.readStatus()
|
||||||
case 0x2004:
|
case 0x2004:
|
||||||
return ppu.readOamData()
|
return ppu.readOamData()
|
||||||
case 0x2007:
|
case 0x2007:
|
||||||
return ppu.readData()
|
return ppu.readData()
|
||||||
case 0x4000...0x4015:
|
|
||||||
return 0 // Ignore APU
|
|
||||||
case 0x4016:
|
|
||||||
return 0 // Ignore Joy 1
|
|
||||||
case 0x4017:
|
|
||||||
return 0 // Ignore Joy 2
|
|
||||||
case 0x2008...PPU_REGISTERS_MIRRORS_END:
|
case 0x2008...PPU_REGISTERS_MIRRORS_END:
|
||||||
let mirrorDownAddr = addr & 0b00100000_00000111;
|
let mirrorDownAddr = addr & 0b00100000_00000111;
|
||||||
return self.memRead(mirrorDownAddr)
|
return self.memRead(mirrorDownAddr)
|
||||||
@ -93,20 +76,6 @@ extension Bus: Memory {
|
|||||||
case 0x2008...PPU_REGISTERS_MIRRORS_END:
|
case 0x2008...PPU_REGISTERS_MIRRORS_END:
|
||||||
let mirrorDownAddr = addr & 0b00100000_00000111
|
let mirrorDownAddr = addr & 0b00100000_00000111
|
||||||
memWrite(mirrorDownAddr, data: data)
|
memWrite(mirrorDownAddr, data: data)
|
||||||
case 0x4000...0x4013, 0x4015:
|
|
||||||
return // Ignore APU
|
|
||||||
case 0x4016:
|
|
||||||
return // ignore Joy 1
|
|
||||||
case 0x4017:
|
|
||||||
return // Ignore Joy 2
|
|
||||||
case 0x4014:
|
|
||||||
var buffer = [UInt8](repeating: 0, count: 256)
|
|
||||||
let hi = UInt16(data) << 8
|
|
||||||
for i in 0..<256 {
|
|
||||||
buffer[i] = memRead(hi + UInt16(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
ppu.writeOamDma(buffer)
|
|
||||||
case ROM_ADDRESS_START...ROM_ADDRESS_END:
|
case ROM_ADDRESS_START...ROM_ADDRESS_END:
|
||||||
fatalError("Attempt to write to Cartridge ROM space: \(addr)")
|
fatalError("Attempt to write to Cartridge ROM space: \(addr)")
|
||||||
default:
|
default:
|
||||||
|
@ -18,7 +18,7 @@ class NesPPU {
|
|||||||
var scanline: UInt16 = 0
|
var scanline: UInt16 = 0
|
||||||
var cycles: Int = 0
|
var cycles: Int = 0
|
||||||
|
|
||||||
var nmiInterrupt: UInt8? = nil
|
var nmiInterrupt: UInt8?
|
||||||
|
|
||||||
init(_ chrRom: [UInt8], _ mirroring: Mirroring) {
|
init(_ chrRom: [UInt8], _ mirroring: Mirroring) {
|
||||||
self.chrRom = chrRom
|
self.chrRom = chrRom
|
||||||
@ -28,16 +28,16 @@ class NesPPU {
|
|||||||
func tick(_ cycles: UInt8) -> Bool {
|
func tick(_ cycles: UInt8) -> Bool {
|
||||||
self.cycles += Int(cycles)
|
self.cycles += Int(cycles)
|
||||||
if self.cycles >= 341 {
|
if self.cycles >= 341 {
|
||||||
//print(self.cycles)
|
|
||||||
self.cycles = self.cycles - 341
|
self.cycles = self.cycles - 341
|
||||||
self.scanline += 1
|
scanline += 1
|
||||||
|
|
||||||
if scanline == 241 {
|
if scanline == 241 {
|
||||||
self.status.setVblankStatus(true)
|
if self.ctrl.generateVblankNMI() {
|
||||||
status.setSpriteZeroHit(false)
|
self.status.setVblankStatus(true)
|
||||||
if ctrl.generateVblankNMI() {
|
status.setSpriteZeroHit(false)
|
||||||
nmiInterrupt = 1
|
if ctrl.generateVblankNMI() {
|
||||||
print("interrupt")
|
nmiInterrupt = 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,12 +52,6 @@ class NesPPU {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func pollNMI() -> UInt8? {
|
|
||||||
let tmp = self.nmiInterrupt
|
|
||||||
self.nmiInterrupt = nil
|
|
||||||
return tmp
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeToPPUAddr(_ value: UInt8) {
|
func writeToPPUAddr(_ value: UInt8) {
|
||||||
addr.update(value)
|
addr.update(value)
|
||||||
}
|
}
|
||||||
@ -115,32 +109,7 @@ class NesPPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func writeToData(_ data: UInt8) {
|
func writeToData(_ data: UInt8) {
|
||||||
let addr = addr.get()
|
fatalError("Not Implemented")
|
||||||
print("\(addr): \(data)")
|
|
||||||
switch addr {
|
|
||||||
case 0...0x1fff:
|
|
||||||
print("Attempt to write to chr rom space \(addr)!")
|
|
||||||
case 0x2000...0x2fff:
|
|
||||||
self.vram[Int(mirrorVramAddr(addr))] = data
|
|
||||||
case 0x3000...0x3eff:
|
|
||||||
fatalError("addr \(addr) should not be used in reality!")
|
|
||||||
//Addresses $3F10/$3F14/$3F18/$3F1C are mirrors of $3F00/$3F04/$3F08/$3F0C
|
|
||||||
case 0x3f10, 0x3f14, 0x3f18, 0x3f1c:
|
|
||||||
let addrMirror = addr - 0x10
|
|
||||||
paletteTable[Int(addrMirror - 0x3f00)] = data
|
|
||||||
case 0x3f00...0x3fff:
|
|
||||||
paletteTable[Int(addr - 0x3f00)] = data
|
|
||||||
default:
|
|
||||||
fatalError("Unexpected access to mirrored space \(addr)")
|
|
||||||
}
|
|
||||||
incrememtVramAddr()
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeOamDma(_ buffer: [UInt8]) {
|
|
||||||
for x in buffer {
|
|
||||||
oamData[Int(oamAddr)] = x
|
|
||||||
oamAddr = oamAddr &+ 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readStatus() -> UInt8 {
|
func readStatus() -> UInt8 {
|
||||||
|
@ -28,7 +28,7 @@ struct ControlRegister: OptionSet {
|
|||||||
static let GENERATE_NMI = ControlRegister(rawValue: 0b10000000)
|
static let GENERATE_NMI = ControlRegister(rawValue: 0b10000000)
|
||||||
|
|
||||||
func vramAddrIncrement() -> UInt8 {
|
func vramAddrIncrement() -> UInt8 {
|
||||||
if !self.contains(.VRAM_ADD_INCREMENT) {
|
if self.contains(.VRAM_ADD_INCREMENT) {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
32
|
32
|
||||||
@ -38,12 +38,4 @@ struct ControlRegister: OptionSet {
|
|||||||
func generateVblankNMI() -> Bool {
|
func generateVblankNMI() -> Bool {
|
||||||
self.contains(.GENERATE_NMI)
|
self.contains(.GENERATE_NMI)
|
||||||
}
|
}
|
||||||
|
|
||||||
func backgroundPatternAddr() -> Int {
|
|
||||||
if !self.contains(.BACKROUND_PATTERN_ADDR) {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
0x1000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
class Render {
|
|
||||||
static func render(_ ppu: NesPPU, frame: Frame) {
|
|
||||||
let bank = ppu.ctrl.backgroundPatternAddr()
|
|
||||||
|
|
||||||
for i in 0..<0x03c0 { // For now, just use first nametable
|
|
||||||
let tileAddr = UInt16(ppu.vram[i])
|
|
||||||
//print(ppu.vram)
|
|
||||||
let tileX = i % 32
|
|
||||||
let tileY = i / 32
|
|
||||||
let tile = ppu.chrRom[(bank + Int(tileAddr) * 16)...(bank + Int(tileAddr) * 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 & upper) << 1 | (1 & lower)
|
|
||||||
upper = upper >> 1
|
|
||||||
lower = lower >> 1
|
|
||||||
let rgb = switch value {
|
|
||||||
case 0:
|
|
||||||
NESColor.SYSTEM_PALLETE[0x01]
|
|
||||||
case 1:
|
|
||||||
NESColor.SYSTEM_PALLETE[0x23]
|
|
||||||
case 2:
|
|
||||||
NESColor.SYSTEM_PALLETE[0x28]
|
|
||||||
case 3:
|
|
||||||
NESColor.SYSTEM_PALLETE[0x31]
|
|
||||||
default:
|
|
||||||
fatalError("Invalid Pallete Color type")
|
|
||||||
}
|
|
||||||
frame.setPixel((tileX * 8 + x, tileY * 8 + y), rgb)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -100,13 +100,14 @@ bytes.getBytes(&gameCode, length: bytes.length)
|
|||||||
|
|
||||||
let rom = try Rom(gameCode)
|
let rom = try Rom(gameCode)
|
||||||
|
|
||||||
var frame = Frame()
|
//let tileFrame = TileViewer.showTile(chrRom: rom.character, bank: 1, tileNum: 0)
|
||||||
let bus = Bus(rom) { ppu in
|
let tileFrame = TileViewer.showTileBank(chrRom: rom.character, bank: 1)
|
||||||
Render.render(ppu, frame: frame)
|
|
||||||
SDL_UpdateTexture(texture, nil, frame.data, 256 * 3)
|
|
||||||
SDL_RenderCopy(canvas, texture, nil, nil)
|
|
||||||
SDL_RenderPresent(canvas)
|
|
||||||
|
|
||||||
|
SDL_UpdateTexture(texture, nil, tileFrame.data, 256 * 3)
|
||||||
|
SDL_RenderCopy(canvas, texture, nil, nil)
|
||||||
|
SDL_RenderPresent(canvas)
|
||||||
|
|
||||||
|
while true {
|
||||||
while SDL_PollEvent(&event) > 0 {
|
while SDL_PollEvent(&event) > 0 {
|
||||||
if event.type == SDL_QUIT.rawValue {
|
if event.type == SDL_QUIT.rawValue {
|
||||||
SDL_DestroyWindow(window)
|
SDL_DestroyWindow(window)
|
||||||
@ -126,37 +127,6 @@ let bus = Bus(rom) { ppu in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let cpu = CPU(bus: bus)
|
|
||||||
cpu.reset()
|
|
||||||
cpu.run()
|
|
||||||
|
|
||||||
// let tileFrame = TileViewer.showTile(chrRom: rom.character, bank: 1, tileNum: 0)
|
|
||||||
// let tileFrame = TileViewer.showTileBank(chrRom: rom.character, bank: 1)
|
|
||||||
|
|
||||||
// SDL_UpdateTexture(texture, nil, tileFrame.data, 256 * 3)
|
|
||||||
// SDL_RenderCopy(canvas, texture, nil, nil)
|
|
||||||
// SDL_RenderPresent(canvas)
|
|
||||||
|
|
||||||
// while true {
|
|
||||||
// while SDL_PollEvent(&event) > 0 {
|
|
||||||
// if event.type == SDL_QUIT.rawValue {
|
|
||||||
// SDL_DestroyWindow(window)
|
|
||||||
// SDL_Quit()
|
|
||||||
// exit(0)
|
|
||||||
// }
|
|
||||||
// if event.type == SDL_KEYDOWN.rawValue {
|
|
||||||
// switch SDL_KeyCode(UInt32(event.key.keysym.sym)) {
|
|
||||||
// case SDLK_ESCAPE:
|
|
||||||
// SDL_DestroyWindow(window)
|
|
||||||
// SDL_Quit()
|
|
||||||
// exit(0)
|
|
||||||
// default:
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let bus = Bus(try! Rom(gameCode))
|
// let bus = Bus(try! Rom(gameCode))
|
||||||
|
|
||||||
//var cpu = CPU(bus: bus)
|
//var cpu = CPU(bus: bus)
|
||||||
|
Loading…
Reference in New Issue
Block a user