A bunch of fixes; gets all the way to test 26

This commit is contained in:
2023-09-27 17:54:06 +02:00
parent dfeb859ac3
commit 78dbcd8500
4 changed files with 134 additions and 30 deletions

View File

@@ -4,5 +4,7 @@ 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
# Test 014
## PC=12136 CC's did not load properly
This is actually a bug in the exerciser:

View File

@@ -37,7 +37,10 @@ fun main(args: Array<String>) {
cpu.runState = CPU.RunState.RUNNING
cpu.pc = 0x80u
val start = System.nanoTime()
val ninsn = cpu.run(600000000)
// val ninsn = cpu.run(600000000)
var ninsn = cpu.run(30000)
// cpu.tracer = tracer
// ninsn += cpu.run(100)
val end = System.nanoTime()
System.err.println("Halted at 0${cpu.pc.toString(8)}")

View File

@@ -2,7 +2,6 @@ package com.thequux.mcpdp.core
import com.thequux.mcpdp.ext.bit.*
import com.thequux.mcpdp.peripheral.MemBus
import com.thequux.mcpdp.debug.Disassembler
import com.thequux.mcpdp.debug.ITracer
import com.thequux.mcpdp.debug.NullTracer
import com.thequux.mcpdp.util.ProgrammerError
@@ -17,7 +16,7 @@ import java.lang.StringBuilder
/// Exxx: ROM
/// xxxx: rest
@OptIn(ExperimentalUnsignedTypes::class)
class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) {
class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
companion object {
val PADDR_REG_BIT: Int = 23
@@ -230,8 +229,38 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) {
pc = registers[5]
registers[5] = stack_pop()
} // MARK
1 -> { throw InvalidOpcodeException() } // MFPI // TODO
2 -> { throw InvalidOpcodeException() } // MTPI // TODO
1 -> {
val src = opc_dst(opcode)
val v = if (is_paddr_reg(src)) {
if (src and 7u == 6u && prv_mode != cur_mode) {
shadow_r6[prv_mode]
} else
registers[src.toInt() and 7]
} else {
// memory ref
core.getSpace(prv_mode).getw(src.toUShort(), dspace = false)
}
stack_push(v)
N = v bit 15
Z = v == 0u.toUShort()
V = false
} // MFPI // TODO
2 -> {
val v = stack_pop()
val dest = opc_dst(opcode)
if (is_paddr_reg(dest)) {
if (dest and 7u == 6u && prv_mode != cur_mode) {
shadow_r6[prv_mode] = v
} else
registers[dest.toInt() and 7] = v
} else {
// memory ref
core.getSpace(prv_mode).setw(dest.toUShort(), v, dspace = false)
}
N = v bit 15
Z = v == 0u.toUShort()
V = false
} // MTPI // TODO
3 -> {
op_storw(opc_dst(opcode), if (N) (-1).toUShort() else 0.toUShort())
Z = !N
@@ -305,28 +334,49 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) {
insnTable[0x70] = { opcode -> // MUL
val r = opcode shr 6 and 0x7
val src = op_loadw(opc_dst(opcode)).toShort().toInt()
val res = registers[r].toShort().toInt() * src
registers[r bis 1] = (res shr 16).toUShort()
registers[r] = res.toUShort()
val src2 = registers[r].toShort().toInt()
val res = src2 * src
registers[r] = (res shr 16 and 0xFFFF).toUShort()
registers[r bis 0] = (res and 0xFFFF).toUShort()
N = res bit 31
Z = res == 0
V = false
C = (res shr 16) == -(res shr 15 and 1) // check if overflow extends the sign bit
C = (res < -0x8000 || res > 0x7FFF) // check if overflow extends the sign bit
} // MUL
insnTable[0x72] = { opcode -> // DIV
val r = opcode shr 6 and 0x7
val src = op_loadw(opc_dst(opcode)).toInt()
val lho = (registers[r].toUInt() shl 16 or registers[r bis 1].toUInt()).toInt()
if (src != 0) {
val quot = lho / src
val rem = lho % src
registers[r] = quot.toUShort()
registers[r bis 1] = rem.toUShort()
val overflow = quot shr 16
V = overflow == -(quot shr 15 and 1) // check if overflow extends the sign bit
val divisor = op_loadw(opc_dst(opcode)).toShort().toInt()
val dividend = registers[r].toInt() shl 16 or registers[r bis 0].toInt()
// logger.warn("$dividend / $divisor")
// dumpReg()
if (dividend.toUInt() == 0x8000_0000u && divisor == 1) {
// Undocumented, but simh does this "for 11/70 compatibility"
// 'tis a good question whether this is a bug in ekbb or a bug in simh.
N = true
Z = true
V = true
C = false
} else if (divisor != 0) {
val quot = dividend / divisor
val rem = dividend % divisor
if (quot > 0x7FFF || quot < -0x8000) {
V = true
N = false
C = false
Z = false
} else {
registers[r] = quot.toUShort()
registers[r bis 0] = rem.toUShort()
// logger.warn("$dividend / $divisor = $quot x + $rem")
// V = overflow != -(quot shr 15 and 1) // check if overflow extends the sign bit
V = false
}
N = quot bit 15
Z = quot == 0
C = false
} else {
N = false
Z = true
C = true
V = true
}
@@ -543,8 +593,38 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) {
} // RORB, ROLB, ASRB, ASLB
insnTable[0x8D] = { opcode ->
when (opcode shr 6 and 3) {
1 -> { throw InvalidOpcodeException() } // MFPD // TODO
2 -> { throw InvalidOpcodeException() } // MTPD // TODO
1 -> {
val src = opc_dst(opcode)
val v = if (is_paddr_reg(src)) {
if (src and 7u == 6u && prv_mode != cur_mode) {
shadow_r6[prv_mode]
} else
registers[src.toInt() and 7]
} else {
// memory ref
core.getSpace(prv_mode).getw(src.toUShort(), dspace = true)
}
stack_push(v)
N = v bit 15
Z = v == 0u.toUShort()
V = false
} // MFPD // TODO
2 -> {
val v = stack_pop()
val dest = opc_dst(opcode)
if (is_paddr_reg(dest)) {
if (dest and 7u == 6u && prv_mode != cur_mode) {
shadow_r6[prv_mode] = v
} else
registers[dest.toInt() and 7] = v
} else {
// memory ref
core.getSpace(prv_mode).setw(dest.toUShort(), v, dspace = true)
}
N = v bit 15
Z = v == 0u.toUShort()
V = false
} // MTPD // TODO
else -> { throw InvalidOpcodeException() } // Reserved
}
} // MFPD, MTPD
@@ -703,16 +783,16 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) {
}
private var pirq: UShort = 0u
set(value) {
val bitset = pirq shr 8
var maxp: UShort = 0u
for (i in 7 downTo 1) {
if (bitset bit i) {
maxp = i.toUShort() shl 1
break
val bitset = value shr 8
var maxp: UShort = 0u
for (i in 7 downTo 1) {
if (bitset bit i) {
maxp = i.toUShort() shl 1
break
}
}
field = value and 0xFE00u or maxp or (maxp shl 4)
}
field = value and 0xFE00u or maxp or (maxp shl 4)
}
private var cpu_err: UShort = 0u
set(value) { field = value and 0xFCu }
@@ -734,6 +814,21 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) {
core.mount(mbus.unibus)
}
fun dumpReg() {
val r = StringBuilder()
r.append("PC=${registers[7].toOctal()} ")
for (i in 0..5) {
r.append("R$i=${registers[i].toOctal()} ")
}
r.append("SP=${registers[6].toOctal()} ")
r.append("CC=")
r.append(if (N) 'N' else '-')
r.append(if (Z) 'Z' else '-')
r.append(if (V) 'V' else '-')
r.append(if (C) 'C' else '-')
logger.info("Regs: {}", r)
}
private fun is_paddr_reg(addr: UInt): Boolean = addr bit PADDR_REG_BIT
private fun is_paddr_ispace(addr: UInt): Boolean = addr bit PADDR_ISPACE_BIT
private fun op_resolve(operand: Int, src: Boolean, byte_mode: Boolean = false): UInt {
@@ -944,7 +1039,7 @@ class CPU(val mbus: MemBus, val tracer: ITracer = NullTracer()) {
private inner class Registers: PAddressSpace {
override fun getw(addr: UInt): UShort = when (addr) {
0x3FF78u -> 0u // Console switch/display
0x3FF78u -> 0x70u // Console switch/display
0x3FFE6u -> control_reg
0x3FFF0u -> (mbus.size shr 6).toUShort()
0x3FFF2u -> 0u // upper size

View File

@@ -144,12 +144,16 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
modeSpace = if (mapMode.mmanEnable) modeVTabs[max(mode, 2)] else noMmanSpace
}
fun getSpace(mode: Int): VAddressSpace = if (mapMode.mmanEnable) modeVTabs[max(mode, 2)] else noMmanSpace
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 modeVTabs: Array<ModeVSpace> = Array(3) { ModeVSpace(itabs[it], dtabs[it], false) }
private var noMmanSpace = NoMmanSpace()
var modeSpace: VAddressSpace = noMmanSpace
private set
var prevSpace: VAddressSpace = noMmanSpace
private set
private val unibusTable = UIntArray(32)