diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 22c414e..8b3bd55 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -37,10 +37,11 @@ fun main(args: Array) { cpu.runState = CPU.RunState.RUNNING cpu.pc = 0x80u val start = System.nanoTime() - val ninsn = cpu.run(600000000) -// var ninsn = cpu.run(17405) -// cpu.tracer = tracer -// ninsn += cpu.run(30) +// var ninsn = cpu.run(600000000) + var ninsn = cpu.run(376670) + cpu.tracer = tracer + ninsn += cpu.run(30) + cpu.dumpReg() val end = System.nanoTime() System.err.println("Halted at 0${cpu.pc.toString(8)}") diff --git a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt index 5cf91cd..ebd7b50 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt @@ -9,7 +9,7 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import java.lang.StringBuilder -private enum class TrapReason(val vector: UShort, val load_mmr2: Boolean, val clear: Int) { +internal enum class TrapReason(val vector: UShort, val load_mmr2: Boolean, val clear: Int) { /** Floating point error */ FPE(0xA4u, true, 0), /** Power fail */ @@ -93,9 +93,9 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { mbus.unibus.reset() } // bus reset TODO: bus init 0x0006 -> { - // TODO: handle suspending the trace trap pc = stack_pop() psw = stack_pop() + allowT = false } // RTT in 0x40..0x7f -> { // jmp @@ -747,6 +747,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { } } + private var allowT: Boolean = true private var control_reg: UShort = 0u val logger: Logger = LoggerFactory.getLogger(this.javaClass) private val flagStr: String @@ -764,7 +765,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { private var stack_limit: UShort = 0u private var handlingStackRed: Boolean = false private var trapReq: Int = 0 - val core = PagingUnit(mbus) + val core = PagingUnit(mbus, this) var runState: RunState = RunState.HALTED var psw: UShort @@ -1005,10 +1006,12 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { fun step_int() { try { tracer.noteBegin(this) + core.newInsn(pc) val opcode = core.getw(pc).toInt() tracer.noteOpcode(opcode.toUShort()) pc = (pc + 2u).toUShort() this.(insnTable[opcode shr 8])(opcode) + core.endInsn() } finally { tracer.noteEnd() } @@ -1034,6 +1037,8 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { psw = core.getw(6u) core.setw(2u, psw) core.setw(0u, pc) + sp = 0u + trapReq = trapReq and TrapReason.RED.clear.inv() pc = core.getw(4u) } @@ -1046,8 +1051,11 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { for (cause in TrapReason.entries.reversed()) { if (trapReq and cause.mask != 0) { // logger.warn("Trapping because $cause") - callVector(cause.vector) - trapReq = trapReq and cause.clear.inv() and cause.mask.inv() + try { + callVector(cause.vector) + } finally { + trapReq = trapReq and cause.clear.inv() and cause.mask.inv() + } // TODO: load MMR2 if necessary break } @@ -1096,6 +1104,10 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { // Proceed to handling instruction try { step_int() + if (T && allowT) { + setTrap(TrapReason.TRC) + } + allowT = true } catch (error: MemoryError) { // TODO: fill in memory manager fields when (error) { @@ -1112,7 +1124,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) { @@ -1132,7 +1144,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { var ninsn: Long = 0 while (runState == RunState.RUNNING && ninsn < nstep) { ninsn++ - if (pc == 0x1F76u.toUShort()) { + if (pc == 0x344A.toUShort()) { pc = pc } step() @@ -1149,7 +1161,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { pc = core.getw(vector) } - private fun setTrap(reason: TrapReason) { + internal fun setTrap(reason: TrapReason) { trapReq = trapReq or reason.mask } @@ -1187,7 +1199,6 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { fun checkSP(addr: UShort): UShort { if (cur_mode != 0) return addr if (sp < stack_limit + 224u || sp.toInt() and 0xFFFE == 0xFFFE) { - logger.warn("Stack RED") trapRed() throw EndCycle() } else if (sp < stack_limit + 256u) { diff --git a/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt b/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt index e61ad79..be7814c 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt @@ -36,6 +36,9 @@ private data class PDR(val plf: UShort, var A: Boolean, var W: Boolean, var ed: } else { 0U..< (plf.toUInt() shl 6) } + + val asU16: UShort + get() = (plf shl 7).bit(7, A).bit(6, W).bit(3, ed) or acf.ordinal.toUShort() fun touched() { A = true } fun written() { A = true; W = true } } @@ -47,11 +50,11 @@ private enum class MManMode(val mmanEnable: Boolean, val addrMask: UInt, val hip } @OptIn(ExperimentalUnsignedTypes::class) -class PagingUnit(val pspace: PAddressSpace): VAddressSpace { +class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace { companion object { - private val MMR0: UInt = 0x3FF8Au - private val MMR1: UInt = 0x3FF8Cu - private val MMR2: UInt = 0x3FF8Eu + private val MMR0: UInt = 0x3FF7Au + private val MMR1: UInt = 0x3FF7Cu + private val MMR2: UInt = 0x3FF7Eu private val MMR3: UInt = 0x3F54Eu private val MEMORY_ERROR_REG: UInt = 0x3FFE4u } @@ -102,17 +105,20 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { if (addr and 0x1FFFU !in pdr.range) { setMmr0(14, apf) // TODO: handle rest of trap - throw Trap(0xA8) + cpu.setTrap(TrapReason.MME) + // TODO: check whether this is always an abort + throw EndCycle() } when (pdr.acf.action(write)) { AccessAction.Allow -> {} AccessAction.Trap -> { - setMmr0(12, apf, true) - trap = true + setMmr0(12, apf) + cpu.setTrap(TrapReason.MME) } AccessAction.Abort -> { setMmr0(13, apf) - throw Trap(0xA8) + cpu.setTrap(TrapReason.MME) + throw EndCycle() } } val tmp1 = addr.toUInt() + (par.toUInt() shl 6) and mapMode.addrMask @@ -210,8 +216,36 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { override fun setb(addr: UShort, value: UByte) = withRecovery(addr) { modeSpace.setb(addr, value) } + private class PdPair(val ipt: PageTable, val dpt: PageTable): PAddressSpace { + override fun getw(addr: UInt): UShort { + val mode = addr.toInt() shr 4 and 3 + val reg = addr.toInt() shr 1 and 7 + return when (mode) { + 0 -> ipt.pdr[reg].asU16 + 1 -> dpt.pdr[reg].asU16 + 2 -> ipt.par[reg] + 3 -> dpt.par[reg] + else -> throw BusTimeoutError(addr) + } + } + + override fun setw(addr: UInt, value: UShort) { + val mode = addr.toInt() shr 4 and 3 + val reg = addr.toInt() shr 1 and 7 + when (mode) { + 0 -> ipt.pdr[reg] = PDR(value) // This clears A and W + 1 -> dpt.pdr[reg] = PDR(value) // This clears A and W + 2 -> ipt.par[reg] = value + 3 -> dpt.par[reg] = value + else -> throw BusTimeoutError(addr) + } + } + + } + private inner class ConfigRegisters: PAddressSpace { + override fun getw(addr: UInt): UShort { return when (addr) { MMR0 -> mmr0 @@ -232,6 +266,12 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { override fun setw(addr: UInt, value: UShort): Unit { return when(addr) { + MMR0 -> { + mmr0 = value + updateMode() + } + MMR1 -> mmr1 = value + MMR2 -> mmr2 = value MMR3 -> { enableUnibusMap = value bit 5 enable22bit = value bit 4 @@ -260,16 +300,25 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { } + // Page space + // 772 200-217 = SUP I PDR + // 772 220-237 = SUP D PDR + // 772 240-257 = SUP I PAR + // 772 260-277 = SUP D PAR + // + // 772 300-377 = KRN same + // 777 600-677 = USR same + fun mount(unibus: Unibus) { val regs = ConfigRegisters() unibus.run { deviceView = UnibusMap() - attach(0x3_FF80u, 6, regs) // User PAR/PDR + attach(0x3_F480u, 6, PdPair(itabs[0], dtabs[0])) + attach(0x3_F4C0u, 6, PdPair(itabs[1], dtabs[1])) + attach(0x3_FF80u, 6, PdPair(itabs[2], dtabs[2])) // User PAR/PDR attach(0x3_FF7Au, 1, regs) // MMR0 attach(0x3_FF7Cu, 2, regs) // MMR1-2 attach(0x3_F54Eu, 1, regs) // MMR3 - attach(0x3_F4C0u, 6, regs) // Kernal PAR/PDF - attach(0x3_F480u, 6, regs) // Supervisor PAR/PDR attach(0x3_F080u, 7, regs) // Unibus map attach(MEMORY_ERROR_REG, 1, regs) } @@ -286,6 +335,10 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { } + fun endInsn() { + mmr0 = mmr0 or 0x70u + } + private inner class UnibusMap: PAddressSpace { // This implements an *18-bit* address space, for the view of unibus peripherals diff --git a/src/main/kotlin/com/thequux/mcpdp/peripheral/MemBus.kt b/src/main/kotlin/com/thequux/mcpdp/peripheral/MemBus.kt index fb716c6..20fa56c 100644 --- a/src/main/kotlin/com/thequux/mcpdp/peripheral/MemBus.kt +++ b/src/main/kotlin/com/thequux/mcpdp/peripheral/MemBus.kt @@ -38,7 +38,7 @@ class MemBus(val size: Int) : PAddressSpace { } override fun getw(addr: UInt): UShort { - if (size bit 0) { + if (addr bit 0) { throw OddAddressError(addr) } return when (addr.toInt()) { @@ -49,7 +49,7 @@ class MemBus(val size: Int) : PAddressSpace { } override fun setw(addr: UInt, value: UShort) { - if (size bit 0) { + if (addr bit 0) { throw OddAddressError(addr) } return when (addr.toInt()) {