diff --git a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt index 3124ff1..041549c 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt @@ -979,17 +979,21 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { if (is_paddr_reg(spec)) { // register registers[addr.toInt()] = value + } else if (addr and 1u != 0u) { + throw OddAddressError(addr) } else { core.setw(addr.toUShort(), value, dspace) } } private fun op_loadw(spec: UInt, dspace: Boolean=true): UShort { - val addr = (spec and 0xFFFFu).toUShort() + val addr = (spec and 0xFFFFu) val value = if (is_paddr_reg(spec)) { registers[addr.toInt()] + } else if (addr and 1u != 0u) { + throw OddAddressError(addr) } else { - core.getw(addr, dspace) + core.getw(addr.toUShort(), dspace) } if (spec bit PADDR_ARG_BIT) tracer.noteReference(spec, value) @@ -1061,9 +1065,9 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) { try { // Check early traps if (trapReq != 0) { - for (cause in TrapReason.entries.reversed()) { + for (cause in TrapReason.entries.asReversed()) { if (trapReq and cause.mask != 0) { -// logger.warn("Trapping because $cause") + logger.trace("Trapping because {}", cause) try { callVector(cause.vector) } finally { @@ -1088,7 +1092,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 - mbus.unibus.logger.debug("DATIP: {} @ {}", vector.toOctal(), i) + mbus.unibus.logger.trace("DATIP: {} @ {}", vector.toOctal(), i) callVector(vector) source.handled() break diff --git a/src/main/kotlin/com/thequux/mcpdp/core/MemoryError.kt b/src/main/kotlin/com/thequux/mcpdp/core/MemoryError.kt index a962717..4417593 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/MemoryError.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/MemoryError.kt @@ -1,6 +1,11 @@ package com.thequux.mcpdp.core -sealed class MemoryError(val type: MemoryErrorType, var addr: UInt): Exception("Memory error: $type at ${addr.toString(8)}") +sealed class MemoryError(val type: MemoryErrorType, var addr: UInt): Exception("Memory error: $type at ${addr.toString(8)}") { + override fun fillInStackTrace(): Throwable { + // we don't want stack traces here, as they drastically slow down the emulator. + return this + } +} class BusTimeoutError(addr: UInt): MemoryError(MemoryErrorType.BusTimeout, addr) class OddAddressError(addr: UInt): MemoryError(MemoryErrorType.OddAddress, addr) class NonExistentMemoryError(addr: UInt): MemoryError(MemoryErrorType.NonExistent, addr) diff --git a/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt b/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt index 1e04611..c7194c4 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt @@ -4,6 +4,8 @@ package com.thequux.mcpdp.core import com.thequux.mcpdp.ext.bit.* import com.thequux.mcpdp.peripheral.Unibus import com.thequux.mcpdp.util.ProgrammerError +import org.slf4j.Logger +import org.slf4j.LoggerFactory import kotlin.math.max import kotlin.math.min @@ -35,7 +37,7 @@ private data class PDR(val plf: UShort, var A: Boolean, var W: Boolean, var ed: get() = if (ed) { (plf.toUInt() shl 6) ..< 0x2000u } else { - 0U..< (plf.toUInt() shl 6) + 0U.. (plf.toUInt() shl 6+1) // +1 allows the last byte address } val asU16: UShort @@ -60,6 +62,7 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace { private val MEMORY_ERROR_REG: UInt = 0x3FFE4u } + private val logger = LoggerFactory.getLogger(this.javaClass) private var mmr0: UShort = 0u set(value) { @@ -105,7 +108,17 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace { // check range if (addr and 0x1FFFU !in pdr.range) { setMmr0(14, apf) - // TODO: handle rest of trap + if (logger.isTraceEnabled) { + val prv = when (mode) { + 0 -> 'K' + 1 -> 'S' + 2, 3 -> 'U' + else -> '?' + } + val spc = if (dspace) 'D' else 'I' + + logger.trace("MME: Page range error on page $apf: ${prv}${spc}PDR${apf}=$pdr") + } cpu.setTrap(TrapReason.MME) // TODO: check whether this is always an abort throw EndCycle() @@ -114,11 +127,15 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace { AccessAction.Allow -> {} AccessAction.Trap -> { setMmr0(12, apf) + if (logger.isTraceEnabled) + logger.trace("MME: ${if (write) "write" else "read"} trap") cpu.setTrap(TrapReason.MME) } AccessAction.Abort -> { setMmr0(13, apf) cpu.setTrap(TrapReason.MME) + if (logger.isTraceEnabled) + logger.trace("MME: ${if (write) "write" else "read"} ABORT") throw EndCycle() } } @@ -163,7 +180,7 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace { private val itabs: Array = Array(3) { PageTable(if (it == 2) 3 else it, dspace = false) } private val dtabs: Array = Array(3) { PageTable(if (it == 2) 3 else it, dspace = true) } - private val modeVTabs: Array = Array(3) { ModeVSpace(itabs[it], dtabs[it], false) } + private val modeVTabs: Array = Array(3) { ModeVSpace(charArrayOf('K', 'S', 'U')[it], itabs[it], dtabs[it], false) } private var noMmanSpace = NoMmanSpace() var modeSpace: VAddressSpace = noMmanSpace private set @@ -172,18 +189,25 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace { private val unibusTable = UIntArray(32) - private inner class ModeVSpace(private val iSpace: PageTable, private val dSpace: PageTable, var useDSpace: Boolean): VAddressSpace { + private inner class ModeVSpace(val mode: Char, private val iSpace: PageTable, private val dSpace: PageTable, useDSpace: Boolean): VAddressSpace { + var useDSpace = useDSpace + set(value) { + if (value != field) { + logger.trace("$mode ${if (value) "now " else "not "}using dspace") + } + field = value + } private fun getSpace(dspace: Boolean): PageTable = if (dspace && useDSpace) dSpace else iSpace override fun getw(addr: UShort, dspace: Boolean): UShort = pspace.getw(getSpace(dspace).map(addr, write = false)) - override fun getb(addr: UShort): UByte = pspace.getb(dSpace.map(addr, write = false)) + override fun getb(addr: UShort): UByte = pspace.getb(getSpace(true).map(addr, write = false)) override fun setw(addr: UShort, value: UShort, dspace: Boolean) { pspace.setw(getSpace(dspace).map(addr, write = true), value) } override fun setb(addr: UShort, value: UByte) { - pspace.setb(dSpace.map(addr, write = true), value) + pspace.setb(getSpace(true).map(addr, write = true), value) } } @@ -217,7 +241,7 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace { override fun setb(addr: UShort, value: UByte) = withRecovery(addr) { modeSpace.setb(addr, value) } - private class PdPair(val ipt: PageTable, val dpt: PageTable): PAddressSpace { + private inner 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 @@ -233,6 +257,17 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace { override fun setw(addr: UInt, value: UShort) { val mode = addr.toInt() shr 4 and 3 val reg = addr.toInt() shr 1 and 7 + if (mode < 2) { + val prv = when (ipt.mode) { + 0 -> 'K' + 1 -> 'S' + 2,3 -> 'U' + else -> '?' + } + val spc = if (mode == 0) 'I' else 'D' + if (logger.isTraceEnabled) + logger.trace("${prv}${spc}PDR${reg} := ${PDR(value)}") + } when (mode) { 0 -> ipt.pdr[reg] = PDR(value) // This clears A and W 1 -> dpt.pdr[reg] = PDR(value) // This clears A and W