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.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<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()
|
||||
var mbus = MemBus(65536)
|
||||
val tracer = Tracer()
|
||||
|
@@ -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
|
||||
|
@@ -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 <E> 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 <E> 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) }
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
@@ -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() { }
|
||||
|
@@ -77,29 +77,47 @@ class Unibus: PAddressSpace, Subregion(12, 6) {
|
||||
private val logger = LoggerFactory.getLogger(this.javaClass)
|
||||
|
||||
private val queue: Array<MutableList<InterruptSource>> = Array(8) { Vector(4) }
|
||||
private val devices: HashSet<Peripheral> = 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) {
|
||||
|
Reference in New Issue
Block a user