Compare commits

..

6 Commits

7 changed files with 157 additions and 75 deletions

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

@@ -40,6 +40,9 @@ class Cli: Callable<Int> {
@Option(names = ["-c", "--count"], description = ["Max number of instructions to run. 0 is infinite"]) @Option(names = ["-c", "--count"], description = ["Max number of instructions to run. 0 is infinite"])
private var maxInsns: Long = 0 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 { override fun call(): Int {
val tb = org.jline.terminal.TerminalBuilder.terminal() val tb = org.jline.terminal.TerminalBuilder.terminal()
var mbus = MemBus(65536) var mbus = MemBus(65536)
@@ -52,6 +55,7 @@ class Cli: Callable<Int> {
} }
var cpu = CPU(mbus, if (traceLength > 0 || CPU.debugMode) tracer else NullTracer()) 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) } val console = DL11(mbus.unibus, tb.input(), tb.output()).apply { mount(mbus.unibus) }
cpu.switchReg = switchReg.toUShort()
try { try {

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,18 @@ 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 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
@@ -795,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)
@@ -813,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) {
@@ -979,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)
@@ -1044,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() {
@@ -1061,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 {
@@ -1088,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
mbus.unibus.logger.debug("DATIP: {} @ {}", vector.toOctal(), i) mbus.unibus.logger.trace("DATIP: {} @ {}", vector.toOctal(), i)
callVector(vector) callVector(vector)
source.handled() source.handled()
break break
@@ -1111,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 {
@@ -1130,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)
} }
@@ -1173,8 +1194,9 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
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)
@@ -1186,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
@@ -1200,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
@@ -1221,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

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

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