diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index e976abf..372284f 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,6 +1,7 @@ import ch.qos.logback.classic.LoggerContext import ch.qos.logback.core.util.StatusPrinter import com.thequux.mcpdp.core.CPU +import com.thequux.mcpdp.debug.FlightRecorder import com.thequux.mcpdp.debug.LoggingCollector import com.thequux.mcpdp.debug.NullTracer import com.thequux.mcpdp.debug.Tracer @@ -24,7 +25,9 @@ fun main(args: Array) { var mbus = MemBus(65536) val tracer = Tracer() val loggingCollector = LoggingCollector() - tracer.addCollector(loggingCollector) +// tracer.addCollector(loggingCollector) + val recorder = FlightRecorder(24) + tracer.addCollector(recorder) var cpu = CPU(mbus, if (CPU.debugMode) tracer else NullTracer()) val console = DL11(mbus.unibus, tb.input(), tb.output()).apply { mount(mbus.unibus) } try { @@ -34,14 +37,16 @@ fun main(args: Array) { console.start() cpu.loadAbs(File(args[0])) + cpu.core.setw(0x3C78u, 0u) // halt instead of restart cpu.runState = CPU.RunState.RUNNING cpu.pc = 0x80u val start = System.nanoTime() -// var ninsn = cpu.run(600000000) -// var ninsn = cpu.run(419380) - var ninsn = cpu.run(13300) +// var ninsn = cpu.run(60000000) cpu.tracer = tracer - ninsn += cpu.run(100) + var ninsn = cpu.run(323227) +// var ninsn = cpu.run(13300) +// ninsn += cpu.run(10) + recorder.dump(System.out) cpu.dumpReg() val end = System.nanoTime() diff --git a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt index c475887..4e061fa 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt @@ -82,7 +82,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { 0x0001 -> runState = RunState.WAIT_FOR_INTERRUPT // WAIT 0x0002 -> { // RTI pc = stack_pop() - psw = stack_pop() // TODO: check privilege on mode; check psw[11] + setPSW(stack_pop(), cur_mode == 0) // TODO: check privilege on mode; check psw[11] } // RTI 0x0003 -> setTrap(TrapReason.BPT) // BPT 0x0004 -> setTrap(TrapReason.IOT) // IOT @@ -94,7 +94,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { } // bus reset TODO: bus init 0x0006 -> { pc = stack_pop() - psw = stack_pop() + setPSW(stack_pop(), cur_mode == 0) allowT = false } // RTT in 0x40..0x7f -> { @@ -768,7 +768,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { val core = PagingUnit(mbus, this) var runState: RunState = RunState.HALTED - var psw: UShort + val psw: UShort get() { var res = 0 if (C) { res = res or 0x0001 } @@ -781,26 +781,33 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { res = res or (registerSet shl 11) return res.toUShort() } - set(value) { - var newpsw = value.toInt() - C = value bit 0 - V = value bit 1 - Z = value bit 2 - N = value bit 3 - T = value bit 4 // TODO: handle suspended trap - psw_priority = newpsw shr 5 and 7 + + fun setPSW(value: UShort, allowEsc: Boolean) { + var newpsw = value.toInt() + C = value bit 0 + V = value bit 1 + Z = value bit 2 + N = value bit 3 + T = value bit 4 // TODO: handle suspended trap + if (allowEsc) { registerSet = newpsw shr 11 and 1 cur_mode = newpsw shr 14 - + prv_mode = newpsw shr 12 and 3 + psw_priority = newpsw shr 5 and 7 + } else { + registerSet = registerSet or (newpsw shr 11 and 1) + cur_mode = cur_mode or (newpsw shr 14 and 3) + prv_mode = prv_mode or (newpsw shr 12 and 3) } + } private var cur_mode: Int = 0 set(value) { - prv_mode = field +// prv_mode = field shadow_r6[field] = sp field = if (value == 2) 3 else value sp = shadow_r6[field] - core.mode = value + core.mode = field } private var prv_mode: Int = 0 private var psw_priority: Int = 0 @@ -817,6 +824,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { private var registerSet: Int = 0 set(value) { + if (value == field) return if (value !in 0..1) { throw ProgrammerError("Invalid register set number") } @@ -830,9 +838,12 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { } private var cc: UShort - get() = psw and 0xFu + get() = 0.bit(3, N).bit(2, Z).bit(1, C).bit(0, C).toUShort() set(value) { - psw = (psw and 0xFFFu) or (value and 0xFu) + N = value bit 3 + Z = value bit 2 + V = value bit 1 + C = value bit 0 } private var pirq: UShort = 0u set(value) { @@ -1031,11 +1042,11 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { fun trapRed() { // This is handled separately because otherwise the stack push // would itself trigger a red trap - logger.warn("Stack RED") +// logger.warn("Stack RED") cpu_err = cpu_err or CPU_ERR_STK_RED val old_psw = psw - psw = core.getw(6u) - core.setw(2u, psw) + setPSW(core.getw(6u), true) + core.setw(2u, old_psw) core.setw(0u, pc) sp = 0u trapReq = trapReq and TrapReason.RED.clear.inv() @@ -1050,7 +1061,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { if (trapReq != 0) { for (cause in TrapReason.entries.reversed()) { if (trapReq and cause.mask != 0) { - logger.warn("Trapping because $cause") +// logger.warn("Trapping because $cause") try { callVector(cause.vector) } finally { @@ -1066,7 +1077,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { else if (mbus.unibus.interruptPending) { for (i in 7 downTo (psw_priority + 1)) { if (pirq bit 8 + i) { - logger.debug("PIRQ{} trap to 0xA0", i) +// logger.debug("PIRQ{} trap to 0xA0", i) callVector(0xA0u) break } @@ -1075,7 +1086,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { // we might have been waiting for an interrupt runState = RunState.RUNNING val vector = source.vector - logger.debug("Unibus interrupt at pri {} to {}", i, vector) +// logger.debug("Unibus interrupt at pri {} to {}", i, vector) callVector(vector) source.handled() break @@ -1124,7 +1135,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { setTrap(TrapReason.NXM) } } - logger.warn("Threw error: $error") +// logger.warn("Threw error: $error") } catch (_: InvalidOpcodeException) { setTrap(TrapReason.ILL) } catch (_: EndCycle) { @@ -1144,8 +1155,8 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { var ninsn: Long = 0 while (runState == RunState.RUNNING && ninsn < nstep) { ninsn++ - if (pc == 0x344A.toUShort()) { - pc = pc + if (pc == 0x2E54.toUShort()) { + runState = RunState.HALTED } step() } @@ -1155,7 +1166,8 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { fun callVector(vector: UShort) { val old_psw = psw // update PSW first so that this gets pushed to the - psw = core.getw((vector + 2u).toUShort()) + val newPSW = core.getw((vector + 2u).toUShort()) or (cur_mode shl 12).toUShort() + setPSW(newPSW, true) stack_push(old_psw) stack_push(pc) pc = core.getw(vector) @@ -1188,7 +1200,11 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { 0x3_FFF6u -> cpu_err = value 0x3_FFFAu -> pirq = value 0x3_FFFCu -> stack_limit = value and 0xFF00u // stack limit - 0x3_FFFEu -> psw = value or (cur_mode.toUShort() shl 14) // writing to PSW can only increase current mode + 0x3_FFFEu -> { + setPSW(value or (cur_mode.toUShort() shl 12), true) + // explicitly switch RS if necessary + registerSet = (value shr 11 and 1u).toInt() + } // writing to PSW can only increase current mode else -> { println("Bus error at ${addr.toString(16)}: ${value.toString(16)}") throw BusTimeoutError(addr) @@ -1202,7 +1218,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { trapRed() throw EndCycle() } else if (sp < stack_limit + 256u) { - logger.warn("Stack YLW") +// logger.warn("Stack YLW") // stack limit yellow cpu_err = cpu_err or CPU_ERR_STK_YLW setTrap(TrapReason.YEL) diff --git a/src/main/kotlin/com/thequux/mcpdp/debug/FlightRecorder.kt b/src/main/kotlin/com/thequux/mcpdp/debug/FlightRecorder.kt new file mode 100644 index 0000000..54b846a --- /dev/null +++ b/src/main/kotlin/com/thequux/mcpdp/debug/FlightRecorder.kt @@ -0,0 +1,26 @@ +package com.thequux.mcpdp.debug + +import java.io.PrintStream +import java.io.Writer + +@OptIn(ExperimentalUnsignedTypes::class) +class FlightRecorder(size: Int): Collector { + var trace: Array = Array(size) { null } + var pos = 0 + + override fun invoke(record: TraceRecord) { + trace[pos++] = record + if (pos >= trace.size) pos -= trace.size + } + + fun dump(os: PrintStream) { + val dis = Disassembler() + for (i in trace.indices) { + val i0 = (i + pos) % trace.size + val record = trace[i0] + if (record != null) { + os.println(record.report(dis)) + } + } + } +} \ No newline at end of file