From 3f86d5185e055a701de087b97573b0c1b1c95f37 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 16 Feb 2020 16:01:41 +0100 Subject: [PATCH] cpu irq/nmi now via "pin assert" instead of pending statuses --- src/main/kotlin/razorvine/c64emu/Cia.kt | 8 +++--- src/main/kotlin/razorvine/c64emu/GUI.kt | 2 +- src/main/kotlin/razorvine/c64emu/VicII.kt | 2 +- .../razorvine/examplemachines/DebugWindow.kt | 4 +-- src/main/kotlin/razorvine/ksim65/Cpu6502.kt | 27 +++++++------------ src/main/kotlin/razorvine/ksim65/Cpu65C02.kt | 4 +-- .../razorvine/ksim65/components/Timer.kt | 4 +-- src/test/kotlin/Test6502Klaus2m5Functional.kt | 12 ++++----- 8 files changed, 28 insertions(+), 35 deletions(-) diff --git a/src/main/kotlin/razorvine/c64emu/Cia.kt b/src/main/kotlin/razorvine/c64emu/Cia.kt index 4c371fc..9a7218e 100644 --- a/src/main/kotlin/razorvine/c64emu/Cia.kt +++ b/src/main/kotlin/razorvine/c64emu/Cia.kt @@ -92,8 +92,8 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu: // timer A is enabled, assume system cycles counting for now timerAactual-- if (timerAactual == 0 && timerAinterruptEnabled) { - if (number == 1) cpu.irq() - else if (number == 2) cpu.nmi() + if (number == 1) cpu.irqAsserted = true + else if (number == 2) cpu.nmiAsserted = true } if (timerAactual < 0) timerAactual = if (ramBuffer[0x0e].toInt() and 0b00001000 != 0) 0 else timerAset } @@ -108,8 +108,8 @@ class Cia(val number: Int, startAddress: Address, endAddress: Address, val cpu: timerBactual-- } if (timerBactual == 0 && timerBinterruptEnabled) { - if (number == 1) cpu.irq() - else if (number == 2) cpu.nmi() + if (number == 1) cpu.irqAsserted = true + else if (number == 2) cpu.nmiAsserted = true } if (timerBactual < 0) timerBactual = if (regCRB and 0b00001000 != 0) 0 else timerBset } diff --git a/src/main/kotlin/razorvine/c64emu/GUI.kt b/src/main/kotlin/razorvine/c64emu/GUI.kt index 561b79a..f43583b 100644 --- a/src/main/kotlin/razorvine/c64emu/GUI.kt +++ b/src/main/kotlin/razorvine/c64emu/GUI.kt @@ -85,7 +85,7 @@ class MainC64Window(title: String, chargen: Rom, val ram: MemoryComponent, val c override fun keyPressed(event: KeyEvent) { // '\' is mapped as RESTORE, this causes a NMI on the cpu if (event.keyChar == '\\') { - cpu.nmi() + cpu.nmiAsserted = true } else { keypressCia.hostKeyPressed(event) } diff --git a/src/main/kotlin/razorvine/c64emu/VicII.kt b/src/main/kotlin/razorvine/c64emu/VicII.kt index 54014b2..38cf00b 100644 --- a/src/main/kotlin/razorvine/c64emu/VicII.kt +++ b/src/main/kotlin/razorvine/c64emu/VicII.kt @@ -38,7 +38,7 @@ class VicII(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemM interruptStatusRegisterD019 = if (currentRasterLine == rasterIrqLine) { // signal that current raster line is equal to the desired IRQ raster line // schedule an IRQ as well if the raster interrupt is enabled - if ((ramBuffer[0x1a].toInt() and 1) != 0) cpu.irq() + if ((ramBuffer[0x1a].toInt() and 1) != 0) cpu.irqAsserted = true interruptStatusRegisterD019 or 0b10000001 } else interruptStatusRegisterD019 and 0b11111110 } diff --git a/src/main/kotlin/razorvine/examplemachines/DebugWindow.kt b/src/main/kotlin/razorvine/examplemachines/DebugWindow.kt index 8c02574..5e8b6ce 100644 --- a/src/main/kotlin/razorvine/examplemachines/DebugWindow.kt +++ b/src/main/kotlin/razorvine/examplemachines/DebugWindow.kt @@ -190,8 +190,8 @@ class DebugWindow(private val vm: IVirtualMachine) : JFrame("Debugger - ksim65 v pauseBt.actionCommand = "pause" pauseBt.text = "Pause" } - "irq" -> vm.cpu.irq() - "nmi" -> vm.cpu.nmi() + "irq" -> vm.cpu.irqAsserted = true + "nmi" -> vm.cpu.nmiAsserted = true "quit" -> { dispatchEvent(WindowEvent(this, WindowEvent.WINDOW_CLOSING)) } diff --git a/src/main/kotlin/razorvine/ksim65/Cpu6502.kt b/src/main/kotlin/razorvine/ksim65/Cpu6502.kt index 4521ad8..1003300 100644 --- a/src/main/kotlin/razorvine/ksim65/Cpu6502.kt +++ b/src/main/kotlin/razorvine/ksim65/Cpu6502.kt @@ -92,6 +92,8 @@ open class Cpu6502 : BusComponent() { var regSP: Int = 0 var regPC: Address = 0 val regP = StatusRegister() + var irqAsserted = false + var nmiAsserted = false var currentOpcode: Int = 0 protected set var currentOpcodeAddress: Address = 0 // the PC can be changed already depending on the addressing mode @@ -100,7 +102,7 @@ open class Cpu6502 : BusComponent() { protected set val isLooping: Boolean get() { // jump loop detection - return (previousOpcodeAddress == currentOpcodeAddress) && !(pendingNMI || pendingIRQ) + return (previousOpcodeAddress == currentOpcodeAddress) && !(nmiAsserted || irqAsserted) } private var previousOpcodeAddress: Address = 0xffff @@ -115,9 +117,6 @@ open class Cpu6502 : BusComponent() { return State(regA.toShort(), regX.toShort(), regY.toShort(), regSP, status, regPC, totalCycles) } - protected var pendingIRQ = false - protected var pendingNMI = false - // data byte from the instruction (only set when addr.mode is Accumulator, Immediate or Implied) protected var fetchedData: Int = 0 @@ -262,7 +261,7 @@ open class Cpu6502 : BusComponent() { */ override fun clock() { if (instrCycles == 0) { - if(pendingNMI || (pendingIRQ && !regP.I)) { + if(nmiAsserted || (irqAsserted && !regP.I)) { handleInterrupt() return } @@ -329,14 +328,6 @@ open class Cpu6502 : BusComponent() { instrCycles = 0 } - fun nmi() { - pendingNMI = true - } - - fun irq() { - pendingIRQ = true - } - protected fun getFetched() = if (currentInstruction.mode == AddrMode.Imm || currentInstruction.mode == AddrMode.Acc || currentInstruction.mode == AddrMode.Imp) fetchedData else read(fetchedAddress) @@ -1079,7 +1070,7 @@ open class Cpu6502 : BusComponent() { protected open fun iBrk() { // handle BRK ('software interrupt') regPC++ - if(pendingNMI) + if(nmiAsserted) return // if an NMI occurs during BRK, the BRK won't get executed on 6502 (65C02 fixes this) pushStackAddr(regPC) regP.B = true @@ -1098,12 +1089,14 @@ open class Cpu6502 : BusComponent() { regP.I = true // interrupts are now disabled // NMOS 6502 doesn't clear the D flag (CMOS 65C02 version does...) - if(pendingNMI) { + // jump to the appropriate irq vector and clear the assertion status of the irq + // (hmm... should the cpu do that? or is this the peripheral's job?) + if(nmiAsserted) { regPC = readWord(NMI_vector) - pendingNMI = false + nmiAsserted = false } else { regPC = readWord(IRQ_vector) - pendingIRQ = false + irqAsserted = false } } diff --git a/src/main/kotlin/razorvine/ksim65/Cpu65C02.kt b/src/main/kotlin/razorvine/ksim65/Cpu65C02.kt index 5e298c7..1dc8efb 100644 --- a/src/main/kotlin/razorvine/ksim65/Cpu65C02.kt +++ b/src/main/kotlin/razorvine/ksim65/Cpu65C02.kt @@ -23,14 +23,14 @@ class Cpu65C02 : Cpu6502() { when (waiting) { Wait.Normal -> super.clock() Wait.Waiting -> { - if (pendingNMI || pendingIRQ) { + if (nmiAsserted || irqAsserted) { // continue execution after hardware interrupt waiting = Wait.Normal instrCycles = 1 } } Wait.Stopped -> { - if (pendingNMI || pendingIRQ) { + if (nmiAsserted || irqAsserted) { // jump to reset vector after hardware interrupt regPC = readWord(RESET_vector) } diff --git a/src/main/kotlin/razorvine/ksim65/components/Timer.kt b/src/main/kotlin/razorvine/ksim65/components/Timer.kt index 0ad331f..36c5119 100644 --- a/src/main/kotlin/razorvine/ksim65/components/Timer.kt +++ b/src/main/kotlin/razorvine/ksim65/components/Timer.kt @@ -33,8 +33,8 @@ class Timer(startAddress: Address, endAddress: Address, val cpu: Cpu6502) : MemM if (enabled && interval > 0) { counter++ if (counter == interval) { - if (nmi) cpu.nmi() - else cpu.irq() + if (nmi) cpu.nmiAsserted = true + else cpu.irqAsserted = true counter = 0 } } diff --git a/src/test/kotlin/Test6502Klaus2m5Functional.kt b/src/test/kotlin/Test6502Klaus2m5Functional.kt index 30200b1..558312b 100644 --- a/src/test/kotlin/Test6502Klaus2m5Functional.kt +++ b/src/test/kotlin/Test6502Klaus2m5Functional.kt @@ -96,19 +96,19 @@ class Test6502Klaus2m5Functional { 1 -> { // println("IRQ at pc ${hexW(cpu.regPC)}") lastIRQpc = cpu.regPC - cpu.irq() + cpu.irqAsserted = true } 2 -> { // println("NMI at pc ${hexW(cpu.regPC)}") lastNMIpc = cpu.regPC - cpu.nmi() + cpu.nmiAsserted = true } 3 -> { // println("IRQ+NMI at pc ${hexW(cpu.regPC)}") lastIRQpc = cpu.regPC lastNMIpc = cpu.regPC - cpu.nmi() - cpu.irq() + cpu.nmiAsserted = true + cpu.irqAsserted = true } } } @@ -154,7 +154,7 @@ class Test6502Klaus2m5Functional { bus.add(ram) cpu.reset() cpu.regPC = 0x0200 - cpu.breakpointForBRK = { cpu, address -> + cpu.breakpointForBRK = { _, address -> if(address==0x024b) { // test end address val error=bus.read(0x000b) // the 'ERROR' variable is stored here if(error==0.toShort()) @@ -189,7 +189,7 @@ class Test6502Klaus2m5Functional { bus.add(ram) cpu.reset() cpu.regPC = 0x0200 - cpu.breakpointForBRK = { cpu, address -> + cpu.breakpointForBRK = { _, address -> if(address==0x024b) { // test end address val error=bus.read(0x000b) // the 'ERROR' variable is stored here if(error==0.toShort())