diff options
Diffstat (limited to 'src/devices/cpu/unsp/unspdasm.cpp')
-rw-r--r-- | src/devices/cpu/unsp/unspdasm.cpp | 452 |
1 files changed, 75 insertions, 377 deletions
diff --git a/src/devices/cpu/unsp/unspdasm.cpp b/src/devices/cpu/unsp/unspdasm.cpp index a69379b555b..3b52b519af3 100644 --- a/src/devices/cpu/unsp/unspdasm.cpp +++ b/src/devices/cpu/unsp/unspdasm.cpp @@ -1,5 +1,5 @@ // license:GPL-2.0+ -// copyright-holders:Segher Boessenkool +// copyright-holders:Segher Boessenkool, David Haywood /***************************************************************************** SunPlus ยต'nSP disassembler @@ -13,18 +13,42 @@ #include "emu.h" #include "unspdasm.h" -char const *const unsp_disassembler::regs[] = +char const* const unsp_disassembler::regs[] = { "sp", "r1", "r2", "r3", "r4", "bp", "sr", "pc" }; -char const *const unsp_disassembler::jumps[] = +char const* const unsp_disassembler::bitops[] = { - "jb", "jae", "jge", "jl", "jne", "je", "jpl", "jmi", - "jbe", "ja", "jle", "jg", "jvc", "jvs", "jmp", "<inv>" + "tstb", "setb", "clrb", "invb" }; -#define UNSP_DASM_OK (len | SUPPORTED) +char const* const unsp_disassembler::signmodes[] = +{ + "uu", "us", "su?", "ss" // su? might be invalid +}; + +char const* const unsp_disassembler::lsft[] = +{ + "asr", "asror", "lsl", "lslor", "lsr", "lsror", "rol", "ror" +}; + +char const* const unsp_disassembler::extregs[] = +{ + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +}; + + +// TODO: use alu_op_start-like formatting +char const* const unsp_disassembler::aluops[] = +{ + "add","adc","sub","sbc","cmp","(invalid)","neg","--","xor","load","or","and","test","store","(invalid)","(invalid)" +}; + +char const* const unsp_disassembler::forms[] = +{ + "[%s]", "[%s--]", "[%s++]", "[++%s]" +}; u32 unsp_disassembler::opcode_alignment() const { @@ -57,6 +81,38 @@ void unsp_disassembler::print_alu_op3(std::ostream &stream, uint8_t op0, uint8_t util::stream_format(stream, alu_op3[op0], regs[opB]); } +void unsp_disassembler::print_mul(std::ostream& stream, uint16_t op) +{ + int rs = (op & 0x0007) >> 0; + // (op & 0x0078) >> 3; fixed 0001 + // (op & 0x0080) >> 7; fixed 0 + int srd = (op & 0x0100) >> 8; + int rd = (op & 0x0e00) >> 9; + int srs = (op & 0x1000) >> 12; + // (op & 0xe000) >> 13; fixed 111 + + int sign = (srs << 1) | srd; + + util::stream_format(stream, "MR = %s*%s, %s", regs[rd], regs[rs], signmodes[sign] ); +} + +void unsp_disassembler::print_muls(std::ostream& stream, uint16_t op) +{ + int rs = (op & 0x0007) >> 0; + int size = (op & 0x0078) >> 3; + // (op & 0x0080) >> 7; fixed 1 + int srd = (op & 0x0100) >> 8; + int rd = (op & 0x0e00) >> 9; + int srs = (op & 0x1000) >> 12; + // (op & 0xe000) >> 13; fixed 111 + + int sign = (srs << 1) | srd; + if (size == 0) size = 16; + + util::stream_format(stream, "MR = [%s]*[%s], %s, %d", regs[rd], regs[rs], signmodes[sign], size ); +} + + void unsp_disassembler::print_alu_op_end(std::ostream &stream, uint8_t op0) { if (op0 == 1 || op0 == 3) @@ -65,78 +121,16 @@ void unsp_disassembler::print_alu_op_end(std::ostream &stream, uint8_t op0) void unsp_disassembler::print_indirect_op(std::ostream &stream, uint8_t opN, uint8_t opB) { - static const char* const forms[] = { "[%s]", "[%s--]", "[%s++]", "[++%s]" }; - if (opN & 4) util::stream_format(stream, "ds:"); util::stream_format(stream, forms[opN & 3], regs[opB]); } -offs_t unsp_disassembler::disassemble_f_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, uint8_t opN, uint8_t opA, uint8_t opB, uint32_t len) -{ - switch (opN) - { - case 1: - if (opA == 7) - { - util::stream_format(stream, "<DUNNO f group>"); - return UNSP_DASM_OK; - } - util::stream_format(stream, "mr = %s*%s, us", regs[opA], regs[opB]); - return UNSP_DASM_OK; - default: - util::stream_format(stream, "<DUNNO f group>"); - return UNSP_DASM_OK; - } -} - -offs_t unsp_newer_disassembler::disassemble_f_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, uint8_t opN, uint8_t opA, uint8_t opB, uint32_t len) -{ - // these are new opcodes on the later core - - switch (opN) - { - case 1: - if (opA == 7) - { - util::stream_format(stream, "<EXTENDED f group>"); - return UNSP_DASM_OK; - } - util::stream_format(stream, "mr = %s*%s, us", regs[opA], regs[opB]); - return UNSP_DASM_OK; - default: - util::stream_format(stream, "<EXTENDED f group>"); - return UNSP_DASM_OK; - } -} - -offs_t unsp_disassembler::disassemble(std::ostream &stream, offs_t pc, uint16_t op, uint16_t ximm) +offs_t unsp_disassembler::disassemble_code(std::ostream &stream, offs_t pc, uint16_t op, uint16_t ximm, const data_buffer &opcodes) { - // the top four bits are the alu op or the branch condition, or E or F - uint8_t op0 = (op >> 12); - - // the next three are usually the destination register - uint8_t opA = (op >> 9) & 7; - - // and the next three the addressing mode - uint8_t op1 = (op >> 6) & 7; - - // the next three can be anything - uint8_t opN = (op >> 3) & 7; - - // and the last three usually the second register (source register) - uint8_t opB = op & 7; - - // the last six sometimes are a single immediate number - uint8_t opimm = op & 63; - uint32_t len = 1; - if ((op0 < 14 && op1 == 4 && (opN == 1 || opN == 2 || opN == 3)) || (op0 == 15 && (op1 == 1 || op1 == 2))) - { - len = 2; - } // all-zero and all-one are invalid insns: if (op == 0 || op == 0xffff) @@ -145,325 +139,29 @@ offs_t unsp_disassembler::disassemble(std::ostream &stream, offs_t pc, uint16_t return UNSP_DASM_OK; } - // first, check for the conditional branch insns - if (op0 < 15 && opA == 7 && op1 == 0) - { - util::stream_format(stream, "%s %04x", jumps[op0], pc+1+opimm); - return UNSP_DASM_OK; - } - if (op0 < 15 && opA == 7 && op1 == 1) - { - util::stream_format(stream, "%s %04x", jumps[op0], pc+1-opimm); - return UNSP_DASM_OK; - } - - switch ((op1 << 4) | op0) - { - case 0x05: case 0x15: case 0x25: case 0x35: - case 0x45: case 0x55: case 0x65: case 0x75: - case 0x85: case 0x95: case 0xa5: case 0xb5: - case 0xc5: case 0xd5: - case 0x07: case 0x17: case 0x27: case 0x37: - case 0x47: case 0x57: case 0x67: case 0x77: - case 0x87: case 0x97: case 0xa7: case 0xb7: - case 0xc7: case 0xd7: - case 0x1d: case 0x5d: case 0x6d: - case 0x20: case 0x21: case 0x22: case 0x23: - case 0x24: case 0x26: case 0x28: case 0x2a: - case 0x2b: case 0x2c: - util::stream_format(stream, "<BAD>"); - return UNSP_DASM_OK; - - - // alu, base+displacement - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x04: case 0x06: case 0x08: case 0x09: - case 0x0a: case 0x0b: case 0x0c: - print_alu_op_start(stream, op0, opA); - util::stream_format(stream, "[bp+%02x]", opimm); - print_alu_op_end(stream, op0); - return UNSP_DASM_OK; - case 0x0d: - util::stream_format(stream, "[bp+%02x] = %s", opimm, regs[opA]); - return UNSP_DASM_OK; - - - // alu, 6-bit immediate - case 0x10: case 0x11: case 0x12: case 0x13: - case 0x14: case 0x16: case 0x18: case 0x19: - case 0x1a: case 0x1b: case 0x1c: - print_alu_op_start(stream, op0, opA); - util::stream_format(stream, "%02x", opimm); - print_alu_op_end(stream, op0); - return UNSP_DASM_OK; - - - // pop insns - case 0x29: - if (op == 0x9a90) - util::stream_format(stream, "retf"); - else if (op == 0x9a98) - util::stream_format(stream, "reti"); - else if (opA+1 < 8 && opA+opN < 8) - util::stream_format(stream, "pop %s, %s from [%s]", - regs[opA+1], regs[opA+opN], regs[opB]); - else - util::stream_format(stream, "<BAD>"); - return UNSP_DASM_OK; - - - // push insns - case 0x2d: - if (opA+1 >= opN && opA < opN+7) - util::stream_format(stream, "push %s, %s to [%s]", - regs[opA+1-opN], regs[opA], regs[opB]); - else - util::stream_format(stream, "<BAD>"); - return UNSP_DASM_OK; - - - // alu, indirect memory - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x36: case 0x38: case 0x39: - case 0x3a: case 0x3b: case 0x3c: - print_alu_op_start(stream, op0, opA); - print_indirect_op(stream, opN, opB); - print_alu_op_end(stream, op0); - return UNSP_DASM_OK; - case 0x3d: - print_indirect_op(stream, opN, opB); - util::stream_format(stream, " = %s", regs[opA]); - return UNSP_DASM_OK; - - - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x46: case 0x48: case 0x49: - case 0x4a: case 0x4b: case 0x4c: - switch (opN) - { - // alu, register - case 0: - print_alu_op_start(stream, op0, opA); - util::stream_format(stream, "%s", regs[opB]); - print_alu_op_end(stream, op0); - return UNSP_DASM_OK; - - // alu, 16-bit immediate - case 1: - if ((op0 == 4 || op0 == 12 || op0 == 6 || op0 == 9) && opA != opB) - { - util::stream_format(stream, "<BAD>"); - return UNSP_DASM_OK; - } - if (op0 != 4 && op0 != 12) - util::stream_format(stream, "%s = ", regs[opA]); - print_alu_op3(stream, op0, opB); - util::stream_format(stream, "%04x", ximm); - print_alu_op_end(stream, op0); - return UNSP_DASM_OK; - - // alu, direct memory - case 2: - if ((op0 == 4 || op0 == 12 || op0 == 6 || op0 == 9) && opA != opB) - { - util::stream_format(stream, "<BAD>"); - return UNSP_DASM_OK; - } - if (op0 != 4 && op0 != 12) - util::stream_format(stream, "%s = ", regs[opA]); - print_alu_op3(stream, op0, opB); - util::stream_format(stream, "[%04x]", ximm); - print_alu_op_end(stream, op0); - return UNSP_DASM_OK; - - // alu, direct memory - case 3: - if (op0 == 4 || op0 == 12) - { - util::stream_format(stream, "<BAD>"); - return UNSP_DASM_OK; - } - if ((op0 == 6 || op0 == 9) && opA != opB) - { - util::stream_format(stream, "<BAD>"); - return UNSP_DASM_OK; - } - util::stream_format(stream, "[%04x] = ", ximm); - print_alu_op3(stream, op0, opB); - util::stream_format(stream, "%s", regs[opA]); - print_alu_op_end(stream, op0); - return UNSP_DASM_OK; - - // alu, with shift - default: - print_alu_op_start(stream, op0, opA); - util::stream_format(stream, "%s asr %x", regs[opB], (opN & 3) + 1); - print_alu_op_end(stream, op0); - return UNSP_DASM_OK; - } - - case 0x4d: - switch (opN) - { - // alu, direct memory - case 3: - if (opA != opB) - { - util::stream_format(stream, "<BAD>"); - return UNSP_DASM_OK; - } - util::stream_format(stream, "[%04x] = %s", ximm, regs[opB]); - return UNSP_DASM_OK; - default: - util::stream_format(stream, "<BAD>"); - return UNSP_DASM_OK; - } - - - // alu, with shift - case 0x50: case 0x51: case 0x52: case 0x53: - case 0x54: case 0x56: case 0x58: case 0x59: - case 0x5a: case 0x5b: case 0x5c: - print_alu_op_start(stream, op0, opA); - if ((opN & 4) == 0) - util::stream_format(stream, "%s lsl %x", regs[opB], (opN & 3) + 1); - else - util::stream_format(stream, "%s lsr %x", regs[opB], (opN & 3) + 1); - print_alu_op_end(stream, op0); - return UNSP_DASM_OK; - - - // alu, with shift - case 0x60: case 0x61: case 0x62: case 0x63: - case 0x64: case 0x66: case 0x68: case 0x69: - case 0x6a: case 0x6b: case 0x6c: - print_alu_op_start(stream, op0, opA); - if ((opN & 4) == 0) - util::stream_format(stream, "%s rol %x", regs[opB], (opN & 3) + 1); - else - util::stream_format(stream, "%s ror %x", regs[opB], (opN & 3) + 1); - print_alu_op_end(stream, op0); - return UNSP_DASM_OK; - + uint8_t op0 = (op >> 12); - // alu, direct memory - case 0x70: case 0x71: case 0x72: case 0x73: - case 0x74: case 0x76: case 0x78: case 0x79: - case 0x7a: case 0x7b: case 0x7c: - print_alu_op_start(stream, op0, opA); - util::stream_format(stream, "[%02x]", opimm); - print_alu_op_end(stream, op0); - return UNSP_DASM_OK; - case 0x7d: - util::stream_format(stream, "[%02x] = %s", opimm, regs[opA]); - return UNSP_DASM_OK; + if (op0 == 0xf) + return disassemble_fxxx_group(stream, pc, op, ximm, opcodes); + uint8_t opA = (op >> 9) & 7; + uint8_t op1 = (op >> 6) & 7; - case 0x1f: - if (opA == 0) - { - util::stream_format(stream, "call %04x", (opimm << 16) | ximm); - return UNSP_DASM_OK; - } - util::stream_format(stream, "<DUNNO>"); - return UNSP_DASM_OK; + if (op0 < 15 && opA == 7 && op1 < 2) + return disassemble_jumps(stream, pc, op); - case 0x2f: case 0x3f: case 0x6f: case 0x7f: - if (opA == 7 && op1 == 2) - { - util::stream_format(stream, "goto %04x", (opimm << 16) | ximm); - return UNSP_DASM_OK; - } - if (opA == 7 && op1 == 3) - { - util::stream_format(stream, "<DUNNO>"); - return UNSP_DASM_OK; - } - util::stream_format(stream, "<DUNNO>"); - return UNSP_DASM_OK; + if (op0 == 0xe) + return disassemble_exxx_group(stream, pc, op, ximm); + return disassemble_remaining(stream, pc, op, ximm, opcodes); +} - case 0x0f: - return disassemble_f_group(stream, pc, op, ximm, opN, opA, opB, len); - - case 0x4f: - switch (opN) - { - case 1: - if (opA == 7) - { - util::stream_format(stream, "<DUNNO>"); - return UNSP_DASM_OK; - } - util::stream_format(stream, "mr = %s*%s", regs[opA], regs[opB]); - return UNSP_DASM_OK; - default: - util::stream_format(stream, "<DUNNO>"); - return UNSP_DASM_OK; - } - - case 0x5f: - if (opA != 0) - { - util::stream_format(stream, "<DUNNO>"); - return UNSP_DASM_OK; - } - switch (opimm) - { - case 0x00: - util::stream_format(stream, "int off"); - return UNSP_DASM_OK; - case 0x01: - util::stream_format(stream, "int irq"); - return UNSP_DASM_OK; - case 0x02: - util::stream_format(stream, "int fiq"); - return UNSP_DASM_OK; - case 0x03: - util::stream_format(stream, "int fiq,irq"); - return UNSP_DASM_OK; - case 0x04: - util::stream_format(stream, "fir_mov on"); - return UNSP_DASM_OK; - case 0x05: - util::stream_format(stream, "fir_mov off"); - return UNSP_DASM_OK; - case 0x08: - util::stream_format(stream, "irq off"); - return UNSP_DASM_OK; - case 0x09: - util::stream_format(stream, "irq on"); - return UNSP_DASM_OK; - case 0x0c: - util::stream_format(stream, "fiq off"); - return UNSP_DASM_OK; - case 0x0e: - util::stream_format(stream, "fiq on"); - return UNSP_DASM_OK; - case 0x25: - util::stream_format(stream, "nop"); - return UNSP_DASM_OK; - default: - util::stream_format(stream, "<DUNNO>"); - return UNSP_DASM_OK; - } - - case 0x0e: case 0x1e: case 0x2e: case 0x3e: - case 0x4e: case 0x5e: case 0x6e: case 0x7e: - util::stream_format(stream, "<DUNNO>"); - return UNSP_DASM_OK; - default: - util::stream_format(stream, "<UNHANDLED>"); - return UNSP_DASM_OK; - } - return UNSP_DASM_OK; -} offs_t unsp_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) { uint16_t op = opcodes.r16(pc); uint16_t imm16 = opcodes.r16(pc+1); - return disassemble(stream, pc, op, imm16); + return disassemble_code(stream, pc, op, imm16, opcodes); } |