mirror of
https://github.com/Candygoblen123/SwiftNES.git
synced 2024-11-24 18:06:47 -06:00
PPU: impl NMI interrupt
This commit is contained in:
parent
05927d8e91
commit
830bc5f65a
@ -14,6 +14,31 @@ enum AddressingMode {
|
|||||||
case NoneAddressing
|
case NoneAddressing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Interrupt {
|
||||||
|
case NMI
|
||||||
|
|
||||||
|
var vectorAddr: UInt16 {
|
||||||
|
switch self {
|
||||||
|
case .NMI:
|
||||||
|
0xfffa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var bFlagMask: UInt8 {
|
||||||
|
switch self {
|
||||||
|
case .NMI:
|
||||||
|
0b00100000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var cpuCycles: UInt8 {
|
||||||
|
switch self {
|
||||||
|
case .NMI:
|
||||||
|
2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct CPUFlags: OptionSet {
|
struct CPUFlags: OptionSet {
|
||||||
var rawValue: UInt8
|
var rawValue: UInt8
|
||||||
|
|
||||||
@ -44,41 +69,43 @@ class CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func getOpperandAddress(_ mode: AddressingMode) -> UInt16 {
|
func getOpperandAddress(_ mode: AddressingMode) -> (UInt16, Bool) {
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Immediate:
|
case .Immediate:
|
||||||
return programCounter
|
return (programCounter, false)
|
||||||
default:
|
default:
|
||||||
return getAbsoluteAddress(mode, addr: programCounter)
|
return getAbsoluteAddress(mode, addr: programCounter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAbsoluteAddress(_ mode: AddressingMode, addr: UInt16) -> UInt16 {
|
func getAbsoluteAddress(_ mode: AddressingMode, addr: UInt16) -> (UInt16, Bool) {
|
||||||
switch mode {
|
switch mode {
|
||||||
case .ZeroPage:
|
case .ZeroPage:
|
||||||
return UInt16(memRead(addr))
|
return (UInt16(memRead(addr)), false)
|
||||||
case .Absolute:
|
case .Absolute:
|
||||||
return memReadU16(addr)
|
return (memReadU16(addr), false)
|
||||||
case .ZeroPage_X:
|
case .ZeroPage_X:
|
||||||
let pos = memRead(addr)
|
let pos = memRead(addr)
|
||||||
let addr = pos &+ register_x
|
let addr = pos &+ register_x
|
||||||
return UInt16(addr)
|
return (UInt16(addr), false)
|
||||||
case .ZeroPage_Y:
|
case .ZeroPage_Y:
|
||||||
let pos = memRead(addr)
|
let pos = memRead(addr)
|
||||||
let addr = pos &+ register_y
|
let addr = pos &+ register_y
|
||||||
return UInt16(addr)
|
return (UInt16(addr), false)
|
||||||
case .Absolute_X:
|
case .Absolute_X:
|
||||||
let base = memReadU16(addr)
|
let base = memReadU16(addr)
|
||||||
return base &+ UInt16(register_x)
|
let addr = base &+ UInt16(register_x)
|
||||||
|
return (addr, isPageCross(base, addr))
|
||||||
case .Absolute_Y:
|
case .Absolute_Y:
|
||||||
let base = memReadU16(addr)
|
let base = memReadU16(addr)
|
||||||
return base &+ UInt16(register_y)
|
let addr = base &+ UInt16(register_y)
|
||||||
|
return (addr, isPageCross(base, addr))
|
||||||
case .Indirect_X:
|
case .Indirect_X:
|
||||||
let base = memRead(addr)
|
let base = memRead(addr)
|
||||||
let ptr = UInt8(base) &+ register_x
|
let ptr = UInt8(base) &+ register_x
|
||||||
let lo = memRead(UInt16(ptr))
|
let lo = memRead(UInt16(ptr))
|
||||||
let hi = memRead(UInt16(ptr &+ 1))
|
let hi = memRead(UInt16(ptr &+ 1))
|
||||||
return UInt16(hi) << 8 | UInt16(lo)
|
return (UInt16(hi) << 8 | UInt16(lo), false)
|
||||||
case .Indirect_Y:
|
case .Indirect_Y:
|
||||||
let base = memRead(addr)
|
let base = memRead(addr)
|
||||||
|
|
||||||
@ -86,12 +113,16 @@ class CPU {
|
|||||||
let hi = memRead(UInt16(base &+ 1))
|
let hi = memRead(UInt16(base &+ 1))
|
||||||
let deref_base = UInt16(hi) << 8 | UInt16(lo)
|
let deref_base = UInt16(hi) << 8 | UInt16(lo)
|
||||||
let deref = deref_base &+ UInt16(register_y)
|
let deref = deref_base &+ UInt16(register_y)
|
||||||
return deref
|
return (deref, isPageCross(deref, deref_base))
|
||||||
default:
|
default:
|
||||||
fatalError("mode \(mode) is not implemented")
|
fatalError("mode \(mode) is not implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isPageCross(_ lhs: UInt16, _ rhs: UInt16) -> Bool {
|
||||||
|
lhs & 0xff00 != rhs & 0xff00
|
||||||
|
}
|
||||||
|
|
||||||
func reset() {
|
func reset() {
|
||||||
register_a = 0
|
register_a = 0
|
||||||
register_x = 0
|
register_x = 0
|
||||||
@ -124,13 +155,36 @@ class CPU {
|
|||||||
|
|
||||||
func run(onCycle: @escaping () -> (), onComplete: @escaping () -> ()) {
|
func run(onCycle: @escaping () -> (), onComplete: @escaping () -> ()) {
|
||||||
let opcodes = OPCODES_MAP
|
let opcodes = OPCODES_MAP
|
||||||
//_ = Timer.scheduledTimer(withTimeInterval: 0.00007, repeats: true) { [self] timer in
|
|
||||||
while true {
|
while true {
|
||||||
|
if let _nmi = bus.pollNMI() {
|
||||||
|
interrupt(.NMI)
|
||||||
|
}
|
||||||
processOpcodes(onCycle: onCycle, opcodes: opcodes) {
|
processOpcodes(onCycle: onCycle, opcodes: opcodes) {
|
||||||
onComplete()
|
onComplete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//}
|
}
|
||||||
|
|
||||||
|
func interrupt(_ interrupt: Interrupt) {
|
||||||
|
stackPushU16(programCounter)
|
||||||
|
var flag = status
|
||||||
|
if interrupt.bFlagMask & 0b010000 == 1 {
|
||||||
|
flag.insert(.break1)
|
||||||
|
} else {
|
||||||
|
flag.remove(.break1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if interrupt.bFlagMask & 0b100000 == 1 {
|
||||||
|
flag.insert(.break2)
|
||||||
|
} else {
|
||||||
|
flag.remove(.break2)
|
||||||
|
}
|
||||||
|
|
||||||
|
stackPush(flag.rawValue)
|
||||||
|
status.insert(.interruptDisable)
|
||||||
|
|
||||||
|
bus.tick(interrupt.cpuCycles)
|
||||||
|
programCounter = memReadU16(interrupt.vectorAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func processOpcodes(onCycle: () -> (), opcodes: [UInt8: OpCode], onComplete: () -> ()) {
|
func processOpcodes(onCycle: () -> (), opcodes: [UInt8: OpCode], onComplete: () -> ()) {
|
||||||
@ -264,10 +318,10 @@ class CPU {
|
|||||||
case 0x24, 0x2c:
|
case 0x24, 0x2c:
|
||||||
bit(opcode.mode)
|
bit(opcode.mode)
|
||||||
case 0x86, 0x96, 0x8e:
|
case 0x86, 0x96, 0x8e:
|
||||||
let addr = getOpperandAddress(opcode.mode)
|
let (addr, _) = getOpperandAddress(opcode.mode)
|
||||||
memWrite(addr, data: register_x)
|
memWrite(addr, data: register_x)
|
||||||
case 0x84, 0x94, 0x8c:
|
case 0x84, 0x94, 0x8c:
|
||||||
let addr = getOpperandAddress(opcode.mode)
|
let (addr, _) = getOpperandAddress(opcode.mode)
|
||||||
memWrite(addr, data: register_y)
|
memWrite(addr, data: register_y)
|
||||||
case 0xa2, 0xa6, 0xb6, 0xae, 0xbe:
|
case 0xa2, 0xa6, 0xb6, 0xae, 0xbe:
|
||||||
ldx(opcode.mode)
|
ldx(opcode.mode)
|
||||||
@ -301,8 +355,11 @@ class CPU {
|
|||||||
onComplete()
|
onComplete()
|
||||||
/// NOP Read
|
/// NOP Read
|
||||||
case 0x04, 0x44, 0x64, 0x14, 0x34, 0x54, 0x74, 0xd4, 0xf4, 0x0c, 0x1c, 0x3c, 0x5c, 0x7c, 0xdc, 0xfc:
|
case 0x04, 0x44, 0x64, 0x14, 0x34, 0x54, 0x74, 0xd4, 0xf4, 0x0c, 0x1c, 0x3c, 0x5c, 0x7c, 0xdc, 0xfc:
|
||||||
let addr = getOpperandAddress(opcode.mode)
|
let (addr, pageCross) = getOpperandAddress(opcode.mode)
|
||||||
let _ = self.memRead(addr)
|
let _ = self.memRead(addr)
|
||||||
|
if pageCross {
|
||||||
|
bus.tick(1)
|
||||||
|
}
|
||||||
// Do nothing
|
// Do nothing
|
||||||
/// NOP
|
/// NOP
|
||||||
case 0x1a, 0x3a, 0x5a, 0x7a, 0xda, 0xfa:
|
case 0x1a, 0x3a, 0x5a, 0x7a, 0xda, 0xfa:
|
||||||
@ -320,23 +377,23 @@ class CPU {
|
|||||||
{ /* 2 byte NOP immediate, do nothing */ }()
|
{ /* 2 byte NOP immediate, do nothing */ }()
|
||||||
/// LAX
|
/// LAX
|
||||||
case 0xa7, 0xb7, 0xaf, 0xbf, 0xa3, 0xb3:
|
case 0xa7, 0xb7, 0xaf, 0xbf, 0xa3, 0xb3:
|
||||||
let addr = getOpperandAddress(opcode.mode)
|
let (addr, _) = getOpperandAddress(opcode.mode)
|
||||||
let data = memRead(addr)
|
let data = memRead(addr)
|
||||||
setRegisterA(data)
|
setRegisterA(data)
|
||||||
register_x = register_a
|
register_x = register_a
|
||||||
/// SAX
|
/// SAX
|
||||||
case 0x87, 0x97, 0x8f, 0x83:
|
case 0x87, 0x97, 0x8f, 0x83:
|
||||||
let data = register_a & register_x
|
let data = register_a & register_x
|
||||||
let addr = getOpperandAddress(opcode.mode)
|
let (addr, _) = getOpperandAddress(opcode.mode)
|
||||||
memWrite(addr, data: data)
|
memWrite(addr, data: data)
|
||||||
// Unoffical SBC
|
// Unoffical SBC
|
||||||
case 0xeb:
|
case 0xeb:
|
||||||
let addr = getOpperandAddress(opcode.mode)
|
let (addr, _) = getOpperandAddress(opcode.mode)
|
||||||
let data = self.memRead(addr)
|
let data = self.memRead(addr)
|
||||||
subFromRegisterA(data)
|
subFromRegisterA(data)
|
||||||
/// DCP
|
/// DCP
|
||||||
case 0xc7, 0xd7, 0xCF, 0xdF, 0xdb, 0xd3, 0xc3:
|
case 0xc7, 0xd7, 0xCF, 0xdF, 0xdb, 0xd3, 0xc3:
|
||||||
let addr = getOpperandAddress(opcode.mode)
|
let (addr, _) = getOpperandAddress(opcode.mode)
|
||||||
var data = memRead(addr)
|
var data = memRead(addr)
|
||||||
data = data &- 1
|
data = data &- 1
|
||||||
memWrite(addr, data: data)
|
memWrite(addr, data: data)
|
||||||
@ -363,6 +420,8 @@ class CPU {
|
|||||||
default: fatalError("TODO!")
|
default: fatalError("TODO!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bus.tick(opcode.cycles)
|
||||||
|
|
||||||
if programCounterState == programCounter {
|
if programCounterState == programCounter {
|
||||||
programCounter += UInt16(opcode.len - 1)
|
programCounter += UInt16(opcode.len - 1)
|
||||||
}
|
}
|
||||||
@ -461,7 +520,7 @@ class CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func compare(mode: AddressingMode, compare_with: UInt8) {
|
func compare(mode: AddressingMode, compare_with: UInt8) {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, pageCross) = getOpperandAddress(mode)
|
||||||
let data = memRead(addr)
|
let data = memRead(addr)
|
||||||
if data <= compare_with {
|
if data <= compare_with {
|
||||||
status.insert(.carry)
|
status.insert(.carry)
|
||||||
@ -470,14 +529,23 @@ class CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateZeroAndNegativeFlags(compare_with &- data)
|
updateZeroAndNegativeFlags(compare_with &- data)
|
||||||
|
|
||||||
|
if pageCross {
|
||||||
|
bus.tick(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func branch(_ condition: Bool) {
|
func branch(_ condition: Bool) {
|
||||||
if condition {
|
if condition {
|
||||||
|
bus.tick(1)
|
||||||
let addr = memRead(programCounter)
|
let addr = memRead(programCounter)
|
||||||
let jump: Int8 = Int8(bitPattern: addr)
|
let jump: Int8 = Int8(bitPattern: addr)
|
||||||
let jump_addr = programCounter &+ 1 &+ UInt16(bitPattern: Int16(jump))
|
let jump_addr = programCounter &+ 1 &+ UInt16(bitPattern: Int16(jump))
|
||||||
|
|
||||||
|
if (programCounter &+ 1) & 0xff00 != jump_addr & 0xff00 {
|
||||||
|
bus.tick(1)
|
||||||
|
}
|
||||||
|
|
||||||
programCounter = jump_addr
|
programCounter = jump_addr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,46 +1,64 @@
|
|||||||
extension CPU {
|
extension CPU {
|
||||||
func lda(_ mode: AddressingMode) {
|
func lda(_ mode: AddressingMode) {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, pageCross) = getOpperandAddress(mode)
|
||||||
let value = memRead(addr)
|
let value = memRead(addr)
|
||||||
|
|
||||||
setRegisterA(value)
|
setRegisterA(value)
|
||||||
|
if pageCross {
|
||||||
|
bus.tick(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ldy(_ mode: AddressingMode) {
|
func ldy(_ mode: AddressingMode) {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, pageCross) = getOpperandAddress(mode)
|
||||||
let data = memRead(addr)
|
let data = memRead(addr)
|
||||||
register_y = data
|
register_y = data
|
||||||
updateZeroAndNegativeFlags(register_y)
|
updateZeroAndNegativeFlags(register_y)
|
||||||
|
if pageCross {
|
||||||
|
bus.tick(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ldx(_ mode: AddressingMode) {
|
func ldx(_ mode: AddressingMode) {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, pageCross) = getOpperandAddress(mode)
|
||||||
let data = memRead(addr)
|
let data = memRead(addr)
|
||||||
register_x = data
|
register_x = data
|
||||||
updateZeroAndNegativeFlags(register_x)
|
updateZeroAndNegativeFlags(register_x)
|
||||||
|
if pageCross {
|
||||||
|
bus.tick(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sta(_ mode: AddressingMode) {
|
func sta(_ mode: AddressingMode) {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, _) = getOpperandAddress(mode)
|
||||||
memWrite(addr, data: register_a)
|
memWrite(addr, data: register_a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func and(_ mode: AddressingMode) {
|
func and(_ mode: AddressingMode) {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, pageCross) = getOpperandAddress(mode)
|
||||||
let data = memRead(addr)
|
let data = memRead(addr)
|
||||||
self.setRegisterA(data & register_a)
|
self.setRegisterA(data & register_a)
|
||||||
|
if pageCross {
|
||||||
|
bus.tick(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func eor(_ mode: AddressingMode) {
|
func eor(_ mode: AddressingMode) {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, pageCross) = getOpperandAddress(mode)
|
||||||
let data = memRead(addr)
|
let data = memRead(addr)
|
||||||
setRegisterA(data ^ register_a)
|
setRegisterA(data ^ register_a)
|
||||||
|
if pageCross {
|
||||||
|
bus.tick(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ora(_ mode: AddressingMode) {
|
func ora(_ mode: AddressingMode) {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, pageCross) = getOpperandAddress(mode)
|
||||||
let data = memRead(addr)
|
let data = memRead(addr)
|
||||||
setRegisterA(data | register_a)
|
setRegisterA(data | register_a)
|
||||||
|
if pageCross {
|
||||||
|
bus.tick(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tax() {
|
func tax() {
|
||||||
@ -59,16 +77,22 @@ extension CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sbc(_ mode: AddressingMode) {
|
func sbc(_ mode: AddressingMode) {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, pageCross) = getOpperandAddress(mode)
|
||||||
let data = memRead(addr)
|
let data = memRead(addr)
|
||||||
let res = Int8(bitPattern: data) &* -1
|
let res = Int8(bitPattern: data) &* -1
|
||||||
addToRegisterA(UInt8(bitPattern: res &- 1))
|
addToRegisterA(UInt8(bitPattern: res &- 1))
|
||||||
|
if pageCross {
|
||||||
|
bus.tick(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func adc(_ mode: AddressingMode) {
|
func adc(_ mode: AddressingMode) {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, pageCross) = getOpperandAddress(mode)
|
||||||
let data = memRead(addr)
|
let data = memRead(addr)
|
||||||
addToRegisterA(data)
|
addToRegisterA(data)
|
||||||
|
if pageCross {
|
||||||
|
bus.tick(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func aslAccumulator() {
|
func aslAccumulator() {
|
||||||
@ -83,7 +107,7 @@ extension CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func asl(_ mode: AddressingMode) -> UInt8 {
|
func asl(_ mode: AddressingMode) -> UInt8 {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, _) = getOpperandAddress(mode)
|
||||||
var data = memRead(addr)
|
var data = memRead(addr)
|
||||||
if data >> 7 == 1 {
|
if data >> 7 == 1 {
|
||||||
setCarryFlag()
|
setCarryFlag()
|
||||||
@ -108,7 +132,7 @@ extension CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func lsr(_ mode: AddressingMode) -> UInt8 {
|
func lsr(_ mode: AddressingMode) -> UInt8 {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, _) = getOpperandAddress(mode)
|
||||||
var data = memRead(addr)
|
var data = memRead(addr)
|
||||||
if data & 1 == 1 {
|
if data & 1 == 1 {
|
||||||
setCarryFlag()
|
setCarryFlag()
|
||||||
@ -138,7 +162,7 @@ extension CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func rol(_ mode: AddressingMode) -> UInt8 {
|
func rol(_ mode: AddressingMode) -> UInt8 {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, _) = getOpperandAddress(mode)
|
||||||
var data = memRead(addr)
|
var data = memRead(addr)
|
||||||
let oldCarry = status.contains(.carry)
|
let oldCarry = status.contains(.carry)
|
||||||
|
|
||||||
@ -174,7 +198,7 @@ extension CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ror(_ mode: AddressingMode) -> UInt8 {
|
func ror(_ mode: AddressingMode) -> UInt8 {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, _) = getOpperandAddress(mode)
|
||||||
var data = memRead(addr)
|
var data = memRead(addr)
|
||||||
let oldCarry = status.contains(.carry)
|
let oldCarry = status.contains(.carry)
|
||||||
if data & 1 == 1 {
|
if data & 1 == 1 {
|
||||||
@ -192,7 +216,7 @@ extension CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func inc(_ mode: AddressingMode) -> UInt8 {
|
func inc(_ mode: AddressingMode) -> UInt8 {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, _) = getOpperandAddress(mode)
|
||||||
var data = memRead(addr)
|
var data = memRead(addr)
|
||||||
data = data &+ 1
|
data = data &+ 1
|
||||||
memWrite(addr, data: data)
|
memWrite(addr, data: data)
|
||||||
@ -211,7 +235,7 @@ extension CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func dec(_ mode: AddressingMode) -> UInt8 {
|
func dec(_ mode: AddressingMode) -> UInt8 {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, _) = getOpperandAddress(mode)
|
||||||
var data = memRead(addr)
|
var data = memRead(addr)
|
||||||
data = data &- 1
|
data = data &- 1
|
||||||
memWrite(addr, data: data)
|
memWrite(addr, data: data)
|
||||||
@ -238,7 +262,7 @@ extension CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func bit(_ mode: AddressingMode) {
|
func bit(_ mode: AddressingMode) {
|
||||||
let addr = getOpperandAddress(mode)
|
let (addr, _) = getOpperandAddress(mode)
|
||||||
let data = memRead(addr)
|
let data = memRead(addr)
|
||||||
let and = register_a & data
|
let and = register_a & data
|
||||||
if and == 0 {
|
if and == 0 {
|
||||||
|
@ -7,7 +7,7 @@ func dumpCpuState(_ cpu: CPU) -> String {
|
|||||||
(UInt16(0), UInt8(0))
|
(UInt16(0), UInt8(0))
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
let addr = cpu.getAbsoluteAddress(opcode.mode, addr: cpu.programCounter + 1)
|
let (addr, _) = cpu.getAbsoluteAddress(opcode.mode, addr: cpu.programCounter + 1)
|
||||||
|
|
||||||
return (addr, cpu.memRead(addr))
|
return (addr, cpu.memRead(addr))
|
||||||
}()
|
}()
|
||||||
|
@ -2,6 +2,7 @@ class Bus {
|
|||||||
var cpuVram: [UInt8] = .init(repeating: 0, count: 2048)
|
var cpuVram: [UInt8] = .init(repeating: 0, count: 2048)
|
||||||
var prgRom: [UInt8]
|
var prgRom: [UInt8]
|
||||||
var ppu: NesPPU
|
var ppu: NesPPU
|
||||||
|
var cycles: Int = 0
|
||||||
|
|
||||||
fileprivate let RAM : UInt16 = 0x0000
|
fileprivate let RAM : UInt16 = 0x0000
|
||||||
fileprivate let RAM_MIRRORS_END: UInt16 = 0x1FFF
|
fileprivate let RAM_MIRRORS_END: UInt16 = 0x1FFF
|
||||||
@ -14,6 +15,15 @@ class Bus {
|
|||||||
ppu = NesPPU(rom.character, rom.screenMirror)
|
ppu = NesPPU(rom.character, rom.screenMirror)
|
||||||
self.prgRom = rom.program
|
self.prgRom = rom.program
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tick(_ cycles: UInt8) {
|
||||||
|
self.cycles += Int(cycles)
|
||||||
|
self.ppu.tick(cycles * 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pollNMI() -> UInt8? {
|
||||||
|
ppu.nmiInterrupt
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,17 +15,53 @@ class NesPPU {
|
|||||||
var oamAddr: UInt8 = 0
|
var oamAddr: UInt8 = 0
|
||||||
var oamData = [UInt8](repeating: 0, count: 64 * 4)
|
var oamData = [UInt8](repeating: 0, count: 64 * 4)
|
||||||
|
|
||||||
|
var scanline: UInt16 = 0
|
||||||
|
var cycles: Int = 0
|
||||||
|
|
||||||
|
var nmiInterrupt: UInt8?
|
||||||
|
|
||||||
init(_ chrRom: [UInt8], _ mirroring: Mirroring) {
|
init(_ chrRom: [UInt8], _ mirroring: Mirroring) {
|
||||||
self.chrRom = chrRom
|
self.chrRom = chrRom
|
||||||
self.mirroring = mirroring
|
self.mirroring = mirroring
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tick(_ cycles: UInt8) -> Bool {
|
||||||
|
self.cycles += Int(cycles)
|
||||||
|
if self.cycles >= 341 {
|
||||||
|
self.cycles = self.cycles - 341
|
||||||
|
scanline += 1
|
||||||
|
|
||||||
|
if scanline == 241 {
|
||||||
|
if self.ctrl.generateVblankNMI() {
|
||||||
|
self.status.setVblankStatus(true)
|
||||||
|
status.setSpriteZeroHit(false)
|
||||||
|
if ctrl.generateVblankNMI() {
|
||||||
|
nmiInterrupt = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if scanline >= 262 {
|
||||||
|
scanline = 0
|
||||||
|
nmiInterrupt = nil
|
||||||
|
status.setSpriteZeroHit(false)
|
||||||
|
self.status.resetVblankStatus()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func writeToPPUAddr(_ value: UInt8) {
|
func writeToPPUAddr(_ value: UInt8) {
|
||||||
addr.update(value)
|
addr.update(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeToCtrl(_ value: UInt8) {
|
func writeToCtrl(_ value: UInt8) {
|
||||||
|
let beforeNmiStatus = ctrl.generateVblankNMI()
|
||||||
ctrl.rawValue = value
|
ctrl.rawValue = value
|
||||||
|
if !beforeNmiStatus && ctrl.generateVblankNMI() && status.isInVblank() {
|
||||||
|
nmiInterrupt = 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func incrememtVramAddr() {
|
func incrememtVramAddr() {
|
||||||
|
@ -34,4 +34,8 @@ struct ControlRegister: OptionSet {
|
|||||||
32
|
32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateVblankNMI() -> Bool {
|
||||||
|
self.contains(.GENERATE_NMI)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user