Improved paging simulation, added disassembler

This commit is contained in:
2023-09-19 22:08:47 +02:00
parent 1bc7f93d57
commit 20e57e3a19
4 changed files with 339 additions and 34 deletions

View File

@@ -6,9 +6,9 @@ import com.thequux.mcpdp.ext.bit.shl
import com.thequux.mcpdp.ext.bit.shr import com.thequux.mcpdp.ext.bit.shr
interface VAddressSpace { interface VAddressSpace {
fun getw(addr: UShort, dspace: Boolean = false): UShort fun getw(addr: UShort, dspace: Boolean = true): UShort
fun getb(addr: UShort): UByte fun getb(addr: UShort): UByte
fun setw(addr: UShort, value: UShort, dspace: Boolean = false) fun setw(addr: UShort, value: UShort, dspace: Boolean = true)
fun setb(addr: UShort, value: UByte) fun setb(addr: UShort, value: UByte)
} }

View File

@@ -2,9 +2,11 @@ package com.thequux.mcpdp.core
import com.thequux.mcpdp.ext.bit.* import com.thequux.mcpdp.ext.bit.*
import com.thequux.mcpdp.peripheral.MemBus import com.thequux.mcpdp.peripheral.MemBus
import com.thequux.mcpdp.util.Disassembler
import com.thequux.mcpdp.util.ProgrammerError import com.thequux.mcpdp.util.ProgrammerError
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import kotlin.math.log
/// The main CPU /// The main CPU
/// ///
@@ -15,6 +17,12 @@ import org.slf4j.LoggerFactory
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
class CPU(val mbus: MemBus) { class CPU(val mbus: MemBus) {
companion object {
val debugMode = System.getProperty("jdp11.itrace").toBoolean()
}
private var control_reg: UShort = 0u
val logger: Logger = LoggerFactory.getLogger(this.javaClass) val logger: Logger = LoggerFactory.getLogger(this.javaClass)
private val flagStr: String private val flagStr: String
get() { get() {
@@ -29,6 +37,7 @@ class CPU(val mbus: MemBus) {
private val general_registers = Array<UShortArray>(2) { UShortArray(6) } private val general_registers = Array<UShortArray>(2) { UShortArray(6) }
private val shadow_r6 = UShortArray(4) // private val shadow_r6 = UShortArray(4) //
val core = PagingUnit(mbus) val core = PagingUnit(mbus)
private val dasm = Disassembler(core)
var runState: RunState = RunState.HALTED var runState: RunState = RunState.HALTED
var psw: UShort var psw: UShort
@@ -119,10 +128,12 @@ class CPU(val mbus: MemBus) {
private var V: Boolean = false private var V: Boolean = false
private var T: Boolean = false private var T: Boolean = false
private val PADDR_REG_BIT: Int = 23 private val PADDR_REG_BIT: Int = 23
private val PADDR_ISPACE_BIT: Int = 22
init { init {
val regs = Registers() val regs = Registers()
mbus.unibus.run { mbus.unibus.run {
attach(0x3FFE6u, 1, regs)
attach(0x3FFF8u, 3, regs) attach(0x3FFF8u, 3, regs)
attach(0x3FFF4u, 2, regs) attach(0x3FFF4u, 2, regs)
} }
@@ -130,38 +141,40 @@ class CPU(val mbus: MemBus) {
} }
private fun is_paddr_reg(addr: UInt): Boolean = addr bit PADDR_REG_BIT private fun is_paddr_reg(addr: UInt): Boolean = addr bit PADDR_REG_BIT
private fun is_paddr_ispace(addr: UInt): Boolean = addr bit PADDR_ISPACE_BIT
private fun op_resolve(operand: Int, byte_mode: Boolean = false): UInt { private fun op_resolve(operand: Int, byte_mode: Boolean = false): UInt {
val mode = operand shr 3 val mode = operand shr 3
val reg = operand and 0x7 val reg = operand and 0x7
val increment = if (byte_mode && reg != 7) 1U else 2U val is_pc = reg == 7
val increment = if (byte_mode && !is_pc) 1U else 2U
return 0x80_FFFFu and when (mode and 0x7) { return 0x80_FFFFu and when (mode and 0x7) {
0 -> reg.toUInt() bis PADDR_REG_BIT 0 -> reg.toUInt() bis PADDR_REG_BIT
1 -> registers[reg].toUInt() 1 -> registers[reg].toUInt()
2 -> { 2 -> {
val addr = registers[reg] val addr = registers[reg]
registers[reg] = (addr + increment).toUShort() registers[reg] = (addr + increment).toUShort()
addr.toUInt() addr.toUInt().bit(PADDR_ISPACE_BIT, is_pc)
} }
3 -> { 3 -> {
val addr = registers[reg] val addr = registers[reg]
registers[reg] = (addr + 2U).toUShort() registers[reg] = (addr + 2U).toUShort()
core.getw(addr).toUInt() core.getw(addr, dspace = !is_pc).toUInt()
} }
4 -> { 4 -> {
registers[reg] = (registers[reg] - increment).toUShort() registers[reg] = (registers[reg] - increment).toUShort()
return registers[reg].toUInt() return registers[reg].toUInt().bit(PADDR_ISPACE_BIT, is_pc)
} }
5 -> { 5 -> {
registers[reg] = (registers[reg] - 2U).toUShort() registers[reg] = (registers[reg] - 2U).toUShort()
core.getw(registers[reg]).toUInt() core.getw(registers[reg], dspace = !is_pc).toUInt()
} }
6 -> { 6 -> {
val idx = core.getw(pc) val idx = core.getw(pc, dspace = false)
pc = (pc + 2u).toUShort() pc = (pc + 2u).toUShort()
idx + registers[reg] (idx + registers[reg]) and 0xFFFFu
} }
7 -> { 7 -> {
val idx = core.getw(pc) val idx = core.getw(pc, dspace = false)
pc = (pc+2u).toUShort() pc = (pc+2u).toUShort()
core.getw((idx+registers[reg]).toUShort()).toUInt() core.getw((idx+registers[reg]).toUShort()).toUInt()
} }
@@ -226,6 +239,9 @@ class CPU(val mbus: MemBus) {
/// Internal step; evaluates one opcode, but does not handle errors, interrupts, or updating system registers /// Internal step; evaluates one opcode, but does not handle errors, interrupts, or updating system registers
fun step_int() { fun step_int() {
if (debugMode) {
logger.debug("${pc.toString(8).padStart(6, '0')}: ${dasm.dasm_at(pc)}")
}
val opcode = core.getw(pc).toInt() val opcode = core.getw(pc).toInt()
pc = (pc + 2u).toUShort() pc = (pc + 2u).toUShort()
when (opcode and 0xF000) { when (opcode and 0xF000) {
@@ -618,7 +634,7 @@ class CPU(val mbus: MemBus) {
0x7000 -> when (opcode shr 9 and 0x7) { 0x7000 -> when (opcode shr 9 and 0x7) {
0 -> { // MUL 0 -> { // MUL
val r = opcode shr 6 and 0x7 val r = opcode shr 6 and 0x7
val src = op_loadw(opc_src(opcode)).toShort().toInt() val src = op_loadw(opc_dst(opcode)).toShort().toInt()
val res = registers[r].toShort().toInt() * src val res = registers[r].toShort().toInt() * src
registers[r bis 1] = (res shr 16).toUShort() registers[r bis 1] = (res shr 16).toUShort()
registers[r] = res.toUShort() registers[r] = res.toUShort()
@@ -629,7 +645,7 @@ class CPU(val mbus: MemBus) {
} // MUL } // MUL
1 -> { // DIV 1 -> { // DIV
val r = opcode shr 6 and 0x7 val r = opcode shr 6 and 0x7
val src = op_loadw(opc_src(opcode)).toInt() val src = op_loadw(opc_dst(opcode)).toInt()
val lho = (registers[r].toUInt() shl 16 or registers[r bis 1].toUInt()).toInt() val lho = (registers[r].toUInt() shl 16 or registers[r bis 1].toUInt()).toInt()
if (src != 0) { if (src != 0) {
val quot = lho / src val quot = lho / src
@@ -647,7 +663,7 @@ class CPU(val mbus: MemBus) {
} // DIV } // DIV
2 -> { // ASH 2 -> { // ASH
val r = opcode shr 6 and 0x7 val r = opcode shr 6 and 0x7
var count = (op_loadb(opc_src(opcode)) and 0x3Fu).toInt() var count = (op_loadb(opc_dst(opcode)) and 0x3Fu).toInt()
val src = registers[r].toShort().toInt() // two casts to sign extend val src = registers[r].toShort().toInt() // two casts to sign extend
count = count sex 6 count = count sex 6
V = false V = false
@@ -674,7 +690,7 @@ class CPU(val mbus: MemBus) {
} // ASH } // ASH
3 -> { // ASHC 3 -> { // ASHC
val r = opcode shr 6 and 0x7 val r = opcode shr 6 and 0x7
var count = (op_loadb(opc_src(opcode)) and 0x3Fu).toInt() sex 6 var count = (op_loadb(opc_dst(opcode)) and 0x3Fu).toInt() sex 6
val src = (registers[r].toUInt() shl 16 or registers[r or 1].toUInt()).toInt() // two casts to sign extend val src = (registers[r].toUInt() shl 16 or registers[r or 1].toUInt()).toInt() // two casts to sign extend
V = false V = false
val res = if (count > 0) { val res = if (count > 0) {
@@ -782,9 +798,9 @@ class CPU(val mbus: MemBus) {
try { try {
if (runState == RunState.HALTED) return if (runState == RunState.HALTED) return
// TODO: handle PIRQ
for (i in 7 downTo (psw_priority + 1)) { for (i in 7 downTo (psw_priority + 1)) {
if (pirq bit 8+i) { if (pirq bit 8+i) {
logger.debug("PIRQ{} trap to 0xA0", i)
trap(0xA0u) trap(0xA0u)
break break
} }
@@ -792,12 +808,16 @@ class CPU(val mbus: MemBus) {
if (source != null) { if (source != null) {
// we might have been waiting for an interrupt // we might have been waiting for an interrupt
runState = RunState.RUNNING runState = RunState.RUNNING
trap(source.vector) val vector = source.vector
logger.debug("Unibus interrupt at pri {} to {}", i, vector)
trap(vector)
source.handled() source.handled()
break break
} }
} }
if (runState == RunState.WAIT_FOR_INTERRUPT) return if (runState == RunState.WAIT_FOR_INTERRUPT) {
return
}
// System.err.println("Executing insn at ${pc.toString(8)}") // System.err.println("Executing insn at ${pc.toString(8)}")
step_int() step_int()
// TODO: handle T bit // TODO: handle T bit
@@ -808,9 +828,9 @@ class CPU(val mbus: MemBus) {
is NonExistentMemoryError -> cpu_err or 0x20u is NonExistentMemoryError -> cpu_err or 0x20u
is BusTimeoutError -> cpu_err or 0x10u is BusTimeoutError -> cpu_err or 0x10u
} }
trap(4u) trap(0x04u)
} catch (_: InvalidOpcodeException) { } catch (_: InvalidOpcodeException) {
trap(10u) trap(0x10u)
} }
} }
@@ -824,14 +844,18 @@ class CPU(val mbus: MemBus) {
} }
fun trap(vector: UShort) { fun trap(vector: UShort) {
stack_push(psw) logger.debug("Trap to {}", vector.toString(8))
val old_psw = psw
// update PSW first so that this gets pushed to the
psw = core.getw((vector + 2u).toUShort())
stack_push(old_psw)
stack_push(pc) stack_push(pc)
pc = core.getw(vector) pc = core.getw(vector)
psw = core.getw((vector + 2u).toUShort())
} }
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) {
0x3FFE6u -> control_reg
0x3FFF0u -> (mbus.size shr 6).toUShort() 0x3FFF0u -> (mbus.size shr 6).toUShort()
0x3FFF2u -> 0u // upper size 0x3FFF2u -> 0u // upper size
0x3FFF4u -> 0x1170u // system ID 0x3FFF4u -> 0x1170u // system ID
@@ -843,6 +867,7 @@ class CPU(val mbus: MemBus) {
} }
override fun setw(addr: UInt, value: UShort) = when (addr) { override fun setw(addr: UInt, value: UShort) = when (addr) {
0x3FFE6u -> 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

View File

@@ -6,6 +6,7 @@ import com.thequux.mcpdp.ext.bit.bit
import com.thequux.mcpdp.ext.bit.shr import com.thequux.mcpdp.ext.bit.shr
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
enum class AccessAction { enum class AccessAction {
Allow, Allow,
@@ -43,20 +44,27 @@ private data class PDR(val plf: UShort, var A: Boolean, var W: Boolean, var ed:
val range: UIntRange val range: UIntRange
get() = if (ed) { get() = if (ed) {
(0x2000U - (plf.toUInt() shl 6))..0x1FFFu (plf.toUInt() shl 6) ..< 0x2000u
} else { } else {
0U..((plf.toUInt() shl 6) -1U) 0U..< (plf.toUInt() shl 6)
} }
fun touched() { A = true } fun touched() { A = true }
fun written() { A = true; W = true } fun written() { A = true; W = true }
} }
private enum class MManMode(val mmanEnable: Boolean, val addrMask: UInt, val hipageMask: UInt) {
MM_16(addrMask = 0xFFFFu, mmanEnable = false, hipageMask = 0xF000u),
MM_18(addrMask = 0x3_FFFFu, mmanEnable = true, hipageMask = 0x3_E000u),
MM_22(addrMask = 0x3F_FFFFu, mmanEnable = true, hipageMask = 0x3C_0000u),
}
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
class PagingUnit(val pspace: PAddressSpace): VAddressSpace { class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
private var mmr = UShortArray(4) private var mmr = UShortArray(4)
private var enableUnibusMap: Boolean = false private var enableUnibusMap: Boolean = false
private var enable22bit: Boolean = false private var enable22bit: Boolean = false
private var mapMode: MManMode = MManMode.MM_16
/// The 18-bit address space exposed to peripherals /// The 18-bit address space exposed to peripherals
val unibusMap: PAddressSpace = UnibusMap() val unibusMap: PAddressSpace = UnibusMap()
@@ -102,20 +110,30 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
throw Trap(0xA8) throw Trap(0xA8)
} }
} }
return addr.toUInt() + (par.toUInt() shl 6) and 0x3F_FFFFu val tmp1 = addr.toUInt() + (par.toUInt() shl 6) and mapMode.addrMask
if (tmp1 and mapMode.hipageMask == mapMode.hipageMask) {
return tmp1 or 0x3C_0000u
} else {
return tmp1
}
} }
} }
var mode: Int = 0 var mode: Int = 0
set(value) { set(value) {
field = value field = value
modeSpace = if (mmr[0] bit 0) { updateMode()
modeVTabs[if (field == 3) 2 else field]
} else {
noMmanSpace
}
} }
fun updateMode() {
mapMode = when {
!(mmr[0] bit 0) -> MManMode.MM_16
enable22bit -> MManMode.MM_22
else -> MManMode.MM_18
}
modeSpace = if (mapMode.mmanEnable) modeVTabs[max(mode, 2)] else noMmanSpace
}
private val itabs: Array<PageTable> = Array(3) { PageTable(if (it == 2) 3 else it, dspace = false) } private val 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(itabs[it], dtabs[it], false) }
@@ -141,7 +159,13 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
} }
private inner class NoMmanSpace: VAddressSpace { private inner class NoMmanSpace: VAddressSpace {
private fun map(addr: UShort): UInt = if ((addr shr 13) == 7u.toUShort()) addr.toUInt().or(0x3F0000u) else addr.toUInt() private fun map(addr: UShort): UInt {
if ((addr shr 13) == 7u.toUShort()) {
return addr.toUInt() or 0x3F0000u
} else {
return addr.toUInt()
}
}
override fun getb(addr: UShort): UByte = pspace.getb(map(addr)) override fun getb(addr: UShort): UByte = pspace.getb(map(addr))
override fun getw(addr: UShort, dspace: Boolean): UShort = pspace.getw(map(addr)) override fun getw(addr: UShort, dspace: Boolean): UShort = pspace.getw(map(addr))
override fun setb(addr: UShort, value: UByte) = pspace.setb(map(addr), value) override fun setb(addr: UShort, value: UByte) = pspace.setb(map(addr), value)
@@ -149,20 +173,34 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
} }
companion object { companion object {
private val MMR0: UInt = 0x3FF8Au
private val MMR1: UInt = 0x3FF8Cu
private val MMR2: UInt = 0x3FF8Eu
private val MMR3: UInt = 0x3F54Eu private val MMR3: UInt = 0x3F54Eu
} }
override fun getw(addr: UShort, dspace: Boolean): UShort = modeSpace.getw(addr, dspace) private fun <E> withRecovery(addr: UShort, op: PagingUnit.() -> E): E {
try {
return this.op()
} catch (e: MemoryError) {
e.addr = addr.toUInt()
throw e
}
}
override fun getw(addr: UShort, dspace: Boolean): UShort = withRecovery(addr) { modeSpace.getw(addr, dspace) }
override fun getb(addr: UShort): UByte = modeSpace.getb(addr) override fun getb(addr: UShort): UByte = withRecovery(addr) { modeSpace.getb(addr) }
override fun setw(addr: UShort, value: UShort, dspace: Boolean) = modeSpace.setw(addr, value, dspace) override fun setw(addr: UShort, value: UShort, dspace: Boolean) = withRecovery(addr) { modeSpace.setw(addr, value, dspace) }
override fun setb(addr: UShort, value: UByte) = modeSpace.setb(addr, value) override fun setb(addr: UShort, value: UByte) = withRecovery(addr) { modeSpace.setb(addr, value) }
private inner class ConfigRegisters: PAddressSpace { private inner class ConfigRegisters: PAddressSpace {
override fun getw(addr: UInt): UShort = when (addr) { override fun getw(addr: UInt): UShort = when (addr) {
MMR0 -> mmr[0]
MMR1 -> mmr[1]
MMR2 -> mmr[2]
MMR3 -> { MMR3 -> {
(0U.bit(0, modeVTabs[2].useDSpace) (0U.bit(0, modeVTabs[2].useDSpace)
.bit(1, modeVTabs[1].useDSpace) .bit(1, modeVTabs[1].useDSpace)
@@ -181,6 +219,7 @@ class PagingUnit(val pspace: PAddressSpace): VAddressSpace {
modeVTabs[0].useDSpace = value bit 2 modeVTabs[0].useDSpace = value bit 2
modeVTabs[1].useDSpace = value bit 1 modeVTabs[1].useDSpace = value bit 1
modeVTabs[2].useDSpace = value bit 0 modeVTabs[2].useDSpace = value bit 0
updateMode()
} }
in 0x3F080u..0x3F0FFu -> { in 0x3F080u..0x3F0FFu -> {
val uaddr = (addr shr 1 and 31u).toInt() val uaddr = (addr shr 1 and 31u).toInt()

View File

@@ -0,0 +1,241 @@
package com.thequux.mcpdp.util
import com.thequux.mcpdp.core.CPU
import com.thequux.mcpdp.core.InvalidOpcodeException
import com.thequux.mcpdp.core.VAddressSpace
import com.thequux.mcpdp.ext.bit.*
object DebugTools {
}
class NullDisassembler() {
fun dasm_at(loc: UShort): String = ""
}
class Disassembler(val core: VAddressSpace) {
var vpc: UShort = 0u
var opc: UShort = 0u
var opcode: Int = 0
private fun fmt(opcode: String, vararg args: String): String {
val res = StringBuilder()
res.append(opcode.uppercase())
for ((index, arg) in args.withIndex()) {
if (index == 0) {
res.append("\t")
} else {
res.append(", ")
}
res.append(arg)
}
return res.toString()
}
private fun reg_name(reg: Int): String {
return when(reg) {
6 -> "SP"
7 -> "PC"
else -> "R$reg"
}
}
private fun getw(): UShort {
val ret = core.getw(vpc, dspace = false)
vpc = vpc.inc().inc()
return ret
}
private fun arg_at(offset: Int): String {
val rv = opcode shr offset and 0x3F
val reg = rv and 0x7
val rn = reg_name(reg)
val mode = rv shr 3 and 0x6
val ind = if (rv bit 3) "@" else ""
return when (mode) {
0 -> "$ind$rn"
2 -> if (reg == 7) "$ind#${getw().toString(8)}" else "$ind($rn)+"
4 -> "$ind-($rn)"
6 -> if (reg == 7) {
ind + (getw() + vpc).toShort().toString(8)
} else {
"$ind${getw().toString(8)}($rn)"
}
else -> throw Exception("Failed to decode arg: ${rv.toString(8)}")
}
}
private fun dst() = arg_at(0)
private fun src() = arg_at(6)
private fun reg0(): String = reg_name(opcode and 0x7)
private fun reg6(): String = reg_name(opcode shr 6 and 0x7)
private fun br_rel(opc: String): String {
val rel = (opcode and 0xFF) - (opcode and 0x80 shl 1)
val dst = (vpc.toInt() + rel).toUShort()
return fmt(opc, dst.toString(8))
}
private fun rel6(): String {
val rel = (opcode and 0x3F) - (opcode and 0x20 shl 1)
val dst = vpc.toInt() + rel
return dst.toUShort().toString(8)
}
fun dasm_at(loc: UShort): String {
var vpc = loc
opcode = core.getw(vpc, dspace = false).toInt()
vpc = (vpc + 2u).toUShort()
try {
return when (opcode and 0xF000) {
0x0, 0x8000 -> when (opcode and 0xFF00) {
0x0000 -> when (opcode) {
0x0000 -> fmt("HALT") // HALT
0x0001 -> fmt("WAIT")
0x0002 -> fmt("WTI")
0x0003 -> fmt("BPT")
0x0004 -> fmt("IOT")
0x0005 -> fmt("RESET")
0x0006 -> fmt("RTT")
in 0x40..0x7f -> fmt("JMP", dst()) // JMP
in 0x80..0x87 -> fmt("RTS", reg0()) // RTS
in 0x98..0x9F -> fmt("SPL", (opcode and 7).toString())
0xBF -> fmt("SCC")
in 0xA0..0xBE -> {
val items: ArrayList<String> = ArrayList()
if (opcode bit 0) items.add("SEC")
if (opcode bit 1) items.add("SEZ")
if (opcode bit 2) items.add("SEV")
if (opcode bit 3) items.add("SEN")
items.joinToString(" ")
} // Scc/Ccc
in 0xC0..0xFF -> fmt("SWAB", dst()) // SWAB
else -> throw InvalidOpcodeException()
}
0x0100 -> br_rel("BR") // BR
0x0200 -> br_rel("BNE") // BNE
0x0300 -> br_rel("BEQ") // BEQ
0x0400 -> br_rel("BGE") // BGE
0x0500 -> br_rel("BLT") // BLT
0x0600 -> br_rel("BGT") // BGT
0x0700 -> br_rel("BLE") // BLE
0x0800, 0x0900 -> fmt("JSR", reg6(), dst()) // JSR
0x0A00 -> when (opcode shr 6 and 3) {
0 -> fmt("CLR", dst()) // CLR
1 -> fmt("COM", dst()) // COM
2 -> fmt("INC", dst()) // INC
3 -> fmt("DEC", dst()) // DEC
else -> throw InvalidOpcodeException()
}
0x0B00 -> when (opcode shr 6 and 3) {
0 -> fmt("NEG", dst()) // NEG
1 -> fmt("ADC", dst()) // ADC
2 -> fmt("SBC", dst()) // SBC
3 -> fmt("TST", dst()) // TST
else -> throw InvalidOpcodeException()
}
0x0C00 -> when (opcode shr 6 and 3) {
0 -> fmt("ROR", dst()) // ROR
1 -> fmt("ROL", dst()) // ROL
2 -> fmt("ASR", dst()) // ASR
3 -> fmt("ASL", dst()) // ASL
else -> throw InvalidOpcodeException()
}
0x0D00 -> when (opcode shr 6 and 3) {
0 -> fmt("MARK", (opcode and 0x3F).toString(8)) // MARK
1 -> {
throw InvalidOpcodeException()
} // MFPI // TODO
2 -> {
throw InvalidOpcodeException()
} // MTPI // TODO
3 -> fmt("SXT", dst()) // SXT
else -> throw InvalidOpcodeException()
}
0x0F00 -> throw InvalidOpcodeException() // CSM
0x8000 -> br_rel("BPL") // BPL
0x8100 -> br_rel("BMI") // BMI
0x8200 -> br_rel("BHI") // BHI
0x8300 -> br_rel("BLOS") // BLOS
0x8400 -> br_rel("BVC") // BVC
0x8500 -> br_rel("BVS") // BVS
0x8600 -> br_rel("BHIS") // BCC/BHIS
0x8700 -> br_rel("BLO") // BCS/BLO
0x8800 -> fmt("EMT", (opcode and 0xFF).toString(8)) // EMT
0x8900 -> fmt("TRAP", (opcode and 0xFF).toString(8)) // TRAP
0x8A00 -> when (opcode shr 6 and 3) {
0 -> fmt("CLRB", dst()) // CLRB
1 -> fmt("COMB", dst()) // COMB
2 -> fmt("INCB", dst()) // INC
3 -> fmt("DECB", dst()) // DEC
else -> throw InvalidOpcodeException()
}
0x8B00 -> when (opcode shr 6 and 3) {
0 -> fmt("NEGB", dst()) // NEGB
1 -> fmt("ADCB", dst()) // ADCB
2 -> fmt("SBCB", dst()) // SBCB
3 -> fmt("TSTB", dst()) // TSTB
else -> throw InvalidOpcodeException()
}
0x8C00 -> when (opcode shr 6 and 3) {
0 -> fmt("RORB", dst()) // RORB
1 -> fmt("ROLB", dst()) // ROLB
2 -> fmt("ASRB", dst()) // ASRB
3 -> fmt("ASLB", dst()) // ASLB
else -> throw InvalidOpcodeException()
}
0x8D00 -> when (opcode shr 6 and 3) {
1 -> {
throw InvalidOpcodeException()
} // MFPD // TODO
2 -> {
throw InvalidOpcodeException()
} // MTPD // TODO
else -> throw InvalidOpcodeException()// Reserved
}
else -> throw InvalidOpcodeException()
}
0x1000 -> fmt("MOV", src(), dst()) // MOV
0x2000 -> fmt("CMP", src(), dst()) // CMP
0x3000 -> fmt("BIT", src(), dst()) // BIT
0x4000 -> fmt("BIC", src(), dst()) // BIC
0x5000 -> fmt("BIS", src(), dst()) // BIS
0x6000 -> fmt("ADD", src(), dst()) // ADD
0x7000 -> when (opcode shr 9 and 0x7) {
0 -> fmt("MUL", reg6(), dst()) // MUL
1 -> fmt("DIV", reg6(), dst()) // DIV
2 -> fmt("ASH", reg6(), dst()) // ASH
3 -> fmt("ASHC", reg6(), dst()) // ASHC
4 -> fmt("XOR", reg6(), dst()) // XOR
5, 6 -> throw InvalidOpcodeException()
7 -> fmt("SOB", reg6(), rel6()) // SOB
else -> throw InvalidOpcodeException()
}
// 0x800 handled above
0x9000 -> fmt("MOVB", src(), dst()) // MOVB
0xA000 -> fmt("CMPB", src(), dst()) // CMPB
0xB000 -> fmt("BITB", src(), dst()) // BITB
0xC000 -> fmt("BICB", src(), dst()) // BICB
0xD000 -> fmt("BISB", src(), dst()) // BISB
0xE000 -> fmt("SUB", src(), dst()) // SUB
else -> throw InvalidOpcodeException()
}
} catch (_: InvalidOpcodeException) {
return fmt(".WORD", opcode.toUShort().toString(8))
}
}
}