Compare commits

...

8 Commits

9 changed files with 288 additions and 89 deletions

View File

@@ -33,5 +33,5 @@ kotlin {
} }
application { application {
mainClass.set("MainKt") mainClass.set("com.thequux.mcpdp.cli.Cli")
} }

16
doc/diagnostics.md Normal file
View File

@@ -0,0 +1,16 @@
# Running ekba
This will run for a total of 541450515 instructions. To just run the first pass (132198 insns), break at 10742.
```
# Start address of 0200, no switch settings, break at end of second pass.
jdp11 -l diag/ekba.pt -g 200 -b 10722
```
# Running ekbb
This will run for around 1144728 instructions.
```
# Start address of 0200, switch set to 161 to disable unibus trap tests, break at 36170, which is the end of the test
jdp11 -l diag/ekbb.pt -g 200 -s 161 -b 36170
```

View File

@@ -65,13 +65,13 @@ fun CPU.loadAbs(infile: File) {
if (cksum != 0) { if (cksum != 0) {
throw Exception("Incorrect checksum: 0x${cksum.toString(16)}") throw Exception("Incorrect checksum: 0x${cksum.toString(16)}")
} }
logger.debug("Loading 0x${len.toString(16)} bytes at 0x${addr.toString(16)}") logger.trace("Loading 0x${len.toString(16)} bytes at 0x${addr.toString(16)}")
if (len == 0) { if (len == 0) {
// end of file // end of file
logger.debug("Tape ended at ${pos+len+7}") logger.trace("Tape ended at ${pos+len+7}")
if (!(addr bit 0)){ if (!(addr bit 0)){
this.pc = addr this.pc = addr
logger.debug("Ready to run at ${addr.toString(8)}") logger.trace("Ready to run at ${addr.toString(8)}")
} }
return return
} else { } else {

View File

@@ -0,0 +1,111 @@
package com.thequux.mcpdp.cli
import ch.qos.logback.classic.LoggerContext
import com.thequux.mcpdp.core.CPU
import com.thequux.mcpdp.debug.FlightRecorder
import com.thequux.mcpdp.debug.LoggingCollector
import com.thequux.mcpdp.debug.NullTracer
import com.thequux.mcpdp.debug.Tracer
import com.thequux.mcpdp.loadAbs
import com.thequux.mcpdp.peripheral.DL11
import com.thequux.mcpdp.peripheral.MemBus
import org.jline.utils.Log
import org.slf4j.LoggerFactory
import picocli.CommandLine
import picocli.CommandLine.Command
import picocli.CommandLine.ITypeConverter
import picocli.CommandLine.Option
import picocli.CommandLine.Parameters
import java.io.File
import java.util.concurrent.Callable
import kotlin.system.exitProcess
@Command(name="jdp11", mixinStandardHelpOptions = true)
class Cli: Callable<Int> {
@Option(names = ["-l", "--load"], description = ["The paper tape image to load"])
private var load: File? = null
@Option(names = ["-t", "--trace"])
private var traceLength: Int = 0
@Option(names = ["--live"])
private var liveTrace = false
@Option(names = ["-g", "--go"], description = ["Start address in octal. Ignored if odd"], converter = [ OctalParamConverter::class ])
private var startAddress: Int = 1
@Option(names = ["-b", "--break"], description = ["Breakpoint address"], converter = [ OctalParamConverter::class ])
private var breakpoint: Int = 1
@Option(names = ["-c", "--count"], description = ["Max number of instructions to run. 0 is infinite"])
private var maxInsns: Long = 0
@Option(names = ["-s", "--switch"], description = ["Value of the switch register, in octal"], defaultValue = "0", converter = [OctalParamConverter::class])
private var switchReg: Int = 0
override fun call(): Int {
val tb = org.jline.terminal.TerminalBuilder.terminal()
var mbus = MemBus(65536)
val tracer = Tracer()
if (CPU.debugMode)
tracer.addCollector(LoggingCollector())
val recorder = FlightRecorder(traceLength)
if (traceLength > 0) {
tracer.addCollector(recorder)
}
var cpu = CPU(mbus, if (traceLength > 0 || CPU.debugMode) tracer else NullTracer())
val console = DL11(mbus.unibus, tb.input(), tb.output()).apply { mount(mbus.unibus) }
cpu.switchReg = switchReg.toUShort()
try {
tb.enterRawMode()
console.start()
if (load != null) {
cpu.loadAbs(load!!)
}
// cpu.core.setw(0x3C78u, 0u) // halt instead of restart
if (startAddress % 2 == 0) {
cpu.pc = startAddress.toUShort()
cpu.runState = CPU.RunState.RUNNING
}
cpu.breakpoint = breakpoint.toUShort()
// var ninsn = cpu.run(60000000)
if (cpu.runState == CPU.RunState.RUNNING) {
val start = System.nanoTime()
var ninsn = if (maxInsns > 0) cpu.run(maxInsns) else cpu.run()
// var ninsn = cpu.run(13300)
// ninsn += cpu.run(10)
recorder.dump(System.out)
cpu.dumpReg()
val end = System.nanoTime()
System.err.println("Halted at 0${cpu.pc.toString(8)}")
val time = (end - start).toDouble() / 1_000_000_000.0
System.err.println("Executed ${ninsn} in ${time}s: ${ninsn / time / 1_000_000} MIPS")
}
} finally {
println("Exiting")
console.stop()
}
val loggerContext = LoggerFactory.getILoggerFactory() as LoggerContext
loggerContext.stop()
return 0
}
companion object {
@JvmStatic
fun main(args: Array<String>) {
exitProcess(CommandLine(Cli()).execute(*args))
}
}
}
class OctalParamConverter: ITypeConverter<Int> {
override fun convert(value: String): Int {
return value.toInt(8)
}
}

View File

@@ -111,7 +111,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
registers[reg] = stack_pop() registers[reg] = stack_pop()
} // RTS } // RTS
in 0x98..0x9F -> { in 0x98..0x9F -> {
if (cur_mode == 0) psw_priority = opcode and 0x7 if (cur_mode == 0) psw_priority_next = opcode and 0x7
} // SPL } // SPL
in 0xA0..0xBF -> { in 0xA0..0xBF -> {
val flag = opcode bit 4 val flag = opcode bit 4
@@ -125,11 +125,11 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val v = op_loadw(dst) val v = op_loadw(dst)
val res = (v shl 8) or (v shr 8) val res = (v shl 8) or (v shr 8)
op_storw(dst, res)
V = false V = false
C = false C = false
N = res bit 7 N = res bit 7
Z = (res and 0xFFu) == 0.toUShort() Z = (res and 0xFFu) == 0.toUShort()
op_storw(dst, res)
} // SWAB } // SWAB
else -> throw InvalidOpcodeException() else -> throw InvalidOpcodeException()
} } } }
@@ -154,35 +154,37 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
insnTable[0x0A] = {opcode -> insnTable[0x0A] = {opcode ->
when (opcode shr 6 and 3) { when (opcode shr 6 and 3) {
0 -> { // CLR 0 -> { // CLR
op_storw(opc_dst(opcode), 0U)
N = false N = false
V = false V = false
C = false C = false
Z = true Z = true
op_storw(opc_dst(opcode), 0U)
} // CLR } // CLR
1 -> { // COM 1 -> { // COM
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val res = op_loadw(dst).inv().also { op_storw(dst, it) } val res = op_loadw(dst).inv()
N = res bit 15 N = res bit 15
Z = res == 0U.toUShort() Z = res == 0U.toUShort()
C = true C = true
V = false V = false
op_storw(dst, res)
} // COM } // COM
2 -> { // INC 2 -> { // INC
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val src = op_loadw(dst) val src = op_loadw(dst)
val res = src.inc() val res = src.inc()
op_storw(dst, res)
N = res bit 15 N = res bit 15
Z = res == 0.toUShort() Z = res == 0.toUShort()
V = res == 0x8000.toUShort() V = res == 0x8000.toUShort()
op_storw(dst, res)
} // INC } // INC
3 -> { // DEC 3 -> { // DEC
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val res = op_loadw(dst).dec().also { op_storw(dst, it) } val res = op_loadw(dst).dec()
N = res bit 15 N = res bit 15
Z = res == 0.toUShort() Z = res == 0.toUShort()
V = res == 0x7FFF.toUShort() V = res == 0x7FFF.toUShort()
op_storw(dst, res)
} // DEC } // DEC
} }
} // CLR, COM, INC, DEC } // CLR, COM, INC, DEC
@@ -191,31 +193,31 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
0 -> { // NEG 0 -> { // NEG
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val res = op_loadw(dst).inv().inc() val res = op_loadw(dst).inv().inc()
op_storw(dst, res)
N = res bit 15 N = res bit 15
Z = res == 0.toUShort() Z = res == 0.toUShort()
V = res == 0x8000.toUShort() V = res == 0x8000.toUShort()
C = !Z C = !Z
op_storw(dst, res)
} // NEG } // NEG
1 -> { // ADC 1 -> { // ADC
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val c: UShort = if (C) 1u else 0u val c: UShort = if (C) 1u else 0u
val res = (op_loadw(dst) + c).toUShort() val res = (op_loadw(dst) + c).toUShort()
op_storw(dst, res)
N = res bit 15 N = res bit 15
Z = res == 0u.toUShort() Z = res == 0u.toUShort()
V = (res == 0x8000u.toUShort()) and C V = (res == 0x8000u.toUShort()) and C
C = Z and C C = Z and C
op_storw(dst, res)
} // ADC } // ADC
2 -> { 2 -> {
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val src = op_loadw(dst) val src = op_loadw(dst)
val res = if (C) src.dec() else src val res = if (C) src.dec() else src
op_storw(dst, res)
N = res bit 15 N = res bit 15
Z = res == 0.toUShort() Z = res == 0.toUShort()
V = res == 0x8000.toUShort() V = res == 0x8000.toUShort()
C = C and (src == 0.toUShort()) C = C and (src == 0.toUShort())
op_storw(dst, res)
} // SBC } // SBC
3 -> { 3 -> {
val dst = op_loadw(opc_dst(opcode)) val dst = op_loadw(opc_dst(opcode))
@@ -232,41 +234,41 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val src = op_loadw(dst) val src = op_loadw(dst)
val res = (src shr 1).bit(15, C) val res = (src shr 1).bit(15, C)
op_storw(dst, res)
C = src bit 0 C = src bit 0
N = res bit 15 N = res bit 15
Z = res == 0.toUShort() Z = res == 0.toUShort()
V = N xor C V = N xor C
op_storw(dst, res)
} // ROR } // ROR
1 -> { 1 -> {
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val src = op_loadw(dst) val src = op_loadw(dst)
val res = (src shl 1).bit(0, C) val res = (src shl 1).bit(0, C)
op_storw(dst, res)
C = src bit 15 C = src bit 15
N = res bit 15 N = res bit 15
Z = res == 0.toUShort() Z = res == 0.toUShort()
V = N xor C V = N xor C
op_storw(dst, res)
} // ROL } // ROL
2 -> { // ASR 2 -> { // ASR
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val src = op_loadw(dst).toShort() val src = op_loadw(dst).toShort()
val res = (src shr 1).toUShort() val res = (src shr 1).toUShort()
op_storw(dst, res)
N = res bit 15 N = res bit 15
Z = res == 0.toUShort() Z = res == 0.toUShort()
C = src bit 0 C = src bit 0
V = N xor C V = N xor C
op_storw(dst, res)
} // ASR } // ASR
3 -> { // ASL 3 -> { // ASL
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val src = op_loadw(dst) val src = op_loadw(dst)
val res = src shl 1 val res = src shl 1
op_storw(dst, res.toUShort())
N = res bit 15 N = res bit 15
Z = res == 0.toUShort() Z = res == 0.toUShort()
C = src and 0x8000u != 0u.toUShort() C = src and 0x8000u != 0u.toUShort()
V = N xor C V = N xor C
op_storw(dst, res)
} // ASL } // ASL
} }
} // ROR, ROL, ASR, ASL } // ROR, ROL, ASR, ASL
@@ -289,14 +291,17 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
// memory ref // memory ref
core.getSpace(prv_mode).getw(src.toUShort(), dspace = false) core.getSpace(prv_mode).getw(src.toUShort(), dspace = false)
} }
stack_push(v)
N = v bit 15 N = v bit 15
Z = v == 0u.toUShort() Z = v == 0u.toUShort()
V = false V = false
stack_push(v)
} // MFPI // TODO } // MFPI // TODO
2 -> { 2 -> {
val v = stack_pop() val v = stack_pop()
val dest = opc_dst(opcode) val dest = opc_dst(opcode)
N = v bit 15
Z = v == 0u.toUShort()
V = false
if (is_paddr_reg(dest)) { if (is_paddr_reg(dest)) {
if (dest and 7u == 6u && prv_mode != cur_mode) { if (dest and 7u == 6u && prv_mode != cur_mode) {
shadow_r6[prv_mode] = v shadow_r6[prv_mode] = v
@@ -306,14 +311,11 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
// memory ref // memory ref
core.getSpace(prv_mode).setw(dest.toUShort(), v, dspace = false) core.getSpace(prv_mode).setw(dest.toUShort(), v, dspace = false)
} }
N = v bit 15
Z = v == 0u.toUShort()
V = false
} // MTPI // TODO } // MTPI // TODO
3 -> { 3 -> {
op_storw(opc_dst(opcode), if (N) (-1).toUShort() else 0.toUShort())
Z = !N Z = !N
V = false V = false
op_storw(opc_dst(opcode), if (N) (-1).toUShort() else 0.toUShort())
} // SXT } // SXT
} }
} // MARK, MFPI, MTPI, SXT } // MARK, MFPI, MTPI, SXT
@@ -325,10 +327,10 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
val src = opc_src(opcode) val src = opc_src(opcode)
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
op_loadw(src).also { op_loadw(src).also {
op_storw(dst, it)
N = it bit 15 N = it bit 15
Z = it == 0.toUShort() Z = it == 0.toUShort()
V = false V = false
op_storw(dst, it)
} }
} // MOV } // MOV
for (i in 0x20..0x2F) insnTable[i] = { opcode -> // CMP for (i in 0x20..0x2F) insnTable[i] = { opcode -> // CMP
@@ -352,19 +354,19 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
val src = opc_src(opcode) val src = opc_src(opcode)
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val res = op_loadw(dst) and op_loadw(src).inv() val res = op_loadw(dst) and op_loadw(src).inv()
op_storw(dst, res)
N = res bit 15 N = res bit 15
Z = res == 0u.toUShort() Z = res == 0u.toUShort()
V = false V = false
op_storw(dst, res)
} // BIC } // BIC
for (i in 0x50..0x5F) insnTable[i] = { opcode -> // BIS for (i in 0x50..0x5F) insnTable[i] = { opcode -> // BIS
val src = opc_src(opcode) val src = opc_src(opcode)
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val res = op_loadw(dst) or op_loadw(src) val res = op_loadw(dst) or op_loadw(src)
op_storw(dst, res)
N = res and 0x8000u != 0u.toUShort() N = res and 0x8000u != 0u.toUShort()
Z = res == 0u.toUShort() Z = res == 0u.toUShort()
V = false V = false
op_storw(dst, res)
} // BIS } // BIS
for (i in 0x60..0x6F) insnTable[i] = { opcode -> // ADD for (i in 0x60..0x6F) insnTable[i] = { opcode -> // ADD
val src = opc_src(opcode) val src = opc_src(opcode)
@@ -373,12 +375,12 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
val dstv = op_loadw(dst) val dstv = op_loadw(dst)
val res = (srcv + dstv) val res = (srcv + dstv)
val resw = res.toUShort() val resw = res.toUShort()
op_storw(dst, res.toUShort())
N = resw > 0x7FFFu N = resw > 0x7FFFu
Z = resw == 0.toUShort() Z = resw == 0.toUShort()
val src_sign = srcv and 0x8000u val src_sign = srcv and 0x8000u
V = (src_sign == dstv and 0x8000u) && (src_sign != resw and 0x8000u) V = (src_sign == dstv and 0x8000u) && (src_sign != resw and 0x8000u)
C = (res >= 0x10000u) C = (res >= 0x10000u)
op_storw(dst, res.toUShort())
} // ADD } // ADD
insnTable[0x70] = { opcode -> // MUL insnTable[0x70] = { opcode -> // MUL
val r = opcode shr 6 and 0x7 val r = opcode shr 6 and 0x7
@@ -493,10 +495,10 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
val r = opcode shr 6 and 7 val r = opcode shr 6 and 7
val dst = opc_dst(opcode) val dst = opc_dst(opcode)
val res = op_loadw(dst) xor registers[r] val res = op_loadw(dst) xor registers[r]
op_storw(dst, res)
N = res bit 15 N = res bit 15
Z = res == 0.toUShort() Z = res == 0.toUShort()
V = false V = false
op_storw(dst, res)
} // XOR } // XOR
// 0x7A and 0x7C are undefined // 0x7A and 0x7C are undefined
insnTable[0x7E] = { opcode -> // SOB insnTable[0x7E] = { opcode -> // SOB
@@ -526,33 +528,36 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
insnTable[0x8A] = { opcode -> insnTable[0x8A] = { opcode ->
when (opcode shr 6 and 3) { when (opcode shr 6 and 3) {
0 -> { // CLRB 0 -> { // CLRB
op_storb(opc_dstb(opcode), 0U)
N = false N = false
V = false V = false
C = false C = false
Z = true Z = true
op_storb(opc_dstb(opcode), 0U)
} // CLRB } // CLRB
1 -> { // COMB 1 -> { // COMB
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val res = op_loadb(dst).inv().also { op_storb(dst, it) } val res = op_loadb(dst).inv()
N = res bit 7 N = res bit 7
Z = res == 0U.toUByte() Z = res == 0U.toUByte()
C = true C = true
V = false V = false
op_storb(dst, res)
} // COMB } // COMB
2 -> { // INC 2 -> { // INCB
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val res = op_loadb(dst).inc().also { op_storb(dst, it) } val res = op_loadb(dst).inc()
N = res bit 7 N = res bit 7
Z = res == 0.toUByte() Z = res == 0.toUByte()
V = res == 0x80.toUByte() V = res == 0x80.toUByte()
op_storb(dst, res)
} // INCB } // INCB
3 -> { // DEC 3 -> { // DEC
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val res = op_loadb(dst).dec().also { op_storb(dst, it) } val res = op_loadb(dst).dec()
N = res bit 7 N = res bit 7
Z = res == 0.toUByte() Z = res == 0.toUByte()
V = res == 0x7F.toUByte() V = res == 0x7F.toUByte()
op_storb(dst, res)
} // DECB } // DECB
} }
} // CLRB, COMB, INCB, DECB } // CLRB, COMB, INCB, DECB
@@ -561,31 +566,31 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
0 -> { // NEGB 0 -> { // NEGB
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val res = op_loadb(dst).inv().inc() val res = op_loadb(dst).inv().inc()
op_storb(dst, res)
N = res bit 7 N = res bit 7
Z = res == 0.toUByte() Z = res == 0.toUByte()
V = res == 0x8000.toUByte() V = res == 0x8000.toUByte()
C = !Z C = !Z
op_storb(dst, res)
} // NEGB } // NEGB
1 -> { // ADCB 1 -> { // ADCB
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val c: UShort = if (C) 1u else 0u val c: UShort = if (C) 1u else 0u
val res = (op_loadb(dst) + c).toUByte() val res = (op_loadb(dst) + c).toUByte()
op_storb(dst, res)
N = res bit 7 N = res bit 7
Z = res == 0u.toUByte() Z = res == 0u.toUByte()
V = (res == 0x80u.toUByte()) and C V = (res == 0x80u.toUByte()) and C
C = Z and C C = Z and C
op_storb(dst, res)
} // ADCB } // ADCB
2 -> { 2 -> {
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val src = op_loadb(dst) val src = op_loadb(dst)
val res = if (C) src.dec() else src val res = if (C) src.dec() else src
op_storb(dst, res)
N = res bit 8 N = res bit 8
Z = res == 0.toUByte() Z = res == 0.toUByte()
V = res == 0x80.toUByte() V = res == 0x80.toUByte()
C = C and (src == 0.toUByte()) C = C and (src == 0.toUByte())
op_storb(dst, res)
} // SBCB } // SBCB
3 -> { 3 -> {
val dst = op_loadb(opc_dstb(opcode)) val dst = op_loadb(opc_dstb(opcode))
@@ -602,41 +607,41 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val src = op_loadb(dst) val src = op_loadb(dst)
val res = (src shr 1).bit(7, C) val res = (src shr 1).bit(7, C)
op_storb(dst, res)
C = src bit 0 C = src bit 0
N = res bit 7 N = res bit 7
Z = res == 0.toUByte() Z = res == 0.toUByte()
V = N xor C V = N xor C
op_storb(dst, res)
} // RORB } // RORB
1 -> { 1 -> {
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val src = op_loadb(dst) val src = op_loadb(dst)
val res = (src shl 1).bit(0, C) val res = (src shl 1).bit(0, C)
op_storb(dst, res)
C = src bit 7 C = src bit 7
N = res bit 7 N = res bit 7
Z = res == 0.toUByte() Z = res == 0.toUByte()
V = N xor C V = N xor C
op_storb(dst, res)
} // ROLB } // ROLB
2 -> { // ASRB 2 -> { // ASRB
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val src = op_loadb(dst).toByte() val src = op_loadb(dst).toByte()
val res = (src shr 1).toUByte() val res = (src shr 1).toUByte()
op_storb(dst, res)
N = res bit 7 N = res bit 7
Z = res == 0.toUByte() Z = res == 0.toUByte()
C = src bit 0 C = src bit 0
V = N xor C V = N xor C
op_storb(dst, res)
} // ASRB } // ASRB
3 -> { // ASLB 3 -> { // ASLB
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val src = op_loadb(dst) val src = op_loadb(dst)
val res = (src shl 1).toUByte() val res = (src shl 1).toUByte()
op_storw(dst, res.toUShort())
N = res bit 7 N = res bit 7
Z = res == 0.toUByte() Z = res == 0.toUByte()
C = src bit 7 C = src bit 7
V = N xor C V = N xor C
op_storw(dst, res.toUShort())
} // ASLB } // ASLB
} }
} // RORB, ROLB, ASRB, ASLB } // RORB, ROLB, ASRB, ASLB
@@ -653,14 +658,17 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
// memory ref // memory ref
core.getSpace(prv_mode).getw(src.toUShort(), dspace = true) core.getSpace(prv_mode).getw(src.toUShort(), dspace = true)
} }
stack_push(v)
N = v bit 15 N = v bit 15
Z = v == 0u.toUShort() Z = v == 0u.toUShort()
V = false V = false
stack_push(v)
} // MFPD // TODO } // MFPD // TODO
2 -> { 2 -> {
val v = stack_pop() val v = stack_pop()
val dest = opc_dst(opcode) val dest = opc_dst(opcode)
N = v bit 15
Z = v == 0u.toUShort()
V = false
if (is_paddr_reg(dest)) { if (is_paddr_reg(dest)) {
if (dest and 7u == 6u && prv_mode != cur_mode) { if (dest and 7u == 6u && prv_mode != cur_mode) {
shadow_r6[prv_mode] = v shadow_r6[prv_mode] = v
@@ -670,9 +678,6 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
// memory ref // memory ref
core.getSpace(prv_mode).setw(dest.toUShort(), v, dspace = true) core.getSpace(prv_mode).setw(dest.toUShort(), v, dspace = true)
} }
N = v bit 15
Z = v == 0u.toUShort()
V = false
} // MTPD // TODO } // MTPD // TODO
else -> { throw InvalidOpcodeException() } // Reserved else -> { throw InvalidOpcodeException() } // Reserved
} }
@@ -683,6 +688,9 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val dstv = op_loadb(src) val dstv = op_loadb(src)
N = dstv bit 7
Z = dstv == 0.toUByte()
V = false
if (is_paddr_reg(dst)) { if (is_paddr_reg(dst)) {
op_storw(dst, dstv.toUShort() sex 8) op_storw(dst, dstv.toUShort() sex 8)
dstv.toUShort() sex 8 dstv.toUShort() sex 8
@@ -690,9 +698,6 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
op_storb(dst, dstv) op_storb(dst, dstv)
dstv.toUShort() dstv.toUShort()
} }
N = dstv bit 7
Z = dstv == 0.toUByte()
V = false
} // MOVB } // MOVB
for (i in 0xA0..0xAF) insnTable[i] = { opcode -> // CMPB for (i in 0xA0..0xAF) insnTable[i] = { opcode -> // CMPB
@@ -716,19 +721,19 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
val src = opc_srcb(opcode) val src = opc_srcb(opcode)
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val res = op_loadb(dst) and op_loadb(src).inv() val res = op_loadb(dst) and op_loadb(src).inv()
op_storb(dst, res)
N = res bit 7 N = res bit 7
Z = res == 0u.toUByte() Z = res == 0u.toUByte()
V = false V = false
op_storb(dst, res)
} // BICB } // BICB
for (i in 0xD0..0xDF) insnTable[i] = { opcode -> // BISB for (i in 0xD0..0xDF) insnTable[i] = { opcode -> // BISB
val src = opc_srcb(opcode) val src = opc_srcb(opcode)
val dst = opc_dstb(opcode) val dst = opc_dstb(opcode)
val res = op_loadb(dst) or op_loadb(src) val res = op_loadb(dst) or op_loadb(src)
op_storb(dst, res)
N = res bit 7 N = res bit 7
Z = res == 0u.toUByte() Z = res == 0u.toUByte()
V = false V = false
op_storb(dst, res)
} // BISB } // BISB
for (i in 0xE0..0xEF) insnTable[i] = { opcode -> for (i in 0xE0..0xEF) insnTable[i] = { opcode ->
val src = opc_src(opcode) val src = opc_src(opcode)
@@ -736,17 +741,19 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
val srcv = op_loadw(src) val srcv = op_loadw(src)
val dstv = op_loadw(dst) val dstv = op_loadw(dst)
val res = (dstv.toShort() - srcv.toShort()) val res = (dstv.toShort() - srcv.toShort())
op_storw(dst, res.toUShort())
N = res < 0 N = res < 0
Z = res == 0 Z = res == 0
V = ((srcv bit 31) xor (dstv bit 15)) and ((srcv bit 15) == (res bit 31)) V = ((srcv bit 31) xor (dstv bit 15)) and ((srcv bit 15) == (res bit 31))
C = (dst.toInt() + src.inv().inc().toInt()) < 0x1_0000 C = (dst.toInt() + src.inv().inc().toInt()) < 0x1_0000
op_storw(dst, res.toUShort())
} // SUB } // SUB
// insnTable[0x0E] = // TODO: check this // insnTable[0x0E] = // TODO: check this
// insnTable[0x0F] = // TODO: check this // insnTable[0x0F] = // TODO: check this
} }
} }
var switchReg: UShort = 0u
private var atBreakpoint: Boolean = false
private var allowT: Boolean = true private var allowT: Boolean = true
private var control_reg: UShort = 0u private var control_reg: UShort = 0u
val logger: Logger = LoggerFactory.getLogger(this.javaClass) val logger: Logger = LoggerFactory.getLogger(this.javaClass)
@@ -765,6 +772,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
private var stack_limit: UShort = 0u private var stack_limit: UShort = 0u
private var handlingStackRed: Boolean = false private var handlingStackRed: Boolean = false
private var trapReq: Int = 0 private var trapReq: Int = 0
var breakpoint: UShort = 1u
val core = PagingUnit(mbus, this) val core = PagingUnit(mbus, this)
var runState: RunState = RunState.HALTED var runState: RunState = RunState.HALTED
@@ -793,7 +801,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
registerSet = newpsw shr 11 and 1 registerSet = newpsw shr 11 and 1
cur_mode = newpsw shr 14 cur_mode = newpsw shr 14
prv_mode = newpsw shr 12 and 3 prv_mode = newpsw shr 12 and 3
psw_priority = newpsw shr 5 and 7 psw_priority_next = newpsw shr 5 and 7
} else { } else {
registerSet = registerSet or (newpsw shr 11 and 1) registerSet = registerSet or (newpsw shr 11 and 1)
cur_mode = cur_mode or (newpsw shr 14 and 3) cur_mode = cur_mode or (newpsw shr 14 and 3)
@@ -811,6 +819,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
} }
private var prv_mode: Int = 0 private var prv_mode: Int = 0
private var psw_priority: Int = 0 private var psw_priority: Int = 0
private var psw_priority_next: Int = 0
var pc: UShort var pc: UShort
get() = registers[7] get() = registers[7]
set(value) { set(value) {
@@ -977,17 +986,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)
@@ -1042,15 +1055,21 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
fun trapRed() { fun trapRed() {
// This is handled separately because otherwise the stack push // This is handled separately because otherwise the stack push
// would itself trigger a red trap // would itself trigger a red trap
// logger.warn("Stack RED") logger.trace("Stack RED")
cpu_err = cpu_err or CPU_ERR_STK_RED cpu_err = cpu_err or CPU_ERR_STK_RED
val old_psw = psw val old_psw = psw
setPSW(core.getw(6u), true) setPSW(core.getSpace(0).getw(6u), true)
core.setw(2u, old_psw) if (cur_mode == 0) {
core.setw(0u, pc) sp = 4u
sp = 0u } else {
shadow_r6[0] = 4u
}
// manually implement stack_push to inhibit red trap
core.setw((sp-2u).toUShort(), old_psw)
core.setw((sp-4u).toUShort(), pc)
sp = (sp - 4u).toUShort()
trapReq = trapReq and TrapReason.RED.clear.inv() trapReq = trapReq and TrapReason.RED.clear.inv()
pc = core.getw(4u) pc = core.getSpace(0).getw(4u)
} }
fun step() { fun step() {
@@ -1059,9 +1078,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 {
@@ -1086,7 +1105,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
// logger.debug("Unibus interrupt at pri {} to {}", i, vector) mbus.unibus.logger.trace("DATIP: {} @ {}", vector.toOctal(), i)
callVector(vector) callVector(vector)
source.handled() source.handled()
break break
@@ -1095,7 +1114,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
} else { } else {
val pirqLvl = pirq.toInt() shr 1 and 7; val pirqLvl = pirq.toInt() shr 1 and 7;
if (pirqLvl > psw_priority) { if (pirqLvl > psw_priority) {
logger.debug("PIRQ{} trap to 0xA0", pirqLvl) // logger.debug("PIRQ{} trap to 0xA0", pirqLvl)
callVector(0xA0u) callVector(0xA0u)
} }
} }
@@ -1109,8 +1128,10 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
} }
if (runState == RunState.WAIT_FOR_INTERRUPT) { if (runState == RunState.WAIT_FOR_INTERRUPT) {
// Note that it is impossible to have a pending priority change at the same time as a WAIT insn
return return
} }
psw_priority = psw_priority_next
// Proceed to handling instruction // Proceed to handling instruction
try { try {
@@ -1128,9 +1149,11 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
} }
is NonExistentMemoryError -> { is NonExistentMemoryError -> {
cpu_err = cpu_err or CPU_ERR_NXM cpu_err = cpu_err or CPU_ERR_NXM
logger.trace("NXM at {}", error.addr.toOctal())
setTrap(TrapReason.NXM) setTrap(TrapReason.NXM)
} }
is BusTimeoutError -> { is BusTimeoutError -> {
logger.trace("TMO at {}", error.addr.toOctal())
cpu_err = cpu_err or CPU_ERR_UNIBUS_TIMEOUT cpu_err = cpu_err or CPU_ERR_UNIBUS_TIMEOUT
setTrap(TrapReason.NXM) setTrap(TrapReason.NXM)
} }
@@ -1145,29 +1168,35 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
fun run(): Long { fun run(): Long {
var ninsn: Long = 0 var ninsn: Long = 0
while (runState == RunState.RUNNING) { atBreakpoint = false
while (runState == RunState.RUNNING && !atBreakpoint) {
ninsn += run(Long.MAX_VALUE) ninsn += run(Long.MAX_VALUE)
} }
return ninsn return ninsn
} }
fun run(nstep: Long): Long { fun run(nstep: Long): Long {
atBreakpoint = false
var ninsn: Long = 0 var ninsn: Long = 0
while (runState == RunState.RUNNING && ninsn < nstep) { while (runState == RunState.RUNNING && ninsn < nstep && !atBreakpoint) {
ninsn++ if (pc == breakpoint) {
if (pc == 0x3224.toUShort()) { atBreakpoint = true
runState = runState ninsn = ninsn // Dummy statement to set debugger bkpt on
runState = RunState.HALTED // continue
}
if (!atBreakpoint) {
ninsn++
step()
} }
step()
} }
return ninsn return ninsn
} }
fun callVector(vector: UShort) { fun callVector(vector: UShort) {
val old_psw = psw val old_psw = psw
val newPSW = core.getw((vector + 2u).toUShort()) and 0xCFFFu or (cur_mode shl 12).toUShort() val newPSW = core.getSpace(0).getw((vector + 2u).toUShort()) and 0xCFFFu or (cur_mode shl 12).toUShort()
setPSW(newPSW, true) setPSW(newPSW, true)
psw_priority = psw_priority_next // calling a vector sets priority immediately
stack_push(old_psw) stack_push(old_psw)
stack_push(pc) stack_push(pc)
pc = core.getw(vector) pc = core.getw(vector)
@@ -1179,7 +1208,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
private inner class Registers: PAddressSpace { private inner class Registers: PAddressSpace {
override fun getw(addr: UInt): UShort = when (addr) { override fun getw(addr: UInt): UShort = when (addr) {
0x3FF78u -> 0x70u // Console switch/display 0x3FF78u -> switchReg // Console switch/display
0x3FFE6u -> control_reg 0x3FFE6u -> control_reg
0x3FFF0u -> (mbus.size shr 6).toUShort() 0x3FFF0u -> (mbus.size shr 6).toUShort()
0x3FFF2u -> 0u // upper size 0x3FFF2u -> 0u // upper size
@@ -1193,7 +1222,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
override fun setw(addr: UInt, value: UShort) = when (addr) { override fun setw(addr: UInt, value: UShort) = when (addr) {
0x3_FF78u -> { 0x3_FF78u -> {
System.err.print("\u001b]0;${value.toOctal()}\u0007") // System.err.print("\u001b]0;${value.toOctal()}\u0007")
} // console switch/display reg } // console switch/display reg
0x3_FFE6u -> control_reg = value 0x3_FFE6u -> control_reg = value
0x3_FFF0u , 0x3_FFF2u , 0x3_FFF4u, 0x3_FFF8u -> {} // read-only registers 0x3_FFF0u , 0x3_FFF2u , 0x3_FFF4u, 0x3_FFF8u -> {} // read-only registers
@@ -1214,10 +1243,10 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
fun checkSP(addr: UShort): UShort { fun checkSP(addr: UShort): UShort {
if (cur_mode != 0) return addr if (cur_mode != 0) return addr
if (sp < stack_limit + 224u || sp.toInt() and 0xFFFE == 0xFFFE) { if (addr < stack_limit + 224u || addr.toInt() and 0xFFFE == 0xFFFE) {
trapRed() trapRed()
throw EndCycle() throw EndCycle()
} else if (sp < stack_limit + 256u) { } else if (addr < stack_limit + 256u) {
// logger.warn("Stack YLW") // logger.warn("Stack YLW")
// stack limit yellow // stack limit yellow
cpu_err = cpu_err or CPU_ERR_STK_YLW cpu_err = cpu_err or CPU_ERR_STK_YLW
@@ -1233,7 +1262,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
enum class RunState(val handleInterrupt: Boolean) { enum class RunState(val handleInterrupt: Boolean) {
RUNNING(handleInterrupt = true), RUNNING(handleInterrupt = true),
HALTED(handleInterrupt = false), HALTED(handleInterrupt = false),
WAIT_FOR_INTERRUPT(handleInterrupt = true) WAIT_FOR_INTERRUPT(handleInterrupt = true),
} }
} }

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()
} }
} }
@@ -146,7 +163,7 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace {
modeSpace = if (mapMode.mmanEnable) modeVTabs[min(mode, 2)] else noMmanSpace modeSpace = if (mapMode.mmanEnable) modeVTabs[min(mode, 2)] else noMmanSpace
} }
fun getSpace(mode: Int): VAddressSpace = if (mapMode.mmanEnable) modeVTabs[max(mode, 2)] else noMmanSpace fun getSpace(mode: Int): VAddressSpace = if (mapMode.mmanEnable) modeVTabs[min(mode, 2)] else noMmanSpace
fun logIncrement(register: Int, amount: Int) { fun logIncrement(register: Int, amount: Int) {
assert(register in 0..7) assert(register in 0..7)
@@ -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
@@ -314,8 +349,8 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace {
val regs = ConfigRegisters() val regs = ConfigRegisters()
unibus.run { unibus.run {
deviceView = UnibusMap() deviceView = UnibusMap()
attach(0x3_F480u, 6, PdPair(itabs[0], dtabs[0])) attach(0x3_F480u, 6, PdPair(itabs[1], dtabs[1]))
attach(0x3_F4C0u, 6, PdPair(itabs[1], dtabs[1])) attach(0x3_F4C0u, 6, PdPair(itabs[0], dtabs[0]))
attach(0x3_FF80u, 6, PdPair(itabs[2], dtabs[2])) // User PAR/PDR attach(0x3_FF80u, 6, PdPair(itabs[2], dtabs[2])) // User PAR/PDR
attach(0x3_FF7Au, 1, regs) // MMR0 attach(0x3_FF7Au, 1, regs) // MMR0
attach(0x3_FF7Cu, 2, regs) // MMR1-2 attach(0x3_FF7Cu, 2, regs) // MMR1-2

View File

@@ -42,7 +42,7 @@ class DL11(private var istr: InputStream, private val ostr: OutputStream, val re
override fun reset() { override fun reset() {
rcsr = 0x0u rcsr = 0x0u
rcsr = 0x0u rcsr = 0x0u
// xcsr = 0x80u xcsr = 0x80u
intrRcv.level = false intrRcv.level = false
intrXmit.level = false intrXmit.level = false
@@ -76,7 +76,10 @@ class DL11(private var istr: InputStream, private val ostr: OutputStream, val re
if (value bit 0) {rcsr = rcsr bic 7 } if (value bit 0) {rcsr = rcsr bic 7 }
} }
2 -> { rcsr = rcsr bic 7 } 2 -> { rcsr = rcsr bic 7 }
4 -> xcsr = xcsr.maskSet(value, 0x0045u) 4 -> {
xcsr = xcsr.maskSet(value, 0x0045u)
if (!(xcsr bit 6)) intrXmit.level = false
}
6 -> { 6 -> {
val b = value.toInt() and 0xFF val b = value.toInt() and 0xFF
if (xcsr bit 2) { if (xcsr bit 2) {

View File

@@ -74,7 +74,7 @@ class Unibus: PAddressSpace, Subregion(12, 6) {
/// The view of the unibus from a device /// The view of the unibus from a device
var deviceView: PAddressSpace = this var deviceView: PAddressSpace = this
internal set internal set
private val logger = LoggerFactory.getLogger(this.javaClass) internal 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 val devices: HashSet<Peripheral> = HashSet()