From 915bff96a16befa6e91414abd1ca124ee7cdd426 Mon Sep 17 00:00:00 2001 From: Andrew Glaze Date: Fri, 19 Jul 2024 22:52:46 -0400 Subject: [PATCH] create Rom.swift and bus.swift --- Sources/Bus.swift | 37 +++++++++++++++++++++++++++++++++++ Sources/CPU.swift | 18 ++++++++++++----- Sources/Rom.swift | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 Sources/Bus.swift create mode 100644 Sources/Rom.swift diff --git a/Sources/Bus.swift b/Sources/Bus.swift new file mode 100644 index 0000000..6e97d7b --- /dev/null +++ b/Sources/Bus.swift @@ -0,0 +1,37 @@ +class Bus { + var cpuVram: [UInt8] = .init(repeating: 0, count: 2048) + fileprivate let RAM : UInt16 = 0x0000 + fileprivate let RAM_MIRRORS_END: UInt16 = 0x1FFF + fileprivate let PPU_REGISTERS: UInt16 = 0x2000 + fileprivate let PPU_REGISTERS_MIRRORS_END: UInt16 = 0x3FFF +} + + +extension Bus: Memory { + func memRead(_ addr: UInt16) -> UInt8 { + switch addr { + case RAM...RAM_MIRRORS_END: + let mirrorDownAddr = addr & 0b00000111_11111111 + return self.cpuVram[Int(mirrorDownAddr)] + case PPU_REGISTERS...PPU_REGISTERS_MIRRORS_END: + let mirrorDownAddr = addr & 0b00100000_00000111; + fatalError("PPU not implemented yet") + default: + print("Ignoring mem access at \(addr)") + return 0 + } + } + + func memWrite(_ addr: UInt16, data: UInt8) { + switch addr { + case RAM...RAM_MIRRORS_END: + let mirrorDownAddr = addr & 0b11111111111 + self.cpuVram[Int(mirrorDownAddr)] = data + case PPU_REGISTERS...PPU_REGISTERS_MIRRORS_END: + let mirrorDownAddr = addr & 0b00100000_00000111 + fatalError("PPU is not implemented yet!") + default: + print("Ignorming mem-write at \(addr)") + } + } +} diff --git a/Sources/CPU.swift b/Sources/CPU.swift index bd282f6..37fe472 100644 --- a/Sources/CPU.swift +++ b/Sources/CPU.swift @@ -37,7 +37,7 @@ class CPU { var stackPointer: UInt8 = STACK_RESET var status: CPUFlags = [.interruptDisable, .break2] var programCounter: UInt16 = 0 - private var memory = [UInt8](repeating: 0, count: 0xFFFF) + var bus = Bus() func getOpperandAddress(_ mode: AddressingMode) -> UInt16 { @@ -98,7 +98,7 @@ class CPU { } func load(_ program: [UInt8]) { - memory[0x0600 ..< (0x0600 + program.count)] = program[0.. (), onComplete: @escaping () -> ()) { let opcodes = OPCODES_MAP - Timer.scheduledTimer(withTimeInterval: 0.00007, repeats: true) { [self] timer in + _ = Timer.scheduledTimer(withTimeInterval: 0.00007, repeats: true) { [self] timer in processOpcodes(onCycle: onCycle, opcodes: opcodes, timer: timer) { onComplete() } @@ -390,11 +390,19 @@ class CPU { extension CPU: Memory { func memRead(_ addr: UInt16) -> UInt8 { - memory[Int(addr)] + return bus.memRead(addr) } func memWrite(_ addr: UInt16, data: UInt8) { - memory[Int(addr)] = data + bus.memWrite(addr, data: data) + } + + func memReadU16(_ addr: UInt16) -> UInt16 { + return bus.memReadU16(addr) + } + + func memWriteU16(_ addr: UInt16, data: UInt16) { + bus.memWriteU16(addr, data: data) } } diff --git a/Sources/Rom.swift b/Sources/Rom.swift new file mode 100644 index 0000000..93b68ce --- /dev/null +++ b/Sources/Rom.swift @@ -0,0 +1,50 @@ +struct Rom { + fileprivate let PRG_ROM_PAGE_SIZE = 16384 + fileprivate let CHR_ROM_PAGE_SIZE = 8192 + + var program: [UInt8] + var character: [UInt8] + var mapper: UInt8 + var screenMirror: Mirroring + + init(_ raw: [UInt8]) throws { + guard raw[0...4] == [0x4E, 0x45, 0x53, 0x1A] else { throw HeaderParseError.notINES("File is not in iNES file format.") } + mapper = (raw[7] & 0b1111_0000) | (raw[6] >> 4) + + let inesVer = (raw[7] >> 2) & 0b11 + guard inesVer == 0 else { throw HeaderParseError.iNes2("iNES2.0 format not supported.") } + + let fourScreen = raw[6] & 0b1000 != 0 + let vertMirroring = raw[6] & 0b1 != 0 + screenMirror = switch (fourScreen, vertMirroring) { + case (true, _): + Mirroring.fourScreen + case (false, true): + Mirroring.vertical + case (false, false): + Mirroring.horizontal + } + + let programSize = Int(raw[4]) * PRG_ROM_PAGE_SIZE + let characterSize = Int(raw[5]) * CHR_ROM_PAGE_SIZE + + let skipTrainer = raw[6] & 0b100 != 0 + + let programStart = 16 + (skipTrainer ? 512 : 0) + let characterStart = programStart + programSize + + program = Array(raw[programStart...(programStart + programSize)]) + character = Array(raw[characterStart...(characterStart + characterSize)]) + } +} + +enum Mirroring { + case vertical + case horizontal + case fourScreen +} + +enum HeaderParseError: Error { + case notINES(String) + case iNes2(String) +}