Additional debugging aids, fixed Obi-Wan error in PLF check in MMU

This commit is contained in:
2023-09-30 15:35:34 +02:00
parent fa7108098b
commit c8c8297765
3 changed files with 57 additions and 13 deletions

View File

@@ -979,17 +979,21 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
if (is_paddr_reg(spec)) { if (is_paddr_reg(spec)) {
// register // register
registers[addr.toInt()] = value registers[addr.toInt()] = value
} else if (addr and 1u != 0u) {
throw OddAddressError(addr)
} else { } else {
core.setw(addr.toUShort(), value, dspace) core.setw(addr.toUShort(), value, dspace)
} }
} }
private fun op_loadw(spec: UInt, dspace: Boolean=true): UShort { 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)) { val value = if (is_paddr_reg(spec)) {
registers[addr.toInt()] registers[addr.toInt()]
} else if (addr and 1u != 0u) {
throw OddAddressError(addr)
} else { } else {
core.getw(addr, dspace) core.getw(addr.toUShort(), dspace)
} }
if (spec bit PADDR_ARG_BIT) if (spec bit PADDR_ARG_BIT)
tracer.noteReference(spec, value) tracer.noteReference(spec, value)
@@ -1061,9 +1065,9 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
try { try {
// Check early traps // Check early traps
if (trapReq != 0) { if (trapReq != 0) {
for (cause in TrapReason.entries.reversed()) { for (cause in TrapReason.entries.asReversed()) {
if (trapReq and cause.mask != 0) { if (trapReq and cause.mask != 0) {
// logger.warn("Trapping because $cause") logger.trace("Trapping because {}", cause)
try { try {
callVector(cause.vector) callVector(cause.vector)
} finally { } finally {
@@ -1088,7 +1092,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
// we might have been waiting for an interrupt // we might have been waiting for an interrupt
runState = RunState.RUNNING runState = RunState.RUNNING
val vector = source.vector val vector = source.vector
mbus.unibus.logger.debug("DATIP: {} @ {}", vector.toOctal(), i) mbus.unibus.logger.trace("DATIP: {} @ {}", vector.toOctal(), i)
callVector(vector) callVector(vector)
source.handled() source.handled()
break break

View File

@@ -1,6 +1,11 @@
package com.thequux.mcpdp.core 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 BusTimeoutError(addr: UInt): MemoryError(MemoryErrorType.BusTimeout, addr)
class OddAddressError(addr: UInt): MemoryError(MemoryErrorType.OddAddress, addr) class OddAddressError(addr: UInt): MemoryError(MemoryErrorType.OddAddress, addr)
class NonExistentMemoryError(addr: UInt): MemoryError(MemoryErrorType.NonExistent, addr) class NonExistentMemoryError(addr: UInt): MemoryError(MemoryErrorType.NonExistent, addr)

View File

@@ -4,6 +4,8 @@ package com.thequux.mcpdp.core
import com.thequux.mcpdp.ext.bit.* import com.thequux.mcpdp.ext.bit.*
import com.thequux.mcpdp.peripheral.Unibus import com.thequux.mcpdp.peripheral.Unibus
import com.thequux.mcpdp.util.ProgrammerError import com.thequux.mcpdp.util.ProgrammerError
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import kotlin.math.max import kotlin.math.max
import kotlin.math.min 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) { get() = if (ed) {
(plf.toUInt() shl 6) ..< 0x2000u (plf.toUInt() shl 6) ..< 0x2000u
} else { } else {
0U..< (plf.toUInt() shl 6) 0U.. (plf.toUInt() shl 6+1) // +1 allows the last byte address
} }
val asU16: UShort 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 MEMORY_ERROR_REG: UInt = 0x3FFE4u
} }
private val logger = LoggerFactory.getLogger(this.javaClass)
private var mmr0: UShort = 0u private var mmr0: UShort = 0u
set(value) { set(value) {
@@ -105,7 +108,17 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace {
// check range // check range
if (addr and 0x1FFFU !in pdr.range) { if (addr and 0x1FFFU !in pdr.range) {
setMmr0(14, apf) 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) cpu.setTrap(TrapReason.MME)
// TODO: check whether this is always an abort // TODO: check whether this is always an abort
throw EndCycle() throw EndCycle()
@@ -114,11 +127,15 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace {
AccessAction.Allow -> {} AccessAction.Allow -> {}
AccessAction.Trap -> { AccessAction.Trap -> {
setMmr0(12, apf) setMmr0(12, apf)
if (logger.isTraceEnabled)
logger.trace("MME: ${if (write) "write" else "read"} trap")
cpu.setTrap(TrapReason.MME) cpu.setTrap(TrapReason.MME)
} }
AccessAction.Abort -> { AccessAction.Abort -> {
setMmr0(13, apf) setMmr0(13, apf)
cpu.setTrap(TrapReason.MME) cpu.setTrap(TrapReason.MME)
if (logger.isTraceEnabled)
logger.trace("MME: ${if (write) "write" else "read"} ABORT")
throw EndCycle() throw EndCycle()
} }
} }
@@ -163,7 +180,7 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace {
private val itabs: Array<PageTable> = Array(3) { PageTable(if (it == 2) 3 else it, dspace = false) } private val itabs: Array<PageTable> = Array(3) { PageTable(if (it == 2) 3 else it, dspace = false) }
private val dtabs: Array<PageTable> = Array(3) { PageTable(if (it == 2) 3 else it, dspace = true) } private val dtabs: Array<PageTable> = Array(3) { PageTable(if (it == 2) 3 else it, dspace = true) }
private val modeVTabs: Array<ModeVSpace> = Array(3) { ModeVSpace(itabs[it], dtabs[it], false) } private val modeVTabs: Array<ModeVSpace> = Array(3) { ModeVSpace(charArrayOf('K', 'S', 'U')[it], itabs[it], dtabs[it], false) }
private var noMmanSpace = NoMmanSpace() private var noMmanSpace = NoMmanSpace()
var modeSpace: VAddressSpace = noMmanSpace var modeSpace: VAddressSpace = noMmanSpace
private set private set
@@ -172,18 +189,25 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace {
private val unibusTable = UIntArray(32) 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 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 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) { override fun setw(addr: UShort, value: UShort, dspace: Boolean) {
pspace.setw(getSpace(dspace).map(addr, write = true), value) pspace.setw(getSpace(dspace).map(addr, write = true), value)
} }
override fun setb(addr: UShort, value: UByte) { 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) } 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 { override fun getw(addr: UInt): UShort {
val mode = addr.toInt() shr 4 and 3 val mode = addr.toInt() shr 4 and 3
val reg = addr.toInt() shr 1 and 7 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) { override fun setw(addr: UInt, value: UShort) {
val mode = addr.toInt() shr 4 and 3 val mode = addr.toInt() shr 4 and 3
val reg = addr.toInt() shr 1 and 7 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) { when (mode) {
0 -> ipt.pdr[reg] = PDR(value) // This clears A and W 0 -> ipt.pdr[reg] = PDR(value) // This clears A and W
1 -> dpt.pdr[reg] = PDR(value) // This clears A and W 1 -> dpt.pdr[reg] = PDR(value) // This clears A and W