Fixed all ASH and ASHC tests in EKBB
This commit is contained in:
8
NOTES.EKBB.md
Normal file
8
NOTES.EKBB.md
Normal file
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -1,4 +1,5 @@
|
|||||||
import ch.qos.logback.classic.LoggerContext
|
import ch.qos.logback.classic.LoggerContext
|
||||||
|
import ch.qos.logback.core.util.StatusPrinter
|
||||||
import com.thequux.mcpdp.core.CPU
|
import com.thequux.mcpdp.core.CPU
|
||||||
import com.thequux.mcpdp.debug.LoggingCollector
|
import com.thequux.mcpdp.debug.LoggingCollector
|
||||||
import com.thequux.mcpdp.debug.NullTracer
|
import com.thequux.mcpdp.debug.NullTracer
|
||||||
@@ -11,6 +12,14 @@ import java.io.File
|
|||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
|
|
||||||
|
// 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()
|
val tb = org.jline.terminal.TerminalBuilder.terminal()
|
||||||
var mbus = MemBus(65536)
|
var mbus = MemBus(65536)
|
||||||
val tracer = Tracer()
|
val tracer = Tracer()
|
||||||
|
@@ -43,7 +43,7 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) {
|
|||||||
} // RTI
|
} // RTI
|
||||||
0x0003 -> trap(0x0Cu) // BPT
|
0x0003 -> trap(0x0Cu) // BPT
|
||||||
0x0004 -> trap(0x10u) // IOT
|
0x0004 -> trap(0x10u) // IOT
|
||||||
0x0005 -> throw InvalidOpcodeException() // bus reset TODO: bus init
|
0x0005 -> mbus.unibus.reset() // bus reset TODO: bus init
|
||||||
0x0006 -> {
|
0x0006 -> {
|
||||||
// TODO: handle suspending the trace trap
|
// TODO: handle suspending the trace trap
|
||||||
pc = stack_pop()
|
pc = stack_pop()
|
||||||
@@ -226,7 +226,7 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) {
|
|||||||
when (opcode shr 6 and 3) {
|
when (opcode shr 6 and 3) {
|
||||||
0 -> { // MARK
|
0 -> { // MARK
|
||||||
val count = opcode and 0x3F
|
val count = opcode and 0x3F
|
||||||
sp = (sp + (2 * count).toUInt()).toUShort()
|
sp = (pc + (2 * count).toUInt()).toUShort()
|
||||||
pc = registers[5]
|
pc = registers[5]
|
||||||
registers[5] = stack_pop()
|
registers[5] = stack_pop()
|
||||||
} // MARK
|
} // 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
|
val src = registers[r].toShort().toInt() // two casts to sign extend
|
||||||
count = count sex 6
|
count = count sex 6
|
||||||
V = false
|
V = false
|
||||||
val res = if (count > 0) {
|
val res = when {
|
||||||
C = (src shl (count-1)) bit 15
|
count > 15 -> {
|
||||||
val shifted = if (count < 16) {
|
C = (count == 16 && src bit 0)
|
||||||
src shr 16-count
|
0
|
||||||
} else {
|
}
|
||||||
|
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
|
src
|
||||||
}
|
}
|
||||||
V = (shifted != 0) and (shifted != -1)
|
}.toShort()
|
||||||
src shl count
|
|
||||||
} else if (count < 0) {
|
|
||||||
count = -count
|
|
||||||
C = (src shr (count-1)) bit 0
|
|
||||||
src shr count
|
|
||||||
} else {
|
|
||||||
C = false
|
|
||||||
src
|
|
||||||
}
|
|
||||||
registers[r] = res.toUShort()
|
registers[r] = res.toUShort()
|
||||||
|
V = (src xor res.toInt()) bit 15
|
||||||
N = res < 0
|
N = res < 0
|
||||||
Z = res == 0
|
Z = res == 0.toShort()
|
||||||
} // ASH
|
} // ASH
|
||||||
insnTable[0x76] = { opcode -> // ASHC
|
insnTable[0x76] = { opcode -> // ASHC
|
||||||
val r = opcode shr 6 and 0x7
|
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
|
val src = (registers[r].toUInt() shl 16 or registers[r or 1].toUInt()).toInt() // two casts to sign extend
|
||||||
V = false
|
V = false
|
||||||
val res = if (count > 0) {
|
val res = if (count > 0) {
|
||||||
C = (src shl (count-1)) bit 31
|
C = (src shl (count - 1)) bit 31
|
||||||
val shifted = src shr 32-count
|
|
||||||
V = (shifted != 0) and (shifted != -1)
|
|
||||||
src shl count
|
src shl count
|
||||||
|
} else if (count == -32) {
|
||||||
|
C = src bit 31
|
||||||
|
src shr 16 shr 16
|
||||||
} else if (count < 0) {
|
} else if (count < 0) {
|
||||||
count = -count
|
count = -count
|
||||||
C = (src shr (count-1)) bit 0
|
C = (src shr (count-1)) bit 0
|
||||||
@@ -376,10 +384,11 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) {
|
|||||||
C = false
|
C = false
|
||||||
src
|
src
|
||||||
}
|
}
|
||||||
registers[r] = (res and 0xFFFF).toUShort()
|
registers[r] = (res shr 16).toUShort()
|
||||||
registers[r or 1] = (res shr 16 and 0xFFFF).toUShort()
|
registers[r or 1] = (res).toUShort()
|
||||||
N = res < 0
|
N = res < 0
|
||||||
Z = res == 0
|
Z = res == 0
|
||||||
|
V = (src xor res) bit 31
|
||||||
} // ASHC
|
} // ASHC
|
||||||
insnTable[0x78] = {opcode -> // XOR
|
insnTable[0x78] = {opcode -> // XOR
|
||||||
val r = opcode shr 6 and 7
|
val r = opcode shr 6 and 7
|
||||||
|
@@ -4,6 +4,7 @@ package com.thequux.mcpdp.core
|
|||||||
import com.thequux.mcpdp.ext.bit.bic
|
import com.thequux.mcpdp.ext.bit.bic
|
||||||
import com.thequux.mcpdp.ext.bit.bit
|
import com.thequux.mcpdp.ext.bit.bit
|
||||||
import com.thequux.mcpdp.ext.bit.shr
|
import com.thequux.mcpdp.ext.bit.shr
|
||||||
|
import com.thequux.mcpdp.ext.bit.toOctal
|
||||||
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 kotlin.math.max
|
import kotlin.math.max
|
||||||
@@ -60,10 +61,19 @@ private enum class MManMode(val mmanEnable: Boolean, val addrMask: UInt, val hip
|
|||||||
|
|
||||||
@OptIn(ExperimentalUnsignedTypes::class)
|
@OptIn(ExperimentalUnsignedTypes::class)
|
||||||
class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
|
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 mmr = UShortArray(4)
|
||||||
private var enableUnibusMap: Boolean = false
|
private var enableUnibusMap: Boolean = false
|
||||||
private var enable22bit: Boolean = false
|
private var enable22bit: Boolean = false
|
||||||
|
var memErrorReg: UShort = 0u
|
||||||
private var mapMode: MManMode = MManMode.MM_16
|
private var mapMode: MManMode = MManMode.MM_16
|
||||||
|
|
||||||
/// The 18-bit address space exposed to peripherals
|
/// 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)
|
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 <E> withRecovery(addr: UShort, op: PagingUnit.() -> E): E {
|
private fun <E> withRecovery(addr: UShort, op: PagingUnit.() -> E): E {
|
||||||
try {
|
try {
|
||||||
return this.op()
|
return this.op()
|
||||||
@@ -197,40 +200,50 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
|
|||||||
|
|
||||||
private inner class ConfigRegisters: PAddressSpace {
|
private inner class ConfigRegisters: PAddressSpace {
|
||||||
|
|
||||||
override fun getw(addr: UInt): UShort = when (addr) {
|
override fun getw(addr: UInt): UShort {
|
||||||
MMR0 -> mmr[0]
|
return when (addr) {
|
||||||
MMR1 -> mmr[1]
|
MMR0 -> mmr[0]
|
||||||
MMR2 -> mmr[2]
|
MMR1 -> mmr[1]
|
||||||
MMR3 -> {
|
MMR2 -> mmr[2]
|
||||||
(0U.bit(0, modeVTabs[2].useDSpace)
|
MMR3 -> {
|
||||||
.bit(1, modeVTabs[1].useDSpace)
|
(0U.bit(0, modeVTabs[2].useDSpace)
|
||||||
.bit(2, modeVTabs[0].useDSpace)
|
.bit(1, modeVTabs[1].useDSpace)
|
||||||
.bit(4, enable22bit)
|
.bit(2, modeVTabs[0].useDSpace)
|
||||||
.bit(5, enableUnibusMap)
|
.bit(4, enable22bit)
|
||||||
.toUShort())
|
.bit(5, enableUnibusMap)
|
||||||
} // 772516 MMR3
|
.toUShort())
|
||||||
else -> throw BusTimeoutError(addr)
|
} // 772516 MMR3
|
||||||
|
MEMORY_ERROR_REG -> memErrorReg
|
||||||
|
else -> throw BusTimeoutError(addr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setw(addr: UInt, value: UShort): Unit = when(addr) {
|
override fun setw(addr: UInt, value: UShort): Unit {
|
||||||
MMR3 -> {
|
return when(addr) {
|
||||||
enableUnibusMap = value bit 5
|
MMR3 -> {
|
||||||
enable22bit = value bit 4
|
enableUnibusMap = value bit 5
|
||||||
modeVTabs[0].useDSpace = value bit 2
|
enable22bit = value bit 4
|
||||||
modeVTabs[1].useDSpace = value bit 1
|
modeVTabs[0].useDSpace = value bit 2
|
||||||
modeVTabs[2].useDSpace = value bit 0
|
modeVTabs[1].useDSpace = value bit 1
|
||||||
updateMode()
|
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)
|
|
||||||
}
|
}
|
||||||
} // 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_F4C0u, 6, regs) // Kernal PAR/PDF
|
||||||
attach(0x3_F480u, 6, regs) // Supervisor PAR/PDR
|
attach(0x3_F480u, 6, regs) // Supervisor PAR/PDR
|
||||||
attach(0x3_F080u, 7, regs) // Unibus map
|
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))
|
private inline fun <E> catchMemoryError(fn: () -> E): E = try {
|
||||||
override fun getb(addr: UInt): UByte = pspace.getb(map(addr))
|
fn()
|
||||||
|
} catch (e: MemoryError) {
|
||||||
override fun setw(addr: UInt, value: UShort) = pspace.setw(map(addr), value)
|
memErrorReg = memErrorReg or 0x400u
|
||||||
override fun setb(addr: UInt, value: UByte) = pspace.setb(map(addr), value)
|
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) }
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -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.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.bic(n: Int): Int = this and (1 shl n).inv()
|
||||||
/*inline*/ infix fun Int.sex(n: Int): Int {
|
/*inline*/ infix fun Int.sex(n: Int): Int {
|
||||||
val sign = 1 shl n+1
|
val sign = this and (1 shl n-1)
|
||||||
return ((this and sign.dec()) - (this and sign))
|
return this or -sign
|
||||||
}
|
}
|
||||||
/*inline*/ infix fun UInt.bit(n: Int): Boolean = this shr n and 1U != 0U
|
/*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
|
/*inline*/ fun UInt.bit(n: Int, v: Boolean): UInt = if (v) this bis n else this bic n
|
||||||
|
@@ -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)
|
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) {
|
override fun mount(bus: Unibus) {
|
||||||
bus.attach(reg_base, 3, this)
|
bus.attach(reg_base, 3, this)
|
||||||
|
bus.addDevice(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun service() { }
|
override fun service() { }
|
||||||
|
@@ -77,29 +77,47 @@ class Unibus: PAddressSpace, Subregion(12, 6) {
|
|||||||
private val logger = LoggerFactory.getLogger(this.javaClass)
|
private val logger = LoggerFactory.getLogger(this.javaClass)
|
||||||
|
|
||||||
private val queue: Array<MutableList<InterruptSource>> = Array(8) { Vector(4) }
|
private val queue: Array<MutableList<InterruptSource>> = Array(8) { Vector(4) }
|
||||||
|
private val devices: HashSet<Peripheral> = HashSet()
|
||||||
private var interruptCount: Int = 0
|
private var interruptCount: Int = 0
|
||||||
val interruptPending: Boolean
|
val interruptPending: Boolean
|
||||||
get() = interruptCount > 0
|
get() = interruptCount > 0
|
||||||
|
|
||||||
override fun map(address: UInt): PAddressSpace =
|
override fun map(address: UInt): PAddressSpace =
|
||||||
super.map(address) ?: throw BusTimeoutError(address)
|
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 {
|
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)
|
return map(addr).getw(addr)
|
||||||
}
|
}
|
||||||
override fun getb(addr: UInt): UByte {
|
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)
|
return map(addr).getb(addr)
|
||||||
}
|
}
|
||||||
override fun setw(addr: UInt, value: UShort) {
|
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)
|
map(addr).setw(addr, value)
|
||||||
}
|
}
|
||||||
override fun setb(addr: UInt, value: UByte) {
|
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)
|
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
|
/// Request that the processor service an interrupt. When the interrupt is handled, calls getVector() on the device
|
||||||
/// to fetch the currently desired interrupt vector
|
/// to fetch the currently desired interrupt vector
|
||||||
fun assertInterrupt(priority: Int, device: InterruptSource) {
|
fun assertInterrupt(priority: Int, device: InterruptSource) {
|
||||||
|
Reference in New Issue
Block a user