Compare commits
3 Commits
d5a36eac84
...
3bbeaa9b8e
| Author | SHA1 | Date | |
|---|---|---|---|
| 3bbeaa9b8e | |||
| 709eddc225 | |||
| c2f38a4b50 |
@@ -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()
|
||||||
|
|||||||
@@ -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 = opcode and 0x7
|
||||||
} // SPL
|
} // SPL
|
||||||
in 0xA0..0xBF -> {
|
in 0xA0..0xBF -> {
|
||||||
val flag = opcode bit 4
|
val flag = opcode bit 4
|
||||||
@@ -768,7 +768,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
|
|||||||
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,26 +781,33 @@ 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 = 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
|
||||||
@@ -817,6 +824,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 +838,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) {
|
||||||
@@ -1031,11 +1042,11 @@ 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.warn("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.getw(6u), true)
|
||||||
core.setw(2u, psw)
|
core.setw(2u, old_psw)
|
||||||
core.setw(0u, pc)
|
core.setw(0u, pc)
|
||||||
sp = 0u
|
sp = 0u
|
||||||
trapReq = trapReq and TrapReason.RED.clear.inv()
|
trapReq = trapReq and TrapReason.RED.clear.inv()
|
||||||
@@ -1084,7 +1095,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
|
|||||||
} else {
|
} else {
|
||||||
val pirqLvl = pirq.toInt() shr 1 and 7;
|
val pirqLvl = pirq.toInt() shr 1 and 7;
|
||||||
if (pirqLvl > psw_priority) {
|
if (pirqLvl > psw_priority) {
|
||||||
// logger.debug("PIRQ{} trap to 0xA0", pirqLvl)
|
logger.debug("PIRQ{} trap to 0xA0", pirqLvl)
|
||||||
callVector(0xA0u)
|
callVector(0xA0u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1124,7 +1135,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
|
|||||||
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) {
|
||||||
@@ -1144,8 +1155,9 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
|
|||||||
var ninsn: Long = 0
|
var ninsn: Long = 0
|
||||||
while (runState == RunState.RUNNING && ninsn < nstep) {
|
while (runState == RunState.RUNNING && ninsn < nstep) {
|
||||||
ninsn++
|
ninsn++
|
||||||
if (pc == 0x344A.toUShort()) {
|
if (pc == 0x3224.toUShort()) {
|
||||||
pc = pc
|
runState = runState
|
||||||
|
runState = RunState.HALTED
|
||||||
}
|
}
|
||||||
step()
|
step()
|
||||||
}
|
}
|
||||||
@@ -1154,8 +1166,8 @@ 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
|
||||||
// update PSW first so that this gets pushed to the
|
val newPSW = core.getw((vector + 2u).toUShort()) and 0xCFFFu or (cur_mode shl 12).toUShort()
|
||||||
psw = core.getw((vector + 2u).toUShort())
|
setPSW(newPSW, true)
|
||||||
stack_push(old_psw)
|
stack_push(old_psw)
|
||||||
stack_push(pc)
|
stack_push(pc)
|
||||||
pc = core.getw(vector)
|
pc = core.getw(vector)
|
||||||
@@ -1188,7 +1200,11 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
|
|||||||
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)
|
||||||
@@ -1202,7 +1218,7 @@ class CPU(val mbus: MemBus, var tracer: ITracer = NullTracer()) {
|
|||||||
trapRed()
|
trapRed()
|
||||||
throw EndCycle()
|
throw EndCycle()
|
||||||
} else if (sp < stack_limit + 256u) {
|
} else if (sp < 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)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ 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 kotlin.math.max
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
enum class AccessAction {
|
enum class AccessAction {
|
||||||
Allow,
|
Allow,
|
||||||
@@ -77,8 +78,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) {
|
||||||
@@ -121,7 +122,7 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace {
|
|||||||
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,7 +143,7 @@ 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[max(mode, 2)] else noMmanSpace
|
||||||
@@ -172,7 +173,7 @@ class PagingUnit(val pspace: PAddressSpace, val cpu: CPU): VAddressSpace {
|
|||||||
|
|
||||||
|
|
||||||
private inner class ModeVSpace(private val iSpace: PageTable, private val dSpace: PageTable, var useDSpace: Boolean): VAddressSpace {
|
private inner class ModeVSpace(private val iSpace: PageTable, private val dSpace: PageTable, var useDSpace: Boolean): VAddressSpace {
|
||||||
private fun getSpace(dspace: Boolean): PageTable = if (dspace) 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(dSpace.map(addr, write = false))
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user