From f911a78d843bc85d6ff6b365e31cb3b38adaa1bf Mon Sep 17 00:00:00 2001 From: TQ Hirsch Date: Wed, 20 Sep 2023 10:44:24 +0200 Subject: [PATCH] 18% speedup from interrupt optimization --- src/main/kotlin/Main.kt | 11 ++-- src/main/kotlin/com/thequux/mcpdp/core/CPU.kt | 60 ++++++++++++------- .../com/thequux/mcpdp/peripheral/Unibus.kt | 11 +++- 3 files changed, 54 insertions(+), 28 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 6119d32..4c9fb91 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -18,15 +18,16 @@ fun main(args: Array) { cpu.loadAbs(File(args[0])) cpu.runState = CPU.RunState.RUNNING cpu.pc = 0x80u - val start = System.nanoTime() - val ninsn = cpu.run() - val end = System.nanoTime() + val start = System.nanoTime() + val ninsn = cpu.run(50000000) + val end = System.nanoTime() System.err.println("Halted at 0${cpu.pc.toString(8)}") - val time = (end-start).toDouble() / 1_000_000_000.0 - println("Executed ${ninsn} in ${time}s: ${ninsn/time} i/s") + val time = (end - start).toDouble() / 1_000_000_000.0 + println("Executed ${ninsn} in ${time}s: ${ninsn / time} i/s") } finally { println("Exiting") console.stop() } + System.exit(0) } diff --git a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt index 84d70b0..e18eac0 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt @@ -111,11 +111,11 @@ class CPU(val mbus: MemBus) { val bitset = pirq shr 8 var maxp: UShort = 0u for (i in 7 downTo 1) { - if (bitset bit i) { - maxp = i.toUShort() shl 1 - break - } - } + if (bitset bit i) { + maxp = i.toUShort() shl 1 + break + } + } field = value and 0xFE00u or maxp or (maxp shl 4) } @@ -828,21 +828,28 @@ class CPU(val mbus: MemBus) { try { if (runState == RunState.HALTED) return - for (i in 7 downTo (psw_priority + 1)) { - if (pirq bit 8+i) { - logger.debug("PIRQ{} trap to 0xA0", i) - trap(0xA0u) - break + if (mbus.unibus.interruptPending) { + for (i in 7 downTo (psw_priority + 1)) { + if (pirq bit 8 + i) { + logger.debug("PIRQ{} trap to 0xA0", i) + trap(0xA0u) + break + } + val source = mbus.unibus.checkInterrupt(i) + if (source != null) { + // we might have been waiting for an interrupt + runState = RunState.RUNNING + val vector = source.vector + logger.debug("Unibus interrupt at pri {} to {}", i, vector) + trap(vector) + source.handled() + break + } } - val source = mbus.unibus.checkInterrupt(i) - if (source != null) { - // we might have been waiting for an interrupt - runState = RunState.RUNNING - val vector = source.vector - logger.debug("Unibus interrupt at pri {} to {}", i, vector) - trap(vector) - source.handled() - break + } else { + val pirqLvl = pirq.toInt() shr 1 and 7; + if (pirqLvl > psw_priority) { + trap(0xA0u) } } if (runState == RunState.WAIT_FOR_INTERRUPT) { @@ -865,12 +872,21 @@ class CPU(val mbus: MemBus) { } fun run(): Long { - var ninsn: Long = 0 + var ninsn: Long = 0 while (runState == RunState.RUNNING) { - ninsn++ + ninsn += run(Long.MAX_VALUE) step() } - return ninsn + return ninsn + } + + fun run(nstep: Long): Long { + var ninsn: Long = 0 + while (runState == RunState.RUNNING && ninsn < nstep) { + ninsn++ + step() + } + return ninsn } fun trap(vector: UShort) { diff --git a/src/main/kotlin/com/thequux/mcpdp/peripheral/Unibus.kt b/src/main/kotlin/com/thequux/mcpdp/peripheral/Unibus.kt index 277cbec..54cec8b 100644 --- a/src/main/kotlin/com/thequux/mcpdp/peripheral/Unibus.kt +++ b/src/main/kotlin/com/thequux/mcpdp/peripheral/Unibus.kt @@ -77,6 +77,9 @@ class Unibus: PAddressSpace, Subregion(12, 6) { private val logger = LoggerFactory.getLogger(this.javaClass) private val queue: Array> = Array(8) { Vector(4) } + private var interruptCount: Int = 0 + val interruptPending: Boolean + get() = interruptCount > 0 override fun map(address: UInt): PAddressSpace = super.map(address) ?: throw BusTimeoutError(address) @@ -101,11 +104,17 @@ class Unibus: PAddressSpace, Subregion(12, 6) { /// to fetch the currently desired interrupt vector fun assertInterrupt(priority: Int, device: InterruptSource) { val list = queue[priority] + if (list.isEmpty()) { + interruptCount++ + } if (!list.contains(device)) list.add(device) } fun deassertInterrupt(priority: Int, device: InterruptSource) { - queue[priority].remove(device) + val lvlQueue = queue[priority] + if (lvlQueue.remove(device) && lvlQueue.isEmpty()) { + interruptCount-- + } } // Checks for an interrupt. The handler receives (priority, device)