Compare commits
11 Commits
d5a36eac84
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| a155097903 | |||
| b512f1a42f | |||
| ef5d8d73c7 | |||
| d90304b5fd | |||
| 6052c9a0c0 | |||
| c8c8297765 | |||
| fa7108098b | |||
| 308e3a9efa | |||
| 3bbeaa9b8e | |||
| 709eddc225 | |||
| c2f38a4b50 |
@@ -33,5 +33,5 @@ kotlin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClass.set("MainKt")
|
mainClass.set("com.thequux.mcpdp.cli.Cli")
|
||||||
}
|
}
|
||||||
|
|||||||
16
doc/diagnostics.md
Normal file
16
doc/diagnostics.md
Normal 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
|
||||||
|
```
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import ch.qos.logback.classic.LoggerContext
|
import ch.qos.logback.classic.LoggerContext
|
||||||
import ch.qos.logback.core.util.StatusPrinter
|
import ch.qos.logback.core.util.StatusPrinter
|
||||||
import com.thequux.mcpdp.core.CPU
|
import com.thequux.mcpdp.core.CPU
|
||||||
|
import com.thequux.mcpdp.debug.FlightRecorder
|
||||||
import com.thequux.mcpdp.debug.LoggingCollector
|
import com.thequux.mcpdp.debug.LoggingCollector
|
||||||
import com.thequux.mcpdp.debug.NullTracer
|
import com.thequux.mcpdp.debug.NullTracer
|
||||||
import com.thequux.mcpdp.debug.Tracer
|
import com.thequux.mcpdp.debug.Tracer
|
||||||
@@ -24,7 +25,9 @@ fun main(args: Array<String>) {
|
|||||||
var mbus = MemBus(65536)
|
var mbus = MemBus(65536)
|
||||||
val tracer = Tracer()
|
val tracer = Tracer()
|
||||||
val loggingCollector = LoggingCollector()
|
val loggingCollector = LoggingCollector()
|
||||||
tracer.addCollector(loggingCollector)
|
// tracer.addCollector(loggingCollector)
|
||||||
|
val recorder = FlightRecorder(3000)
|
||||||
|
tracer.addCollector(recorder)
|
||||||
var cpu = CPU(mbus, if (CPU.debugMode) tracer else NullTracer())
|
var cpu = CPU(mbus, if (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) }
|
||||||
try {
|
try {
|
||||||
@@ -34,19 +37,22 @@ fun main(args: Array<String>) {
|
|||||||
console.start()
|
console.start()
|
||||||
|
|
||||||
cpu.loadAbs(File(args[0]))
|
cpu.loadAbs(File(args[0]))
|
||||||
|
cpu.core.setw(0x3C78u, 0u) // halt instead of restart
|
||||||
cpu.runState = CPU.RunState.RUNNING
|
cpu.runState = CPU.RunState.RUNNING
|
||||||
cpu.pc = 0x80u
|
cpu.pc = 0x80u
|
||||||
val start = System.nanoTime()
|
val start = System.nanoTime()
|
||||||
// var ninsn = cpu.run(600000000)
|
// var ninsn = cpu.run(60000000)
|
||||||
var ninsn = cpu.run(376670)
|
|
||||||
cpu.tracer = tracer
|
cpu.tracer = tracer
|
||||||
ninsn += cpu.run(30)
|
var ninsn = cpu.run(323227)
|
||||||
|
// var ninsn = cpu.run(13300)
|
||||||
|
// ninsn += cpu.run(10)
|
||||||
|
recorder.dump(System.out)
|
||||||
cpu.dumpReg()
|
cpu.dumpReg()
|
||||||
val end = System.nanoTime()
|
val end = System.nanoTime()
|
||||||
|
|
||||||
System.err.println("Halted at 0${cpu.pc.toString(8)}")
|
System.err.println("Halted at 0${cpu.pc.toString(8)}")
|
||||||
val time = (end - start).toDouble() / 1_000_000_000.0
|
val time = (end - start).toDouble() / 1_000_000_000.0
|
||||||
println("Executed ${ninsn} in ${time}s: ${ninsn / time / 1_000_000} MIPS")
|
System.err.println("Executed ${ninsn} in ${time}s: ${ninsn / time / 1_000_000} MIPS")
|
||||||
} finally {
|
} finally {
|
||||||
println("Exiting")
|
println("Exiting")
|
||||||
console.stop()
|
console.stop()
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
111
src/main/kotlin/com/thequux/mcpdp/cli/Cli.kt
Normal file
111
src/main/kotlin/com/thequux/mcpdp/cli/Cli.kt
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -82,7 +82,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
|
|||||||
0x0001 -> runState = RunState.WAIT_FOR_INTERRUPT // WAIT
|
0x0001 -> runState = RunState.WAIT_FOR_INTERRUPT // WAIT
|
||||||
0x0002 -> { // RTI
|
0x0002 -> { // RTI
|
||||||
pc = stack_pop()
|
pc = stack_pop()
|
||||||
psw = stack_pop() // TODO: check privilege on mode; check psw[11]
|
setPSW(stack_pop(), cur_mode == 0) // TODO: check privilege on mode; check psw[11]
|
||||||
} // RTI
|
} // RTI
|
||||||
0x0003 -> setTrap(TrapReason.BPT) // BPT
|
0x0003 -> setTrap(TrapReason.BPT) // BPT
|
||||||
0x0004 -> setTrap(TrapReason.IOT) // IOT
|
0x0004 -> setTrap(TrapReason.IOT) // IOT
|
||||||
@@ -94,7 +94,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
|
|||||||
} // bus reset TODO: bus init
|
} // bus reset TODO: bus init
|
||||||
0x0006 -> {
|
0x0006 -> {
|
||||||
pc = stack_pop()
|
pc = stack_pop()
|
||||||
psw = stack_pop()
|
setPSW(stack_pop(), cur_mode == 0)
|
||||||
allowT = false
|
allowT = false
|
||||||
} // RTT
|
} // RTT
|
||||||
in 0x40..0x7f -> {
|
in 0x40..0x7f -> {
|
||||||
@@ -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 -> {
|
||||||
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,10 +772,11 @@ 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
|
||||||
var psw: UShort
|
val psw: UShort
|
||||||
get() {
|
get() {
|
||||||
var res = 0
|
var res = 0
|
||||||
if (C) { res = res or 0x0001 }
|
if (C) { res = res or 0x0001 }
|
||||||
@@ -781,29 +789,37 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
|
|||||||
res = res or (registerSet shl 11)
|
res = res or (registerSet shl 11)
|
||||||
return res.toUShort()
|
return res.toUShort()
|
||||||
}
|
}
|
||||||
set(value) {
|
|
||||||
var newpsw = value.toInt()
|
fun setPSW(value: UShort, allowEsc: Boolean) {
|
||||||
C = value bit 0
|
var newpsw = value.toInt()
|
||||||
V = value bit 1
|
C = value bit 0
|
||||||
Z = value bit 2
|
V = value bit 1
|
||||||
N = value bit 3
|
Z = value bit 2
|
||||||
T = value bit 4 // TODO: handle suspended trap
|
N = value bit 3
|
||||||
psw_priority = newpsw shr 5 and 7
|
T = value bit 4 // TODO: handle suspended trap
|
||||||
|
if (allowEsc) {
|
||||||
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
|
||||||
|
psw_priority_next = newpsw shr 5 and 7
|
||||||
|
} else {
|
||||||
|
registerSet = registerSet or (newpsw shr 11 and 1)
|
||||||
|
cur_mode = cur_mode or (newpsw shr 14 and 3)
|
||||||
|
prv_mode = prv_mode or (newpsw shr 12 and 3)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var cur_mode: Int = 0
|
private var cur_mode: Int = 0
|
||||||
set(value) {
|
set(value) {
|
||||||
prv_mode = field
|
// prv_mode = field
|
||||||
shadow_r6[field] = sp
|
shadow_r6[field] = sp
|
||||||
field = if (value == 2) 3 else value
|
field = if (value == 2) 3 else value
|
||||||
sp = shadow_r6[field]
|
sp = shadow_r6[field]
|
||||||
core.mode = value
|
core.mode = field
|
||||||
}
|
}
|
||||||
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) {
|
||||||
@@ -817,6 +833,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
|
|||||||
|
|
||||||
private var registerSet: Int = 0
|
private var registerSet: Int = 0
|
||||||
set(value) {
|
set(value) {
|
||||||
|
if (value == field) return
|
||||||
if (value !in 0..1) {
|
if (value !in 0..1) {
|
||||||
throw ProgrammerError("Invalid register set number")
|
throw ProgrammerError("Invalid register set number")
|
||||||
}
|
}
|
||||||
@@ -830,9 +847,12 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var cc: UShort
|
private var cc: UShort
|
||||||
get() = psw and 0xFu
|
get() = 0.bit(3, N).bit(2, Z).bit(1, C).bit(0, C).toUShort()
|
||||||
set(value) {
|
set(value) {
|
||||||
psw = (psw and 0xFFFu) or (value and 0xFu)
|
N = value bit 3
|
||||||
|
Z = value bit 2
|
||||||
|
V = value bit 1
|
||||||
|
C = value bit 0
|
||||||
}
|
}
|
||||||
private var pirq: UShort = 0u
|
private var pirq: UShort = 0u
|
||||||
set(value) {
|
set(value) {
|
||||||
@@ -966,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)
|
||||||
@@ -1031,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
|
||||||
psw = core.getw(6u)
|
setPSW(core.getSpace(0).getw(6u), true)
|
||||||
core.setw(2u, 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() {
|
||||||
@@ -1048,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 {
|
||||||
@@ -1075,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
|
||||||
@@ -1098,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 {
|
||||||
@@ -1117,14 +1149,16 @@ 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.warn("Threw error: $error")
|
// logger.warn("Threw error: $error")
|
||||||
} catch (_: InvalidOpcodeException) {
|
} catch (_: InvalidOpcodeException) {
|
||||||
setTrap(TrapReason.ILL)
|
setTrap(TrapReason.ILL)
|
||||||
} catch (_: EndCycle) {
|
} catch (_: EndCycle) {
|
||||||
@@ -1134,28 +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 == 0x344A.toUShort()) {
|
atBreakpoint = true
|
||||||
pc = pc
|
ninsn = ninsn // Dummy statement to set debugger bkpt on
|
||||||
|
// 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
|
||||||
// update PSW first so that this gets pushed to the
|
val newPSW = core.getSpace(0).getw((vector + 2u).toUShort()) and 0xCFFFu or (cur_mode shl 12).toUShort()
|
||||||
psw = core.getw((vector + 2u).toUShort())
|
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)
|
||||||
@@ -1167,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
|
||||||
@@ -1181,14 +1222,18 @@ 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
|
||||||
0x3_FFF6u -> cpu_err = value
|
0x3_FFF6u -> cpu_err = value
|
||||||
0x3_FFFAu -> pirq = value
|
0x3_FFFAu -> pirq = value
|
||||||
0x3_FFFCu -> stack_limit = value and 0xFF00u // stack limit
|
0x3_FFFCu -> stack_limit = value and 0xFF00u // stack limit
|
||||||
0x3_FFFEu -> psw = value or (cur_mode.toUShort() shl 14) // writing to PSW can only increase current mode
|
0x3_FFFEu -> {
|
||||||
|
setPSW(value, true)
|
||||||
|
// explicitly switch RS if necessary
|
||||||
|
// registerSet = (value shr 11 and 1u).toInt()
|
||||||
|
} // writing to PSW can only increase current mode
|
||||||
else -> {
|
else -> {
|
||||||
println("Bus error at ${addr.toString(16)}: ${value.toString(16)}")
|
println("Bus error at ${addr.toString(16)}: ${value.toString(16)}")
|
||||||
throw BusTimeoutError(addr)
|
throw BusTimeoutError(addr)
|
||||||
@@ -1198,11 +1243,11 @@ 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
|
||||||
setTrap(TrapReason.YEL)
|
setTrap(TrapReason.YEL)
|
||||||
@@ -1217,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),
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ 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
|
||||||
|
|
||||||
enum class AccessAction {
|
enum class AccessAction {
|
||||||
Allow,
|
Allow,
|
||||||
@@ -34,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
|
||||||
@@ -59,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) {
|
||||||
@@ -77,8 +81,8 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace {
|
|||||||
val unibusMap: PAddressSpace = UnibusMap()
|
val unibusMap: PAddressSpace = UnibusMap()
|
||||||
|
|
||||||
private inner class PageTable(val mode: Int, val dspace: Boolean) {
|
private inner class PageTable(val mode: Int, val dspace: Boolean) {
|
||||||
val par = UShortArray(16) { 0U }
|
val par = UShortArray(8) { 0U }
|
||||||
val pdr = Array(16) { PDR() }
|
val pdr = Array(8) { PDR() }
|
||||||
|
|
||||||
|
|
||||||
fun setMmr0(causeBit: Int, apf: Int, completed: Boolean = false) {
|
fun setMmr0(causeBit: Int, apf: Int, completed: Boolean = false) {
|
||||||
@@ -104,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()
|
||||||
@@ -113,15 +127,19 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val tmp1 = addr.toUInt() + (par.toUInt() shl 6) and mapMode.addrMask
|
val tmp1 = addr.toUInt().and(0x1FFFu) + (par.toUInt() shl 6) and mapMode.addrMask
|
||||||
if (tmp1 and mapMode.hipageMask == mapMode.hipageMask) {
|
if (tmp1 and mapMode.hipageMask == mapMode.hipageMask) {
|
||||||
return tmp1 or 0x3C_0000u
|
return tmp1 or 0x3C_0000u
|
||||||
} else {
|
} else {
|
||||||
@@ -142,10 +160,10 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace {
|
|||||||
enable22bit -> MManMode.MM_22
|
enable22bit -> MManMode.MM_22
|
||||||
else -> MManMode.MM_18
|
else -> MManMode.MM_18
|
||||||
}
|
}
|
||||||
modeSpace = if (mapMode.mmanEnable) modeVTabs[max(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)
|
||||||
@@ -162,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
|
||||||
@@ -171,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 {
|
||||||
private fun getSpace(dspace: Boolean): PageTable = if (dspace) dSpace else iSpace
|
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
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,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
|
||||||
@@ -232,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
|
||||||
@@ -313,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
|
||||||
|
|||||||
@@ -86,7 +86,11 @@ class Disassembler {
|
|||||||
fun dasm_at(loc: UShort, istream: UShortArray): String {
|
fun dasm_at(loc: UShort, istream: UShortArray): String {
|
||||||
opc = loc
|
opc = loc
|
||||||
this.istream = istream
|
this.istream = istream
|
||||||
opcode = istream[0].toInt()
|
try {
|
||||||
|
opcode = istream[0].toInt()
|
||||||
|
} catch(_: IndexOutOfBoundsException) {
|
||||||
|
return fmt("????")
|
||||||
|
}
|
||||||
|
|
||||||
vpc = 1
|
vpc = 1
|
||||||
try {
|
try {
|
||||||
|
|||||||
26
src/main/kotlin/com/thequux/mcpdp/debug/FlightRecorder.kt
Normal file
26
src/main/kotlin/com/thequux/mcpdp/debug/FlightRecorder.kt
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package com.thequux.mcpdp.debug
|
||||||
|
|
||||||
|
import java.io.PrintStream
|
||||||
|
import java.io.Writer
|
||||||
|
|
||||||
|
@OptIn(ExperimentalUnsignedTypes::class)
|
||||||
|
class FlightRecorder(size: Int): Collector {
|
||||||
|
var trace: Array<TraceRecord?> = Array(size) { null }
|
||||||
|
var pos = 0
|
||||||
|
|
||||||
|
override fun invoke(record: TraceRecord) {
|
||||||
|
trace[pos++] = record
|
||||||
|
if (pos >= trace.size) pos -= trace.size
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dump(os: PrintStream) {
|
||||||
|
val dis = Disassembler()
|
||||||
|
for (i in trace.indices) {
|
||||||
|
val i0 = (i + pos) % trace.size
|
||||||
|
val record = trace[i0]
|
||||||
|
if (record != null) {
|
||||||
|
os.println(record.report(dis))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user