From 3f85ee0603f950a17301a56483d28e12bf9db772 Mon Sep 17 00:00:00 2001 From: TQ Hirsch Date: Wed, 20 Sep 2023 11:34:46 +0200 Subject: [PATCH] 25x speedup by moving to switch table --- src/main/kotlin/Main.kt | 4 +- src/main/kotlin/com/thequux/mcpdp/core/CPU.kt | 1148 +++++++++-------- 2 files changed, 584 insertions(+), 568 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 4c9fb91..8b5e2df 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -19,12 +19,12 @@ fun main(args: Array) { cpu.runState = CPU.RunState.RUNNING cpu.pc = 0x80u val start = System.nanoTime() - val ninsn = cpu.run(50000000) + val ninsn = cpu.run(600000000) val end = System.nanoTime() System.err.println("Halted at 0${cpu.pc.toString(8)}") val time = (end - start).toDouble() / 1_000_000_000.0 - println("Executed ${ninsn} in ${time}s: ${ninsn / time} i/s") + println("Executed ${ninsn} in ${time}s: ${ninsn / time / 1_000_000} MIPS") } finally { println("Exiting") console.stop() diff --git a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt index e18eac0..46e8540 100644 --- a/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt +++ b/src/main/kotlin/com/thequux/mcpdp/core/CPU.kt @@ -19,6 +19,587 @@ class CPU(val mbus: MemBus) { companion object { val debugMode = System.getProperty("jdp11.itrace").toBoolean() + + private val insnTable: Array Unit> = Array(256) {{throw InvalidOpcodeException()}} + + // Construct instruction table + init { + insnTable[0x00] = { opcode -> when (opcode) { + 0x0000 -> { + if (cur_mode == 0) + runState = RunState.HALTED + } // HALT + 0x0001 -> runState = RunState.WAIT_FOR_INTERRUPT // WAIT + 0x0002 -> { // RTI + pc = stack_pop() + psw = stack_pop() // TODO: check privilege on mode; check psw[11] + } // RTI + 0x0003 -> trap(0x0Cu) // BPT + 0x0004 -> trap(0x10u) // IOT + 0x0005 -> throw InvalidOpcodeException() // bus reset TODO: bus init + 0x0006 -> { + // TODO: handle suspending the trace trap + pc = stack_pop() + psw = stack_pop() + } // RTT + in 0x40..0x7f -> { + // jmp + val dst = opc_dst(opcode) + if (is_paddr_reg(dst)) { + trap(4u); // Illegal instruction + } + pc = dst.toUShort() + } // JMP + in 0x80..0x87 -> { + val reg = opcode and 0x7 + pc = registers[reg] + registers[reg] = stack_pop() + } // RTS + in 0x98..0x9F -> { + psw_priority = opcode and 0x7 + } // SPL + in 0xA0..0xBF -> { + val flag = opcode bit 4 + if (opcode bit 0) C = flag + if (opcode bit 1) V = flag + if (opcode bit 2) Z = flag + if (opcode bit 3) N = flag +// debugFlags() + } // Scc/Ccc + in 0xC0..0xFF -> { + val dst = opc_dst(opcode) + val v = op_loadw(dst) + val res = (v shl 8) or (v shr 8) + op_storw(dst, res) + V = false + C = false + N = res bit 7 + Z = (res and 0xFFu) == 0.toUShort() + } // SWAB + else -> throw InvalidOpcodeException() + } } + insnTable[0x01] = { br_rel(true, it) } // BR + insnTable[0x02] = { br_rel(!Z, it) } // BNE + insnTable[0x03] = { br_rel(Z, it) } // BEQ + insnTable[0x04] = { br_rel(N == V, it) } // BGE + insnTable[0x05] = { br_rel(N xor V, it) } // BLT + insnTable[0x06] = { br_rel(!Z and (N == V), it) } // BGT + insnTable[0x07] = { br_rel(Z or (N xor V), it) } // BLE + insnTable[0x08] = { opcode -> // JSR + val r = opcode shr 6 and 0x7 + val dst = opc_dst(opcode) + if (is_paddr_reg(dst)) { + trap(4u) // illegal opcode + } + stack_push(registers[r]) + registers[r] = pc + pc = dst.toUShort() + } // JSR + insnTable[0x09] = insnTable[0x08] + insnTable[0x0A] = {opcode -> + when (opcode shr 6 and 3) { + 0 -> { // CLR + op_storw(opc_dst(opcode), 0U) + N = false + V = false + C = false + Z = true + } // CLR + 1 -> { // COM + val dst = opc_dst(opcode) + val res = op_loadw(dst).inv().also { op_storw(dst, it) } + N = res bit 15 + Z = res == 0U.toUShort() + C = true + V = false + } // COM + 2 -> { // INC + val dst = opc_dst(opcode) + val src = op_loadw(dst) + val res = src.inc() + op_storw(dst, res) + N = res bit 15 + Z = res == 0.toUShort() + V = res == 0x8000.toUShort() + } // INC + 3 -> { // DEC + val dst = opc_dst(opcode) + val res = op_loadw(dst).dec().also { op_storw(dst, it) } + N = res bit 15 + Z = res == 0.toUShort() + V = res == 0x7FFF.toUShort() + } // DEC + } + } // CLR, COM, INC, DEC + insnTable[0x0B] = { opcode -> + when (opcode shr 6 and 3) { + 0 -> { // NEG + val dst = opc_dst(opcode) + val res = op_loadw(dst).inv().inc() + op_storw(dst, res) + N = res bit 15 + Z = res == 0.toUShort() + V = res == 0x8000.toUShort() + C = !Z + } // NEG + 1 -> { // ADC + val dst = opc_dst(opcode) + val c: UShort = if (C) 1u else 0u + val res = (op_loadw(dst) + c).toUShort() + op_storw(dst, res) + N = res bit 15 + Z = res == 0u.toUShort() + V = (res == 0x8000u.toUShort()) and C + C = Z and C + } // ADC + 2 -> { + val dst = opc_dst(opcode) + val src = op_loadw(dst) + val res = if (C) src.dec() else src + op_storw(dst, res) + N = res bit 15 + Z = res == 0.toUShort() + V = res == 0x8000.toUShort() + C = C and (src == 0.toUShort()) + } // SBC + 3 -> { + val dst = op_loadw(opc_dst(opcode)) + Z = dst == 0.toUShort() + N = dst bit 15 + V = false + C = false + } // TST + } + } // NEG, ADC, SBC, TST + insnTable[0x0C] = { opcode -> + when (opcode shr 6 and 3) { + 0 -> { + val dst = opc_dst(opcode) + val src = op_loadw(dst) + val res = (src shr 1).bit(15, C) + op_storw(dst, res) + C = src bit 0 + N = res bit 15 + Z = res == 0.toUShort() + V = N xor C + } // ROR + 1 -> { + val dst = opc_dst(opcode) + val src = op_loadw(dst) + val res = (src shl 1).bit(0, C) + op_storw(dst, res) + C = src bit 15 + N = res bit 15 + Z = res == 0.toUShort() + V = N xor C + } // ROL + 2 -> { // ASR + val dst = opc_dst(opcode) + val src = op_loadw(dst).toShort() + val res = (src shr 1).toUShort() + op_storw(dst, res) + N = res bit 15 + Z = res == 0.toUShort() + C = src bit 0 + V = N xor C + } // ASR + 3 -> { // ASL + val dst = opc_dst(opcode) + val src = op_loadw(dst) + val res = src shl 1 + op_storw(dst, res.toUShort()) + N = res bit 15 + Z = res == 0.toUShort() + C = src and 0x8000u != 0u.toUShort() + V = N xor C + } // ASL + } + } // ROR, ROL, ASR, ASL + insnTable[0x0D] = { opcode -> + when (opcode shr 6 and 3) { + 0 -> { // MARK + val count = opcode and 0x3F + sp = (sp + (2 * count).toUInt()).toUShort() + pc = registers[5] + registers[5] = stack_pop() + } // MARK + 1 -> { throw InvalidOpcodeException() } // MFPI // TODO + 2 -> { throw InvalidOpcodeException() } // MTPI // TODO + 3 -> { + op_storw(opc_dst(opcode), if (N) (-1).toUShort() else 0.toUShort()) + Z = !N + V = false + } // SXT + } + } // MARK, MFPI, MTPI, SXT + // insnTable[0x0E] = // TODO: check this + // insnTable[0x0F] = invalid + + + for (i in 0x10..0x1F) insnTable[i] = { opcode -> // MOV + val src = opc_src(opcode) + val dst = opc_dst(opcode) + op_loadw(src).also { + op_storw(dst, it) + N = it bit 15 + Z = it == 0.toUShort() + V = false + } + } // MOV + for (i in 0x20..0x2F) insnTable[i] = { opcode -> // CMP + val src = op_loadw(opc_src(opcode)) + val src2 = op_loadw(opc_dst(opcode)) + val res = (src - src2) and 0xFFFFu + N = res bit 15 + Z = res == 0U + C = src < src2 // unsigned lt + V = ((src bit 15) xor (src2 bit 15)) and ((src2 bit 15) == (res bit 15)) + } // CMP + for (i in 0x30..0x3F) insnTable[i] = { opcode -> // BIT + val src = opc_src(opcode) + val dst = opc_dst(opcode) + val res = op_loadw(dst) and op_loadw(src) + N = res bit 15 + Z = res == 0u.toUShort() + V = false + } // BIT + for (i in 0x40..0x4F) insnTable[i] = { opcode -> // BIC + val src = opc_src(opcode) + val dst = opc_dst(opcode) + val res = op_loadw(dst) and op_loadw(src).inv() + op_storw(dst, res) + N = res bit 15 + Z = res == 0u.toUShort() + V = false + } // BIC + for (i in 0x50..0x5F) insnTable[i] = { opcode -> // BIS + val src = opc_src(opcode) + val dst = opc_dst(opcode) + val res = op_loadw(dst) or op_loadw(src) + op_storw(dst, res) + N = res and 0x8000u != 0u.toUShort() + Z = res == 0u.toUShort() + V = false + } // BIS + for (i in 0x60..0x6F) insnTable[i] = { opcode -> // ADD + val src = opc_src(opcode) + val dst = opc_dst(opcode) + val srcv = op_loadw(src) + val dstv = op_loadw(dst) + val res = (srcv + dstv) + val resw = res.toUShort() + op_storw(dst, res.toUShort()) + N = resw > 0x7FFFu + Z = resw == 0.toUShort() + val src_sign = srcv and 0x8000u + V = (src_sign == dstv and 0x8000u) && (src_sign != resw and 0x8000u) + C = (res >= 0x10000u) + } // ADD + insnTable[0x70] = { opcode -> // MUL + val r = opcode shr 6 and 0x7 + val src = op_loadw(opc_dst(opcode)).toShort().toInt() + val res = registers[r].toShort().toInt() * src + registers[r bis 1] = (res shr 16).toUShort() + registers[r] = res.toUShort() + N = res bit 31 + Z = res == 0 + V = false + C = (res shr 16) == -(res shr 15 and 1) // check if overflow extends the sign bit + } // MUL + insnTable[0x72] = { opcode -> // DIV + val r = opcode shr 6 and 0x7 + val src = op_loadw(opc_dst(opcode)).toInt() + val lho = (registers[r].toUInt() shl 16 or registers[r bis 1].toUInt()).toInt() + if (src != 0) { + val quot = lho / src + val rem = lho % src + registers[r] = quot.toUShort() + registers[r bis 1] = rem.toUShort() + val overflow = quot shr 16 + V = overflow == -(quot shr 15 and 1) // check if overflow extends the sign bit + N = quot bit 15 + Z = quot == 0 + } else { + C = true + V = true + } + } // DIV + insnTable[0x74] = { opcode -> // ASH + val r = opcode shr 6 and 0x7 + var count = (op_loadb(opc_dst(opcode)) and 0x3Fu).toInt() + val src = registers[r].toShort().toInt() // two casts to sign extend + count = count sex 6 + V = false + val res = if (count > 0) { + C = (src shl (count-1)) bit 15 + val shifted = if (count < 16) { + src shr 16-count + } else { + src + } + V = (shifted != 0) and (shifted != -1) + src shl count + } else if (count < 0) { + count = -count + C = (src shr (count-1)) bit 0 + src shr count + } else { + C = false + src + } + registers[r] = res.toUShort() + N = res < 0 + Z = res == 0 + } // ASH + insnTable[0x76] = { opcode -> // ASHC + val r = opcode shr 6 and 0x7 + 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 + V = false + val res = if (count > 0) { + C = (src shl (count-1)) bit 31 + val shifted = src shr 32-count + V = (shifted != 0) and (shifted != -1) + src shl count + } else if (count < 0) { + count = -count + C = (src shr (count-1)) bit 0 + src shr count + } else { + C = false + src + } + registers[r] = (res and 0xFFFF).toUShort() + registers[r or 1] = (res shr 16 and 0xFFFF).toUShort() + N = res < 0 + Z = res == 0 + } // ASHC + insnTable[0x78] = {opcode -> // XOR + val r = opcode shr 6 and 7 + val dst = opc_dst(opcode) + val res = op_loadw(dst) xor registers[r] + op_storw(dst, res) + N = res bit 15 + Z = res == 0.toUShort() + V = false + } // XOR + // 0x7A and 0x7C are undefined + insnTable[0x7E] = { opcode -> // SOB + val reg = opcode shr 6 and 7 + registers[reg] = registers[reg].dec() + if (registers[reg] != 0.toUShort()) { + pc = (pc.toInt() - (opcode and 0x3F shl 1)).toUShort() + } + } // SOB + insnTable[0x71] = insnTable[0x70] + insnTable[0x73] = insnTable[0x72] + insnTable[0x75] = insnTable[0x74] + insnTable[0x77] = insnTable[0x76] + insnTable[0x79] = insnTable[0x78] + insnTable[0x7F] = insnTable[0x7E] + + insnTable[0x80] = { br_rel(!N, it) } // BPL + insnTable[0x81] = { br_rel(N, it) } // BMI + insnTable[0x82] = { br_rel(!C and !Z, it) } // BHI + insnTable[0x83] = { br_rel(C or Z, it) } // BLOS + insnTable[0x84] = { br_rel(!V, it) } // BVC + insnTable[0x85] = { br_rel(V, it) } // BVS + insnTable[0x86] = { br_rel(!C, it) } // BCC/BHIS + insnTable[0x87] = { br_rel(C, it) } // BCS/BLO + insnTable[0x88] = { trap(0x18u) } // EMT + insnTable[0x89] = { trap(0x1Cu) } // TRAP + insnTable[0x8A] = { opcode -> + when (opcode shr 6 and 3) { + 0 -> { // CLRB + op_storb(opc_dstb(opcode), 0U) + N = false + V = false + C = false + Z = true + } // CLRB + 1 -> { // COMB + val dst = opc_dstb(opcode) + val res = op_loadb(dst).inv().also { op_storb(dst, it) } + N = res bit 7 + Z = res == 0U.toUByte() + C = true + V = false + } // COMB + 2 -> { // INC + val dst = opc_dstb(opcode) + val res = op_loadb(dst).inc().also { op_storb(dst, it) } + N = res bit 7 + Z = res == 0.toUByte() + V = res == 0x80.toUByte() + } // INCB + 3 -> { // DEC + val dst = opc_dstb(opcode) + val res = op_loadb(dst).dec().also { op_storb(dst, it) } + N = res bit 7 + Z = res == 0.toUByte() + V = res == 0x7F.toUByte() + } // DECB + } + } // CLRB, COMB, INCB, DECB + insnTable[0x8B] = { opcode -> + when (opcode shr 6 and 3) { + 0 -> { // NEGB + val dst = opc_dstb(opcode) + val res = op_loadb(dst).inv().inc() + op_storb(dst, res) + N = res bit 7 + Z = res == 0.toUByte() + V = res == 0x8000.toUByte() + C = !Z + } // NEGB + 1 -> { // ADCB + val dst = opc_dstb(opcode) + val c: UShort = if (C) 1u else 0u + val res = (op_loadb(dst) + c).toUByte() + op_storb(dst, res) + N = res bit 7 + Z = res == 0u.toUByte() + V = (res == 0x80u.toUByte()) and C + C = Z and C + } // ADCB + 2 -> { + val dst = opc_dstb(opcode) + val src = op_loadb(dst) + val res = if (C) src.dec() else src + op_storb(dst, res) + N = res bit 8 + Z = res == 0.toUByte() + V = res == 0x80.toUByte() + C = C and (src == 0.toUByte()) + } // SBCB + 3 -> { + val dst = op_loadb(opc_dstb(opcode)) + Z = dst == 0.toUByte() + N = dst bit 7 + V = false + C = false + } // TSTB + } + } // NEGB, ADCB, SBCB, TSTB + insnTable[0x8C] = { opcode -> + when (opcode shr 6 and 3) { + 0 -> { + val dst = opc_dstb(opcode) + val src = op_loadb(dst) + val res = (src shr 1).bit(7, C) + op_storb(dst, res) + C = src bit 0 + N = res bit 7 + Z = res == 0.toUByte() + V = N xor C + } // RORB + 1 -> { + val dst = opc_dstb(opcode) + val src = op_loadb(dst) + val res = (src shl 1).bit(0, C) + op_storb(dst, res) + C = src bit 7 + N = res bit 7 + Z = res == 0.toUByte() + V = N xor C + } // ROLB + 2 -> { // ASRB + val dst = opc_dstb(opcode) + val src = op_loadb(dst).toByte() + val res = (src shr 1).toUByte() + op_storb(dst, res) + N = res bit 7 + Z = res == 0.toUByte() + C = src bit 0 + V = N xor C + } // ASRB + 3 -> { // ASLB + val dst = opc_dstb(opcode) + val src = op_loadb(dst) + val res = (src shl 1).toUByte() + op_storw(dst, res.toUShort()) + N = res bit 7 + Z = res == 0.toUByte() + C = src bit 7 + V = N xor C + } // ASLB + } + } // RORB, ROLB, ASRB, ASLB + insnTable[0x8D] = { opcode -> + when (opcode shr 6 and 3) { + 1 -> { throw InvalidOpcodeException() } // MFPD // TODO + 2 -> { throw InvalidOpcodeException() } // MTPD // TODO + else -> { throw InvalidOpcodeException() } // Reserved + } + } // MFPD, MTPD + + for (i in 0x90..0x9F) insnTable[i] = { opcode -> // MOVB + val src = opc_srcb(opcode) + val dst = opc_dstb(opcode) + var dstv = op_loadb(src) + + var dstw = if (is_paddr_reg(dst)) { + op_storw(dst, dstv.toUShort() sex 8) + dstv.toUShort() sex 8 + } else { + op_storb(dst, dstv) + dstv.toUShort() + } + N = dstv bit 7 + Z = dstv == 0.toUByte() + V = false + + } // MOVB + for (i in 0xA0..0xAF) insnTable[i] = { opcode -> // CMPB + val src = op_loadb(opc_srcb(opcode)) + val src2 = op_loadb(opc_dstb(opcode)) + val res = (src - src2) and 0xFFu + N = res bit 7 + Z = res == 0U + C = src < src2 // unsigned lt + V = ((src bit 8) xor (src2 bit 8)) and ((src2 bit 8) == (res bit 8)) + } // CMPB + for (i in 0xB0..0xBF) insnTable[i] = { opcode -> // BITB + val src = opc_srcb(opcode) + val dst = opc_dstb(opcode) + val res = op_loadb(dst) and op_loadb(src) + N = res bit 7 + Z = res == 0u.toUByte() + V = false + } // BITB + for (i in 0xC0..0xCF) insnTable[i] = { opcode -> // BICB + val src = opc_srcb(opcode) + val dst = opc_dstb(opcode) + val res = op_loadb(dst) and op_loadb(src).inv() + op_storb(dst, res) + N = res bit 7 + Z = res == 0u.toUByte() + V = false + } // BICB + for (i in 0xD0..0xDF) insnTable[i] = { opcode -> // BISB + val src = opc_srcb(opcode) + val dst = opc_dstb(opcode) + val res = op_loadb(dst) or op_loadb(src) + op_storb(dst, res) + N = res bit 7 + Z = res == 0u.toUByte() + V = false + } // BISB + for (i in 0xE0..0xEF) insnTable[i] = { opcode -> + val src = opc_src(opcode) + val dst = opc_dst(opcode) + val srcv = op_loadw(src) + val dstv = op_loadw(dst) + val res = (dstv.toShort() - srcv.toShort()) + op_storw(dst, res.toUShort()) + N = res < 0 + Z = res == 0 + V = ((srcv bit 31) xor (dstv bit 15)) and ((srcv bit 15) == (res bit 31)) + C = (dst.toInt() + src.inv().inc().toInt()) >= 0x1_0000 + } // SUB + // insnTable[0x0E] = // TODO: check this + // insnTable[0x0F] = // TODO: check this + } } @@ -245,572 +826,7 @@ class CPU(val mbus: MemBus) { } val opcode = core.getw(pc).toInt() pc = (pc + 2u).toUShort() - when (opcode and 0xF000) { - 0x0, 0x8000 -> when (opcode and 0xFF00) { - 0x0000 -> when (opcode) { - 0x0000 -> { - if (cur_mode == 0) - runState = RunState.HALTED - } // HALT - 0x0001 -> runState = RunState.WAIT_FOR_INTERRUPT // WAIT - 0x0002 -> { // RTI - pc = stack_pop() - psw = stack_pop() // TODO: check privilege on mode; check psw[11] - } // RTI - 0x0003 -> trap(0x0Cu) // BPT - 0x0004 -> trap(0x10u) // IOT - 0x0005 -> throw InvalidOpcodeException() // bus reset TODO: bus init - 0x0006 -> { - // TODO: handle suspending the trace trap - pc = stack_pop() - psw = stack_pop() - } // RTT - in 0x40..0x7f -> { - // jmp - val dst = opc_dst(opcode) - if (is_paddr_reg(dst)) { - trap(4u); // Illegal instruction - } - pc = dst.toUShort() - } // JMP - in 0x80..0x87 -> { - val reg = opcode and 0x7 - pc = registers[reg] - registers[reg] = stack_pop() - } // RTS - in 0x98..0x9F -> { - psw_priority = opcode and 0x7 - } // SPL - in 0xA0..0xBF -> { - val flag = opcode bit 4 - if (opcode bit 0) C = flag - if (opcode bit 1) V = flag - if (opcode bit 2) Z = flag - if (opcode bit 3) N = flag -// debugFlags() - } // Scc/Ccc - in 0xC0..0xFF -> { - val dst = opc_dst(opcode) - val v = op_loadw(dst) - val res = (v shl 8) or (v shr 8) - op_storw(dst, res) - V = false - C = false - N = res bit 7 - Z = (res and 0xFFu) == 0.toUShort() - } // SWAB - else -> throw InvalidOpcodeException() - } - 0x0100 -> br_rel(true, opcode) // BR - 0x0200 -> br_rel(!Z, opcode) // BNE - 0x0300 -> br_rel(Z, opcode) // BEQ - 0x0400 -> br_rel(N == V, opcode) // BGE - 0x0500 -> br_rel(N xor V, opcode) // BLT - 0x0600 -> br_rel(!Z and (N == V), opcode) // BGT - 0x0700 -> br_rel(Z or (N xor V), opcode) // BLE - 0x0800, 0x0900 -> { // JSR - val r = opcode shr 6 and 0x7 - val dst = opc_dst(opcode) - if (is_paddr_reg(dst)) { - trap(4u) // illegal opcode - } - stack_push(registers[r]) - registers[r] = pc - pc = dst.toUShort() - } // JSR - 0x0A00 -> when (opcode shr 6 and 3) { - 0 -> { // CLR - op_storw(opc_dst(opcode), 0U) - N = false - V = false - C = false - Z = true - } // CLR - 1 -> { // COM - val dst = opc_dst(opcode) - val res = op_loadw(dst).inv().also { op_storw(dst, it) } - N = res bit 15 - Z = res == 0U.toUShort() - C = true - V = false - } // COM - 2 -> { // INC - val dst = opc_dst(opcode) - val src = op_loadw(dst) - val res = src.inc() - op_storw(dst, res) - N = res bit 15 - Z = res == 0.toUShort() - V = res == 0x8000.toUShort() -// debugFlags() -// logger.debug("RV: ${dst.toString(16)} RES: ${res.toString(16)}, SRC: ${src.toString(16)}") - - } // INC - 3 -> { // DEC - val dst = opc_dst(opcode) - val res = op_loadw(dst).dec().also { op_storw(dst, it) } - N = res bit 15 - Z = res == 0.toUShort() - V = res == 0x7FFF.toUShort() - } // DEC - } - 0x0B00 -> when (opcode shr 6 and 3) { - 0 -> { // NEG - val dst = opc_dst(opcode) - val res = op_loadw(dst).inv().inc() - op_storw(dst, res) - N = res bit 15 - Z = res == 0.toUShort() - V = res == 0x8000.toUShort() - C = !Z - } // NEG - 1 -> { // ADC - val dst = opc_dst(opcode) - val c: UShort = if (C) 1u else 0u - val res = (op_loadw(dst) + c).toUShort() - op_storw(dst, res) - N = res bit 15 - Z = res == 0u.toUShort() - V = (res == 0x8000u.toUShort()) and C - C = Z and C - } // ADC - 2 -> { - val dst = opc_dst(opcode) - val src = op_loadw(dst) - val res = if (C) src.dec() else src - op_storw(dst, res) - N = res bit 15 - Z = res == 0.toUShort() - V = res == 0x8000.toUShort() - C = C and (src == 0.toUShort()) - } // SBC - 3 -> { - val dst = op_loadw(opc_dst(opcode)) - Z = dst == 0.toUShort() - N = dst bit 15 - V = false - C = false - } // TST - } - 0x0C00 -> when (opcode shr 6 and 3) { - 0 -> { - val dst = opc_dst(opcode) - val src = op_loadw(dst) - val res = (src shr 1).bit(15, C) - op_storw(dst, res) - C = src bit 0 - N = res bit 15 - Z = res == 0.toUShort() - V = N xor C -// debugFlags() -// logger.debug("RV: ${dst.toString(16)} RES: ${res.toString(16)}/${op_loadw(dst).toString(16)}, SRC: ${src.toString(16)}, C: ${src bit 15}") - } // ROR - 1 -> { - val dst = opc_dst(opcode) - val src = op_loadw(dst) - val res = (src shl 1).bit(0, C) - op_storw(dst, res) - C = src bit 15 - N = res bit 15 - Z = res == 0.toUShort() - V = N xor C -// debugFlags() -// logger.debug("RES: ${res.toString(16)}, SRC: ${src.toString(16)}, C: ${src bit 15}") - } // ROL - 2 -> { // ASR - val dst = opc_dst(opcode) - val src = op_loadw(dst).toShort() - val res = (src shr 1).toUShort() - op_storw(dst, res) - N = res bit 15 - Z = res == 0.toUShort() - C = src bit 0 - V = N xor C - } // ASR - 3 -> { // ASL - val dst = opc_dst(opcode) - val src = op_loadw(dst) - val res = src shl 1 - op_storw(dst, res.toUShort()) - N = res bit 15 - Z = res == 0.toUShort() - C = src and 0x8000u != 0u.toUShort() - V = N xor C - } // ASL - } - 0x0D00 -> when (opcode shr 6 and 3) { - 0 -> { // MARK - val count = opcode and 0x3F - sp = (sp + (2 * count).toUInt()).toUShort() - pc = registers[5] - registers[5] = stack_pop() - } // MARK - 1 -> { throw InvalidOpcodeException() } // MFPI // TODO - 2 -> { throw InvalidOpcodeException() } // MTPI // TODO - 3 -> { - op_storw(opc_dst(opcode), if (N) (-1).toUShort() else 0.toUShort()) - Z = !N - V = false - } // SXT - } - 0x0F00 -> throw InvalidOpcodeException() // CSM - 0x8000 -> br_rel(!N, opcode) // BPL - 0x8100 -> br_rel(N, opcode) // BMI - 0x8200 -> br_rel(!C and !Z, opcode) // BHI - 0x8300 -> br_rel(C or Z, opcode) // BLOS - 0x8400 -> br_rel(!V, opcode) // BVC - 0x8500 -> br_rel(V, opcode) // BVS - 0x8600 -> br_rel(!C, opcode) // BCC/BHIS - 0x8700 -> br_rel(C, opcode) // BCS/BLO - 0x8800 -> trap(0x18u) // EMT - 0x8900 -> trap(0x1Cu) // TRAP - - 0x8A00 -> when (opcode shr 6 and 3) { - 0 -> { // CLRB - op_storb(opc_dstb(opcode), 0U) - N = false - V = false - C = false - Z = true - } // CLRB - 1 -> { // COMB - val dst = opc_dstb(opcode) - val res = op_loadb(dst).inv().also { op_storb(dst, it) } - N = res bit 7 - Z = res == 0U.toUByte() - C = true - V = false - } // COMB - 2 -> { // INC - val dst = opc_dstb(opcode) - val res = op_loadb(dst).inc().also { op_storb(dst, it) } - N = res bit 7 - Z = res == 0.toUByte() - V = res == 0x80.toUByte() - } // INC - 3 -> { // DEC - val dst = opc_dstb(opcode) - val res = op_loadb(dst).dec().also { op_storb(dst, it) } - N = res bit 7 - Z = res == 0.toUByte() - V = res == 0x7F.toUByte() - } // DEC - } - 0x8B00 -> when (opcode shr 6 and 3) { - 0 -> { // NEGB - val dst = opc_dstb(opcode) - val res = op_loadb(dst).inv().inc() - op_storb(dst, res) - N = res bit 7 - Z = res == 0.toUByte() - V = res == 0x8000.toUByte() - C = !Z - } // NEGB - 1 -> { // ADCB - val dst = opc_dstb(opcode) - val c: UShort = if (C) 1u else 0u - val res = (op_loadb(dst) + c).toUByte() - op_storb(dst, res) - N = res bit 7 - Z = res == 0u.toUByte() - V = (res == 0x80u.toUByte()) and C - C = Z and C - } // ADCB - 2 -> { - val dst = opc_dstb(opcode) - val src = op_loadb(dst) - val res = if (C) src.dec() else src - op_storb(dst, res) - N = res bit 8 - Z = res == 0.toUByte() - V = res == 0x80.toUByte() - C = C and (src == 0.toUByte()) - } // SBCB - 3 -> { - val dst = op_loadb(opc_dstb(opcode)) - Z = dst == 0.toUByte() - N = dst bit 7 - V = false - C = false - } // TSTB - } - 0x8C00 -> when (opcode shr 6 and 3) { - 0 -> { - val dst = opc_dstb(opcode) - val src = op_loadb(dst) - val res = (src shr 1).bit(7, C) - op_storb(dst, res) - C = src bit 0 - N = res bit 7 - Z = res == 0.toUByte() - V = N xor C - } // RORB - 1 -> { - val dst = opc_dstb(opcode) - val src = op_loadb(dst) - val res = (src shl 1).bit(0, C) - op_storb(dst, res) - C = src bit 7 - N = res bit 7 - Z = res == 0.toUByte() - V = N xor C - } // ROLB - 2 -> { // ASRB - val dst = opc_dstb(opcode) - val src = op_loadb(dst).toByte() - val res = (src shr 1).toUByte() - op_storb(dst, res) - N = res bit 7 - Z = res == 0.toUByte() - C = src bit 0 - V = N xor C - } // ASRB - 3 -> { // ASLB - val dst = opc_dstb(opcode) - val src = op_loadb(dst) - val res = (src shl 1).toUByte() - op_storw(dst, res.toUShort()) - N = res bit 7 - Z = res == 0.toUByte() - C = src bit 7 - V = N xor C - } // ASLB - } - 0x8D00 -> when (opcode shr 6 and 3) { - 1 -> { throw InvalidOpcodeException() } // MFPD // TODO - 2 -> { throw InvalidOpcodeException() } // MTPD // TODO - else -> { throw InvalidOpcodeException() } // Reserved - } - } - 0x1000 -> { // MOV - val src = opc_src(opcode) - val dst = opc_dst(opcode) - op_loadw(src).also { - op_storw(dst, it) - N = it bit 15 - Z = it == 0.toUShort() - V = false - } - } // MOV - 0x2000 -> { // CMP - - val src = op_loadw(opc_src(opcode)) - val src2 = op_loadw(opc_dst(opcode)) - val res = (src - src2) and 0xFFFFu - N = res bit 15 - Z = res == 0U - C = src < src2 // unsigned lt - V = ((src bit 15) xor (src2 bit 15)) and ((src2 bit 15) == (res bit 15)) - } // CMP - 0x3000 -> { // BIT - val src = opc_src(opcode) - val dst = opc_dst(opcode) - val res = op_loadw(dst) and op_loadw(src) - N = res bit 15 - Z = res == 0u.toUShort() - V = false -// logger.debug("RV: ${dst.toString(16)} RES: ${res.toString(16)}, SRC: ${op_loadw(src).toString(16)}") -// debugFlags() - } // BIT - 0x4000 -> { // BIC - val src = opc_src(opcode) - val dst = opc_dst(opcode) - val res = op_loadw(dst) and op_loadw(src).inv() - op_storw(dst, res) - N = res bit 15 - Z = res == 0u.toUShort() - V = false - } // BIC - 0x5000 -> { // BIS - val src = opc_src(opcode) - val dst = opc_dst(opcode) - val res = op_loadw(dst) or op_loadw(src) - op_storw(dst, res) - N = res and 0x8000u != 0u.toUShort() - Z = res == 0u.toUShort() - V = false - } // BIS - 0x6000 -> { // ADD - val src = opc_src(opcode) - val dst = opc_dst(opcode) - val srcv = op_loadw(src) - val dstv = op_loadw(dst) - val res = (srcv + dstv) - val resw = res.toUShort() - op_storw(dst, res.toUShort()) - N = resw > 0x7FFFu - Z = resw == 0.toUShort() - val src_sign = srcv and 0x8000u - V = (src_sign == dstv and 0x8000u) && (src_sign != resw and 0x8000u) - C = (res >= 0x10000u) -// logger.debug("RV: ${dst.toString(16)} RES: ${res.toString(16)}, SRC: ${srcv.toString(16)}, DST: ${dstv.toString(16)}") -// debugFlags() - - } // ADD - 0x7000 -> when (opcode shr 9 and 0x7) { - 0 -> { // MUL - val r = opcode shr 6 and 0x7 - val src = op_loadw(opc_dst(opcode)).toShort().toInt() - val res = registers[r].toShort().toInt() * src - registers[r bis 1] = (res shr 16).toUShort() - registers[r] = res.toUShort() - N = res bit 31 - Z = res == 0 - V = false - C = (res shr 16) == -(res shr 15 and 1) // check if overflow extends the sign bit - } // MUL - 1 -> { // DIV - val r = opcode shr 6 and 0x7 - val src = op_loadw(opc_dst(opcode)).toInt() - val lho = (registers[r].toUInt() shl 16 or registers[r bis 1].toUInt()).toInt() - if (src != 0) { - val quot = lho / src - val rem = lho % src - registers[r] = quot.toUShort() - registers[r bis 1] = rem.toUShort() - val overflow = quot shr 16 - V = overflow == -(quot shr 15 and 1) // check if overflow extends the sign bit - N = quot bit 15 - Z = quot == 0 - } else { - C = true - V = true - } - } // DIV - 2 -> { // ASH - val r = opcode shr 6 and 0x7 - var count = (op_loadb(opc_dst(opcode)) and 0x3Fu).toInt() - val src = registers[r].toShort().toInt() // two casts to sign extend - count = count sex 6 - V = false - val res = if (count > 0) { - C = (src shl (count-1)) bit 15 - val shifted = if (count < 16) { - src shr 16-count - } else { - src - } - V = (shifted != 0) and (shifted != -1) - src shl count - } else if (count < 0) { - count = -count - C = (src shr (count-1)) bit 0 - src shr count - } else { - C = false - src - } - registers[r] = res.toUShort() - N = res < 0 - Z = res == 0 - } // ASH - 3 -> { // ASHC - val r = opcode shr 6 and 0x7 - 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 - V = false - val res = if (count > 0) { - C = (src shl (count-1)) bit 31 - val shifted = src shr 32-count - V = (shifted != 0) and (shifted != -1) - src shl count - } else if (count < 0) { - count = -count - C = (src shr (count-1)) bit 0 - src shr count - } else { - C = false - src - } - registers[r] = (res and 0xFFFF).toUShort() - registers[r or 1] = (res shr 16 and 0xFFFF).toUShort() - N = res < 0 - Z = res == 0 - } // ASHC - 4 -> { - val r = opcode shr 6 and 7 - val dst = opc_dst(opcode) - val res = op_loadw(dst) xor registers[r] - op_storw(dst, res) - N = res bit 15 - Z = res == 0.toUShort() - V = false - } // XOR - 5,6 -> throw InvalidOpcodeException() - 7 -> { - val reg = opcode shr 6 and 7 - registers[reg] = registers[reg].dec() - if (registers[reg] != 0.toUShort()) { - pc = (pc.toInt() - (opcode and 0x3F shl 1)).toUShort() - } - } // SOB - } - // 0x800 handled above - 0x9000 -> { // MOVB - val src = opc_srcb(opcode) - val dst = opc_dstb(opcode) - var dstv = op_loadb(src) - - var dstw = if (is_paddr_reg(dst)) { - op_storw(dst, dstv.toUShort() sex 8) - dstv.toUShort() sex 8 - } else { - op_storb(dst, dstv) - dstv.toUShort() - } - N = dstv bit 7 - Z = dstv == 0.toUByte() - V = false - - } // MOVB - 0xA000 -> { // CMPB - val src = op_loadb(opc_srcb(opcode)) - val src2 = op_loadb(opc_dstb(opcode)) - val res = (src - src2) and 0xFFu - N = res bit 7 - Z = res == 0U - C = src < src2 // unsigned lt - V = ((src bit 8) xor (src2 bit 8)) and ((src2 bit 8) == (res bit 8)) - } // CMPB - 0xB000 -> { // BITB - val src = opc_srcb(opcode) - val dst = opc_dstb(opcode) - val res = op_loadb(dst) and op_loadb(src) - N = res bit 7 - Z = res == 0u.toUByte() - V = false - } // BITB - 0xC000 -> { // BICB - val src = opc_srcb(opcode) - val dst = opc_dstb(opcode) - val res = op_loadb(dst) and op_loadb(src).inv() - op_storb(dst, res) - N = res bit 7 - Z = res == 0u.toUByte() - V = false - } // BICB - 0xD000 -> { // BISB - val src = opc_srcb(opcode) - val dst = opc_dstb(opcode) - val res = op_loadb(dst) or op_loadb(src) - op_storb(dst, res) - N = res bit 7 - Z = res == 0u.toUByte() - V = false - } // BISB - 0xE000 -> { - val src = opc_src(opcode) - val dst = opc_dst(opcode) - val srcv = op_loadw(src) - val dstv = op_loadw(dst) - val res = (dstv.toShort() - srcv.toShort()) - op_storw(dst, res.toUShort()) - N = res < 0 - Z = res == 0 - V = ((srcv bit 31) xor (dstv bit 15)) and ((srcv bit 15) == (res bit 31)) - C = (dst.toInt() + src.inv().inc().toInt()) >= 0x1_0000 - } // SUB - } + this.(insnTable[opcode shr 8])(opcode) } private fun debugFlags() {