diff --git a/NOTES.EKBB.md b/NOTES.EKBB.md new file mode 100644 index 0000000..a886d7e --- /dev/null +++ b/NOTES.EKBB.md @@ -0,0 +1,8 @@ +# Test 3 +tests reset insn + +## RACF E8 BAD +triggered by printer interrupt; unknown root cause. Apparently need to examine DL11 docs to see how it handles RESET + + + diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index c331f9b..12fead2 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,4 +1,5 @@ import ch.qos.logback.classic.LoggerContext +import ch.qos.logback.core.util.StatusPrinter import com.thequux.mcpdp.core.CPU import com.thequux.mcpdp.debug.LoggingCollector import com.thequux.mcpdp.debug.NullTracer @@ -11,6 +12,14 @@ import java.io.File fun main(args: Array) { +// val lc: LoggerContext = LoggerFactory.getILoggerFactory() as LoggerContext +// StatusPrinter.print(lc) + + // print system properties +// for ((name, value) in System.getProperties()) { +// println("${name}=${value}") +// } + val tb = org.jline.terminal.TerminalBuilder.terminal() var mbus = MemBus(65536) val tracer = Tracer() diff --git a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt index 97c3ad6..19d875f 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt @@ -43,7 +43,7 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) { } // RTI 0x0003 -> trap(0x0Cu) // BPT 0x0004 -> trap(0x10u) // IOT - 0x0005 -> throw InvalidOpcodeException() // bus reset TODO: bus init + 0x0005 -> mbus.unibus.reset() // bus reset TODO: bus init 0x0006 -> { // TODO: handle suspending the trace trap pc = stack_pop() @@ -226,7 +226,7 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) { when (opcode shr 6 and 3) { 0 -> { // MARK val count = opcode and 0x3F - sp = (sp + (2 * count).toUInt()).toUShort() + sp = (pc + (2 * count).toUInt()).toUShort() pc = registers[5] registers[5] = stack_pop() } // MARK @@ -337,26 +337,33 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) { val src = registers[r].toShort().toInt() // two casts to sign extend count = count sex 6 V = false - val res = if (count > 0) { - C = (src shl (count-1)) bit 15 - val shifted = if (count < 16) { - src shr 16-count - } else { + val res = when { + count > 15 -> { + C = (count == 16 && src bit 0) + 0 + } + count > 0 -> { + C = src bit 16-count + src shl count + } + count < -15 -> { + C = src bit 15 + src shr 8 shr 8 + } + count < 0 -> { + count = -count + C = src bit (count-1) + src shr count + } + else -> { + C = false src } - V = (shifted != 0) and (shifted != -1) - src shl count - } else if (count < 0) { - count = -count - C = (src shr (count-1)) bit 0 - src shr count - } else { - C = false - src - } + }.toShort() registers[r] = res.toUShort() + V = (src xor res.toInt()) bit 15 N = res < 0 - Z = res == 0 + Z = res == 0.toShort() } // ASH insnTable[0x76] = { opcode -> // ASHC val r = opcode shr 6 and 0x7 @@ -364,10 +371,11 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) { val src = (registers[r].toUInt() shl 16 or registers[r or 1].toUInt()).toInt() // two casts to sign extend V = false val res = if (count > 0) { - C = (src shl (count-1)) bit 31 - val shifted = src shr 32-count - V = (shifted != 0) and (shifted != -1) + C = (src shl (count - 1)) bit 31 src shl count + } else if (count == -32) { + C = src bit 31 + src shr 16 shr 16 } else if (count < 0) { count = -count C = (src shr (count-1)) bit 0 @@ -376,10 +384,11 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) { C = false src } - registers[r] = (res and 0xFFFF).toUShort() - registers[r or 1] = (res shr 16 and 0xFFFF).toUShort() + registers[r] = (res shr 16).toUShort() + registers[r or 1] = (res).toUShort() N = res < 0 Z = res == 0 + V = (src xor res) bit 31 } // ASHC insnTable[0x78] = {opcode -> // XOR val r = opcode shr 6 and 7 diff --git a/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt b/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt index a6b51ca..196f775 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/PagingUnit.kt @@ -4,6 +4,7 @@ package com.thequux.mcpdp.core import com.thequux.mcpdp.ext.bit.bic import com.thequux.mcpdp.ext.bit.bit import com.thequux.mcpdp.ext.bit.shr +import com.thequux.mcpdp.ext.bit.toOctal import com.thequux.mcpdp.peripheral.Unibus import com.thequux.mcpdp.util.ProgrammerError import kotlin.math.max @@ -60,10 +61,19 @@ private enum class MManMode(val mmanEnable: Boolean, val addrMask: UInt, val hip @OptIn(ExperimentalUnsignedTypes::class) class PagingUnit(val pspace: PAddressSpace): VAddressSpace { + companion object { + private val MMR0: UInt = 0x3FF8Au + private val MMR1: UInt = 0x3FF8Cu + private val MMR2: UInt = 0x3FF8Eu + private val MMR3: UInt = 0x3F54Eu + private val MEMORY_ERROR_REG: UInt = 0x3FFE4u + } + private var mmr = UShortArray(4) private var enableUnibusMap: Boolean = false private var enable22bit: Boolean = false + var memErrorReg: UShort = 0u private var mapMode: MManMode = MManMode.MM_16 /// The 18-bit address space exposed to peripherals @@ -172,13 +182,6 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { override fun setw(addr: UShort, value: UShort, dspace: Boolean) = pspace.setw(map(addr), value) } - companion object { - private val MMR0: UInt = 0x3FF8Au - private val MMR1: UInt = 0x3FF8Cu - private val MMR2: UInt = 0x3FF8Eu - private val MMR3: UInt = 0x3F54Eu - } - private fun withRecovery(addr: UShort, op: PagingUnit.() -> E): E { try { return this.op() @@ -197,40 +200,50 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { private inner class ConfigRegisters: PAddressSpace { - override fun getw(addr: UInt): UShort = when (addr) { - MMR0 -> mmr[0] - MMR1 -> mmr[1] - MMR2 -> mmr[2] - MMR3 -> { - (0U.bit(0, modeVTabs[2].useDSpace) - .bit(1, modeVTabs[1].useDSpace) - .bit(2, modeVTabs[0].useDSpace) - .bit(4, enable22bit) - .bit(5, enableUnibusMap) - .toUShort()) - } // 772516 MMR3 - else -> throw BusTimeoutError(addr) + override fun getw(addr: UInt): UShort { + return when (addr) { + MMR0 -> mmr[0] + MMR1 -> mmr[1] + MMR2 -> mmr[2] + MMR3 -> { + (0U.bit(0, modeVTabs[2].useDSpace) + .bit(1, modeVTabs[1].useDSpace) + .bit(2, modeVTabs[0].useDSpace) + .bit(4, enable22bit) + .bit(5, enableUnibusMap) + .toUShort()) + } // 772516 MMR3 + MEMORY_ERROR_REG -> memErrorReg + else -> throw BusTimeoutError(addr) + } } - override fun setw(addr: UInt, value: UShort): Unit = when(addr) { - MMR3 -> { - enableUnibusMap = value bit 5 - enable22bit = value bit 4 - modeVTabs[0].useDSpace = value bit 2 - modeVTabs[1].useDSpace = value bit 1 - modeVTabs[2].useDSpace = value bit 0 - updateMode() - } - in 0x3F080u..0x3F0FFu -> { - val uaddr = (addr shr 1 and 31u).toInt() - val hiWord = addr bit 1 - if (hiWord) { - unibusTable[uaddr] = unibusTable[uaddr] and 0xFFFFu or (value.toUInt() and 0x3Fu shl 16) - } else { - unibusTable[uaddr] = unibusTable[uaddr] and 0xFFFF_0000u or (value.toUInt() bic 0) + override fun setw(addr: UInt, value: UShort): Unit { + return when(addr) { + MMR3 -> { + enableUnibusMap = value bit 5 + enable22bit = value bit 4 + modeVTabs[0].useDSpace = value bit 2 + modeVTabs[1].useDSpace = value bit 1 + modeVTabs[2].useDSpace = value bit 0 + updateMode() } - } // 770200..770377 Unibus map - else -> throw BusTimeoutError(addr) + + MEMORY_ERROR_REG -> { + memErrorReg = memErrorReg and value.inv() + } + + in 0x3F080u..0x3F0FFu -> { + val uaddr = (addr shr 1 and 31u).toInt() + val hiWord = addr bit 1 + if (hiWord) { + unibusTable[uaddr] = unibusTable[uaddr] and 0xFFFFu or (value.toUInt() and 0x3Fu shl 16) + } else { + unibusTable[uaddr] = unibusTable[uaddr] and 0xFFFF_0000u or (value.toUInt() bic 0) + } + } // 770200..770377 Unibus map + else -> throw BusTimeoutError(addr) + } } } @@ -246,6 +259,7 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { 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) } } @@ -265,12 +279,18 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace { } } - override fun getw(addr: UInt): UShort = pspace.getw(map(addr)) - override fun getb(addr: UInt): UByte = pspace.getb(map(addr)) - - override fun setw(addr: UInt, value: UShort) = pspace.setw(map(addr), value) - override fun setb(addr: UInt, value: UByte) = pspace.setb(map(addr), value) + private inline fun catchMemoryError(fn: () -> E): E = try { + fn() + } catch (e: MemoryError) { + memErrorReg = memErrorReg or 0x400u + throw e + } + override fun getw(addr: UInt): UShort = catchMemoryError { pspace.getw(map(addr)) } + override fun getb(addr: UInt): UByte = catchMemoryError { pspace.getb(map(addr)) } + + override fun setw(addr: UInt, value: UShort) = catchMemoryError { pspace.setw(map(addr), value) } + override fun setb(addr: UInt, value: UByte) = catchMemoryError { pspace.setb(map(addr), value) } } } \ No newline at end of file diff --git a/src/main/kotlin/com/thequux/mcpdp/ext/bit/bitext.kt b/src/main/kotlin/com/thequux/mcpdp/ext/bit/bitext.kt index 359e369..ae212d0 100644 --- a/src/main/kotlin/com/thequux/mcpdp/ext/bit/bitext.kt +++ b/src/main/kotlin/com/thequux/mcpdp/ext/bit/bitext.kt @@ -57,8 +57,8 @@ import kotlin.math.min /*inline*/ infix fun Int.bis(n: Int): Int = this.or(1 shl n) /*inline*/ infix fun Int.bic(n: Int): Int = this and (1 shl n).inv() /*inline*/ infix fun Int.sex(n: Int): Int { - val sign = 1 shl n+1 - return ((this and sign.dec()) - (this and sign)) + val sign = this and (1 shl n-1) + return this or -sign } /*inline*/ infix fun UInt.bit(n: Int): Boolean = this shr n and 1U != 0U /*inline*/ fun UInt.bit(n: Int, v: Boolean): UInt = if (v) this bis n else this bic n diff --git a/src/main/kotlin/com/thequux/mcpdp/peripheral/DL11.kt b/src/main/kotlin/com/thequux/mcpdp/peripheral/DL11.kt index 194f410..c81abf7 100644 --- a/src/main/kotlin/com/thequux/mcpdp/peripheral/DL11.kt +++ b/src/main/kotlin/com/thequux/mcpdp/peripheral/DL11.kt @@ -39,8 +39,18 @@ class DL11(private var istr: InputStream, private val ostr: OutputStream, val re constructor(unibus: Unibus, istr: InputStream, ostr: OutputStream): this(istr, ostr, 0x3FF70u, 0x30u, unibus) + override fun reset() { + rcsr = 0x0u + rcsr = 0x0u +// xcsr = 0x80u + + intrRcv.level = false + intrXmit.level = false + } + override fun mount(bus: Unibus) { bus.attach(reg_base, 3, this) + bus.addDevice(this) } override fun service() { } diff --git a/src/main/kotlin/com/thequux/mcpdp/peripheral/Unibus.kt b/src/main/kotlin/com/thequux/mcpdp/peripheral/Unibus.kt index 54cec8b..5d2b6bc 100644 --- a/src/main/kotlin/com/thequux/mcpdp/peripheral/Unibus.kt +++ b/src/main/kotlin/com/thequux/mcpdp/peripheral/Unibus.kt @@ -77,29 +77,47 @@ class Unibus: PAddressSpace, Subregion(12, 6) { private val logger = LoggerFactory.getLogger(this.javaClass) private val queue: Array> = Array(8) { Vector(4) } + private val devices: HashSet = HashSet() private var interruptCount: Int = 0 val interruptPending: Boolean get() = interruptCount > 0 override fun map(address: UInt): PAddressSpace = super.map(address) ?: throw BusTimeoutError(address) + + private fun shouldTrace(addr: UInt): Boolean { + if (!logger.isTraceEnabled) return false + if (addr and 0x3FFF8u == 0x3FF70u) return false + return true + } + override fun getw(addr: UInt): UShort { - if (logger.isTraceEnabled) logger.trace("DATIW ${addr.toOctal()}") + if (shouldTrace(addr)) logger.trace("DATIW ${addr.toOctal()}") return map(addr).getw(addr) } override fun getb(addr: UInt): UByte { - if (logger.isTraceEnabled) logger.trace("DATIB ${addr.toOctal()}") + if (shouldTrace(addr)) logger.trace("DATIB ${addr.toOctal()}") return map(addr).getb(addr) } override fun setw(addr: UInt, value: UShort) { - if (logger.isTraceEnabled) logger.trace("DATOW ${addr.toOctal()} <- ${value.toOctal()}") + if (shouldTrace(addr)) logger.trace("DATOW ${addr.toOctal()} <- ${value.toOctal()}") map(addr).setw(addr, value) } override fun setb(addr: UInt, value: UByte) { - if (logger.isTraceEnabled) logger.trace("DATOB ${addr.toOctal()} <- ${value.toOctal()}") + if (shouldTrace(addr)) logger.trace("DATOB ${addr.toOctal()} <- ${value.toOctal()}") map(addr).setb(addr, value) } + fun reset() { + for (dev in devices) { + dev.reset() + } + } + + fun addDevice(dev: Peripheral) { + devices.add(dev) + } + /// Request that the processor service an interrupt. When the interrupt is handled, calls getVector() on the device /// to fetch the currently desired interrupt vector fun assertInterrupt(priority: Int, device: InterruptSource) {