diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index daec3987605..d4538b11abb 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -2378,6 +2378,7 @@ end if (CPUS["MB86901"]~=null) then files { MAME_DIR .. "src/devices/cpu/sparc/mb86901.cpp", + MAME_DIR .. "src/devices/cpu/sparc/sparcdasm.h", MAME_DIR .. "src/devices/cpu/sparc/sparcdefs.h", MAME_DIR .. "src/devices/cpu/sparc/sparc.h", } diff --git a/src/devices/cpu/sparc/mb86901.cpp b/src/devices/cpu/sparc/mb86901.cpp index 08794476f31..04e41e94e60 100644 --- a/src/devices/cpu/sparc/mb86901.cpp +++ b/src/devices/cpu/sparc/mb86901.cpp @@ -37,6 +37,7 @@ const int mb86901_device::WINDOW_COUNT = 7; mb86901_device::mb86901_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : cpu_device(mconfig, MB86901, "Fujitsu MB86901", tag, owner, clock, "mb86901", __FILE__) , m_program_config("program", ENDIANNESS_BIG, 32, 32) + , m_dasm(7) { } @@ -351,8 +352,8 @@ UINT32 mb86901_device::disasm_max_opcode_bytes() const offs_t mb86901_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) { - extern CPU_DISASSEMBLE( sparc ); - return CPU_DISASSEMBLE_NAME(sparc)(this, buffer, pc, oprom, opram, options); + UINT32 op = *reinterpret_cast(oprom); + return m_dasm.dasm(buffer, pc, BIG_ENDIANIZE_INT32(op)); } diff --git a/src/devices/cpu/sparc/sparc.h b/src/devices/cpu/sparc/sparc.h index 481c23ec515..a646a80040c 100644 --- a/src/devices/cpu/sparc/sparc.h +++ b/src/devices/cpu/sparc/sparc.h @@ -4,11 +4,13 @@ SPARC v7 emulator */ -#pragma once - #ifndef __SPARC_H__ #define __SPARC_H__ +#pragma once + +#include "sparcdasm.h" + #define SPARC_NO_TRAP 256 #define SPARC_RESET 0 #define SPARC_INSTRUCTION_ACCESS_EXCEPTION 1 @@ -142,6 +144,7 @@ protected: // debugger helpers UINT32 m_dbgregs[24]; + sparc_disassembler m_dasm; // address spaces address_space *m_program; @@ -190,6 +193,4 @@ enum SPARC_R96, SPARC_R97, SPARC_R98, SPARC_R99, SPARC_R100, SPARC_R101, SPARC_R102, SPARC_R103, SPARC_R104, SPARC_R105, SPARC_R106, SPARC_R107, SPARC_R108, SPARC_R109, SPARC_R110, SPARC_R111 }; -CPU_DISASSEMBLE( sparc ); - #endif /* __SPARC_H__ */ diff --git a/src/devices/cpu/sparc/sparcdasm.cpp b/src/devices/cpu/sparc/sparcdasm.cpp index 8e72e0bcacb..357e391702d 100644 --- a/src/devices/cpu/sparc/sparcdasm.cpp +++ b/src/devices/cpu/sparc/sparcdasm.cpp @@ -1,594 +1,1175 @@ // license:BSD-3-Clause -// copyright-holders:Ryan Holtz +// copyright-holders:Ryan Holtz, Vas Crabb /* - SPARC v7 disassembler + SPARC disassembler */ #include "emu.h" +#include "sparcdasm.h" #include "sparcdefs.h" -static void print(char *output, const char *fmt, ...) -{ - va_list vl; +#include - va_start(vl, fmt); - output += vsprintf(output, fmt, vl); - va_end(vl); +namespace { + const sparc_disassembler DASM_V7(7); + const sparc_disassembler DASM_V8(8); + const sparc_disassembler DASM_V9(9); } -#define INVALFMT "%s; op:%08x rs1:%d rd:%d simm13:%d i:%d asi:%d rs2:%d" - -static const char * const regnames[32] = { +const char * const sparc_disassembler::REG_NAMES[32] = { "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o6", "%o7", "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%i6", "%i7" }; -void sparc_dasm_address(char* address, UINT32 op) -{ - char rs1[128]; - memset(rs1, 0, 128); - bool rs1present = false; - if (RS1 != 0) +const sparc_disassembler::branch_desc sparc_disassembler::EMPTY_BRANCH_DESC = { + nullptr, 0, false, false, + { nullptr, nullptr, nullptr, nullptr }, { - rs1present = true; - print(rs1, "%s", regnames[RS1]); + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } +}; - char rs2[128]; - memset(rs2, 0, 128); - if (USEIMM) +const sparc_disassembler::branch_desc sparc_disassembler::BPCC_DESC = { + [](UINT32 op) { return DISP19; }, 6, true, true, + { "%icc", nullptr, "%xcc", nullptr }, { - if (SIMM13 != 0) + "bn", "be", "ble", "bl", "bleu", "bcs", "bneg", "bvs", + "ba", "bne", "bg", "bge", "bgu", "bcc", "bpos", "bvc" + } +}; + +const sparc_disassembler::branch_desc sparc_disassembler::BICC_DESC = { + [](UINT32 op) { return DISP22; }, 6, false, false, + { nullptr, nullptr, nullptr, nullptr }, + { + "bn", "be", "ble", "bl", "bleu", "bcs", "bneg", "bvs", + "ba", "bne", "bg", "bge", "bgu", "bcc", "bpos", "bvc" + } +}; + +const sparc_disassembler::branch_desc sparc_disassembler::BPR_DESC = { + [](UINT32 op) { return DISP16; }, 5, true, false, + { nullptr, nullptr, nullptr, nullptr }, + { + nullptr, "brz", "brlez", "brlz", nullptr, "brnz", "brgz", "brgez", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr + } +}; + +const sparc_disassembler::branch_desc sparc_disassembler::FBPFCC_DESC = { + [](UINT32 op) { return DISP19; }, 6, true, true, + { "%fcc0", "%fcc1", "%fcc2", "%fcc3" }, + { + "fbn", "fbne", "fblg", "fbul", "fbl", "fbug", "fbg", "fbu", + "fba", "fbe", "fbue", "fbge", "fbuge", "fble", "fbule", "fbo" + } +}; + +const sparc_disassembler::branch_desc sparc_disassembler::FBFCC_DESC = { + [](UINT32 op) { return DISP22; }, 6, false, false, + { nullptr, nullptr, nullptr, nullptr }, + { + "fbn", "fbne", "fblg", "fbul", "fbl", "fbug", "fbg", "fbu", + "fba", "fbe", "fbue", "fbge", "fbuge", "fble", "fbule", "fbo" + } +}; + +const sparc_disassembler::branch_desc sparc_disassembler::CBCCC_DESC = { + [](UINT32 op) { return DISP22; }, 6, false, false, + { nullptr, nullptr, nullptr, nullptr }, + { + "cbn", "cb123", "cb12", "cb13", "cb1", "cb23", "cb2", "cb3", + "cba", "cb0", "cb03", "cb02", "cb023", "cb01", "cb013", "cb012" + } +}; + +const sparc_disassembler::int_op_desc_map::value_type sparc_disassembler::SIMPLE_INT_OP_DESC[] = { + { 0x00, { 7, false, "add" } }, + { 0x01, { 7, true, "and" } }, + { 0x02, { 7, true, "or" } }, + { 0x03, { 7, true, "xor" } }, + { 0x04, { 7, false, "sub" } }, + { 0x05, { 7, true, "andn" } }, + { 0x06, { 7, true, "orn" } }, + { 0x07, { 7, true, "xnor" } }, + { 0x08, { 7, false, "addx" } }, + { 0x09, { 9, false, "mulx" } }, + { 0x0a, { 8, false, "umul" } }, + { 0x0b, { 8, false, "smul" } }, + { 0x0c, { 7, false, "subx" } }, + { 0x0d, { 9, false, "udivx" } }, + { 0x0e, { 8, false, "udiv" } }, + { 0x0f, { 8, false, "sdiv" } }, + { 0x10, { 8, false, "addcc" } }, + { 0x11, { 8, true, "andcc" } }, + { 0x12, { 7, true, "orcc" } }, + { 0x13, { 7, true, "xorcc" } }, + { 0x14, { 7, false, "subcc" } }, + { 0x15, { 7, true, "andncc" } }, + { 0x16, { 7, true, "orncc" } }, + { 0x17, { 7, true, "xnorcc" } }, + { 0x18, { 7, false, "addxcc" } }, + { 0x1a, { 8, false, "umulcc" } }, + { 0x1b, { 8, false, "smulcc" } }, + { 0x1c, { 7, false, "subxcc" } }, + { 0x1e, { 8, false, "udivcc" } }, + { 0x1f, { 8, false, "sdivcc" } }, + { 0x20, { 7, false, "taddcc" } }, + { 0x21, { 7, false, "tsubcc" } }, + { 0x22, { 7, false, "taddcctv" } }, + { 0x23, { 7, false, "tsubcctv" } }, + { 0x24, { 7, false, "mulscc" } }, + { 0x2d, { 9, false, "sdivx" } }, + { 0x3c, { 7, false, "save" } }, + { 0x3d, { 7, false, "restore" } } +}; + +const sparc_disassembler::state_reg_desc_map::value_type sparc_disassembler::V9_STATE_REG_DESC[] = { + { 1, { true, nullptr, nullptr } }, + { 2, { false, "%ccr", "%ccr" } }, + { 3, { false, "%asi", "%asi" } }, + { 4, { false, "%tick", nullptr } }, + { 5, { false, "%pc", nullptr } }, + { 6, { false, "%fprs", "%fprs" } } +}; + +const char * const sparc_disassembler::MOVCC_CC_NAMES[8] = { + "%fcc0", "%fcc1", "%fcc2", "%fcc3", "%icc", nullptr, "%xcc", nullptr +}; + +const char * const sparc_disassembler::MOVCC_COND_NAMES[32] = { + "n", "ne", "lg", "ul", "l", "ug", "g", "u", + "a", "e", "ue", "ge", "uge", "le", "ule", "o", + "n", "e", "le", "l", "leu", "cs", "neg", "vs", + "a", "ne", "g", "ge", "gu", "cc", "pos", "vc" +}; + +const char * const sparc_disassembler::MOVE_INT_COND_MNEMONICS[8] = { + nullptr, "movrz", "movrlez", "movrlz", nullptr, "movrnz", "movrgz", "movrgez" +}; + +const char * const sparc_disassembler::V9_PRIV_REG_NAMES[32] = { + "%tpc", "%tnpc", "%tstate", "%tt", "%tick", "%tba", "%pstate", "%tl", + "%pil", "%cwp", "%cansave", "%canrestore", "%cleanwin", "%otherwin", "%wstate", "%fq", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, "%ver" +}; + +const sparc_disassembler::fpop1_desc_map::value_type sparc_disassembler::V7_FPOP1_DESC[] = { + { 0x001, { false, false, false, false, "fmovs" } }, + { 0x005, { false, false, false, false, "fnegs" } }, + { 0x009, { false, false, false, false, "fabss" } }, + { 0x029, { false, false, false, false, "fsqrts" } }, + { 0x02a, { false, false, true, true, "fsqrtd" } }, + { 0x02b, { false, false, true, true, "fsqrtq" } }, + { 0x041, { true, false, false, false, "fadds" } }, + { 0x042, { true, true, true, true, "faddd" } }, + { 0x043, { true, true, true, true, "faddq" } }, + { 0x045, { true, false, false, false, "fsubs" } }, + { 0x046, { true, true, true, true, "fsubd" } }, + { 0x047, { true, true, true, true, "fsubq" } }, + { 0x049, { true, false, false, false, "fmuls" } }, + { 0x04a, { true, true, true, true, "fmuld" } }, + { 0x04b, { true, true, true, true, "fmulq" } }, + { 0x04d, { true, false, false, false, "fdivs" } }, + { 0x04e, { true, true, true, true, "fdivd" } }, + { 0x04f, { true, true, true, true, "fdivq" } }, + { 0x069, { true, false, false, true, "fsmuld" } }, + { 0x06e, { true, true, true, true, "fdmulq" } }, + { 0x0c4, { false, false, false, false, "fitos" } }, + { 0x0c6, { false, false, true, false, "fdtos" } }, + { 0x0c7, { false, false, true, false, "fqtos" } }, + { 0x0c8, { false, false, false, true, "fitod" } }, + { 0x0c9, { false, false, false, true, "fstod" } }, + { 0x0cb, { false, false, true, true, "fqtod" } }, + { 0x0cc, { false, false, false, true, "fitoq" } }, + { 0x0cd, { false, false, false, true, "fstoq" } }, + { 0x0ce, { false, false, true, true, "fdtoq" } }, + { 0x0d1, { false, false, false, false, "fstoi" } }, + { 0x0d2, { false, false, true, false, "fdtoi" } }, + { 0x0d3, { false, false, true, false, "fqtoi" } } +}; + +const sparc_disassembler::fpop1_desc_map::value_type sparc_disassembler::V9_FPOP1_DESC[] = { + { 0x002, { false, false, true, true, "fmovd" } }, + { 0x003, { false, false, true, true, "fmovq" } }, + { 0x006, { false, false, true, true, "fnegd" } }, + { 0x007, { false, false, true, true, "fnegq" } }, + { 0x00a, { false, false, true, true, "fabsd" } }, + { 0x00b, { false, false, true, true, "fabsq" } }, + { 0x081, { false, false, false, true, "fstox" } }, + { 0x082, { false, false, true, true, "fdtox" } }, + { 0x083, { false, false, true, true, "fqtox" } }, + { 0x084, { false, false, true, false, "fxtos" } }, + { 0x088, { false, false, true, true, "fxtod" } }, + { 0x08c, { false, false, true, true, "fxtoq" } } +}; + +const sparc_disassembler::fpop2_desc_map::value_type sparc_disassembler::V7_FPOP2_DESC[] = { + { 0x051, { false, false, "fcmps" } }, + { 0x052, { false, true, "fcmpd" } }, + { 0x053, { false, true, "fcmpq" } }, + { 0x055, { false, false, "fcmpes" } }, + { 0x056, { false, true, "fcmped" } }, + { 0x057, { false, true, "fcmpeq" } } +}; + +const sparc_disassembler::fpop2_desc_map::value_type sparc_disassembler::V9_FPOP2_DESC[] = { + { 0x025, { true, false, "fmovrse" } }, + { 0x026, { true, true, "fmovrde" } }, + { 0x027, { true, true, "fmovrqe" } }, + { 0x045, { true, false, "fmovrslez" } }, + { 0x046, { true, true, "fmovrdlez" } }, + { 0x047, { true, true, "fmovrqlez" } }, + { 0x065, { true, false, "fmovrslz" } }, + { 0x066, { true, true, "fmovrdlz" } }, + { 0x067, { true, true, "fmovrqlz" } }, + { 0x0a5, { true, false, "fmovrsne" } }, + { 0x0a6, { true, true, "fmovrdne" } }, + { 0x0a7, { true, true, "fmovrqne" } }, + { 0x0c5, { true, false, "fmovrsgz" } }, + { 0x0c6, { true, true, "fmovrdgz" } }, + { 0x0c7, { true, true, "fmovrqgz" } }, + { 0x0e5, { true, false, "fmovrsgez" } }, + { 0x0e6, { true, true, "fmovrdgez" } }, + { 0x0e7, { true, true, "fmovrqgez" } } +}; + +const sparc_disassembler::ldst_desc_map::value_type sparc_disassembler::V7_LDST_DESC[] = { + { 0x00, { false, false, '\0', false, "ld", nullptr } }, { 0x10, { false, true, '\0', false, "lda", nullptr } }, + { 0x01, { false, false, '\0', false, "ldub", nullptr } }, { 0x11, { false, true, '\0', false, "lduba", nullptr } }, + { 0x02, { false, false, '\0', false, "lduh", nullptr } }, { 0x12, { false, true, '\0', false, "lduha", nullptr } }, + { 0x03, { false, false, '\0', false, "ldd", nullptr } }, { 0x13, { false, true, '\0', false, "ldda", nullptr } }, + { 0x04, { true, false, '\0', false, "st", "clr" } }, { 0x14, { true, true, '\0', false, "sta", nullptr } }, + { 0x05, { true, false, '\0', false, "stb", "clrb" } }, { 0x15, { true, true, '\0', false, "stba", nullptr } }, + { 0x06, { true, false, '\0', false, "sth", "clrh" } }, { 0x16, { true, true, '\0', false, "stha", nullptr } }, + { 0x07, { true, false, '\0', false, "std", nullptr } }, { 0x17, { true, true, '\0', false, "stda", nullptr } }, + { 0x09, { false, false, '\0', false, "ldsb", nullptr } }, { 0x19, { false, true, '\0', false, "ldsba", nullptr } }, + { 0x0a, { false, false, '\0', false, "ldsh", nullptr } }, { 0x1a, { false, true, '\0', false, "ldsha", nullptr } }, + { 0x0d, { false, false, '\0', false, "ldstub", nullptr } }, { 0x1d, { false, true, '\0', false, "ldstuba", nullptr } }, + { 0x0f, { false, false, '\0', false, "swap", nullptr } }, { 0x1f, { false, true, '\0', false, "swapa", nullptr } }, + + { 0x20, { false, false, 'f', false, "ld", nullptr } }, { 0x30, { false, false, 'c', false, "ld", nullptr } }, + { 0x23, { false, false, 'f', true, "ldd", nullptr } }, { 0x33, { false, false, 'c', false, "ldd", nullptr } }, + { 0x24, { true, false, 'f', false, "st", nullptr } }, { 0x34, { true, false, 'c', false, "st", nullptr } }, + { 0x27, { true, false, 'f', true, "std", nullptr } }, { 0x37, { true, false, 'c', false, "std", nullptr } } +}; + +const sparc_disassembler::ldst_desc_map::value_type sparc_disassembler::V9_LDST_DESC[] = { + { 0x08, { false, false, '\0', false, "ldsw", nullptr } }, { 0x18, { false, true, '\0', false, "ldswa", nullptr } }, + { 0x0b, { false, false, '\0', false, "ldx", nullptr } }, { 0x1b, { false, true, '\0', false, "ldxa", nullptr } }, + { 0x0e, { true, false, '\0', false, "stx", "clrx" } }, { 0x1e, { true, true, '\0', false, "stxa", nullptr } }, + + { 0x30, { false, true, 'f', false, "lda", nullptr } }, + { 0x22, { false, false, 'f', true, "ldq", nullptr } }, { 0x32, { false, true, 'f', true, "ldqa", nullptr } }, + { 0x33, { false, true, 'f', true, "ldda", nullptr } }, + { 0x34, { true, true, 'f', false, "sta", nullptr } }, + { 0x26, { true, false, 'f', true, "stq", nullptr } }, { 0x36, { true, true, 'f', true, "stqa", nullptr } }, + { 0x37, { true, true, 'f', true, "stda", nullptr } } +}; + +const sparc_disassembler::asi_desc_map::value_type sparc_disassembler::V9_ASI_DESC[] = { + { 0x10, { "#ASI_AIUP", nullptr } }, + { 0x11, { "#ASI_AIUS", nullptr } }, + { 0x18, { "#ASI_AIUP_L", nullptr } }, + { 0x19, { "#ASI_AIUS_L", nullptr } }, + { 0x80, { "#ASI_P", nullptr } }, + { 0x81, { "#ASI_S", nullptr } }, + { 0x82, { "#ASI_PNF", nullptr } }, + { 0x83, { "#ASI_SNF", nullptr } }, + { 0x88, { "#ASI_P_L", nullptr } }, + { 0x89, { "#ASI_S_L", nullptr } }, + { 0x8a, { "#ASI_PNF_L", nullptr } }, + { 0x8b, { "#ASI_SNF_L", nullptr } } +}; + +const sparc_disassembler::prftch_desc_map::value_type sparc_disassembler::V9_PRFTCH_DESC[] = +{ + { 0x00, { "#n_reads" } }, + { 0x01, { "#one_read" } }, + { 0x02, { "#n_writes" } }, + { 0x03, { "#one_write" } }, + { 0x04, { "#page" } } +}; + + +inline UINT32 sparc_disassembler::freg(UINT32 val, bool shift) const +{ + return (shift && (m_version >= 9)) ? ((val & 0x1e) | ((val << 5) & 0x20)) : val; +} + +template inline void sparc_disassembler::add_fpop1_desc(const T &desc) +{ + for (const auto &it : desc) + m_fpop1_desc.insert(it); +} + +template inline void sparc_disassembler::add_fpop2_desc(const T &desc) +{ + for (const auto &it : desc) + m_fpop2_desc.insert(it); +} + +template inline void sparc_disassembler::add_ldst_desc(const T &desc) +{ + for (const auto &it : desc) + m_ldst_desc.insert(it); +} + +inline void sparc_disassembler::pad_op_field(char *buf, char *&output) const +{ + while ((output - buf) < m_op_field_width) *output++ = ' '; +} + +inline void sparc_disassembler::print(char *&output, const char *fmt, ...) +{ + va_list vl; + va_start(vl, fmt); + output += std::vsprintf(output, fmt, vl); + va_end(vl); +} + + +sparc_disassembler::sparc_disassembler(unsigned version) + : m_version(version) + , m_op_field_width(9) + , m_branch_desc{ + EMPTY_BRANCH_DESC, + (version >= 9) ? BPCC_DESC : EMPTY_BRANCH_DESC, // branch on integer condition codes with prediction, SPARCv9 + BICC_DESC, // branch on integer condition codes + (version >= 9) ? BPR_DESC : EMPTY_BRANCH_DESC, // branch on integer register with prediction, SPARCv9 + EMPTY_BRANCH_DESC, + (version >= 9) ? FBPFCC_DESC : EMPTY_BRANCH_DESC, // branch on floating-point condition codes with prediction, SPARCv9 + FBFCC_DESC, // branch on floating-point condition codes + (version == 8) ? CBCCC_DESC : EMPTY_BRANCH_DESC // branch on coprocessor condition codes, SPARCv8 + } + , m_simple_int_op_desc(std::begin(SIMPLE_INT_OP_DESC), std::end(SIMPLE_INT_OP_DESC)) + , m_state_reg_desc() + , m_fpop1_desc(std::begin(V7_FPOP1_DESC), std::end(V7_FPOP1_DESC)) + , m_fpop2_desc(std::begin(V7_FPOP2_DESC), std::end(V7_FPOP2_DESC)) + , m_ldst_desc(std::begin(V7_LDST_DESC), std::end(V7_LDST_DESC)) + , m_asi_desc() + , m_prftch_desc() +{ + if (m_version >= 9) + { + m_op_field_width = 11; + + m_simple_int_op_desc.find(0x08)->second.mnemonic = "addc"; + m_simple_int_op_desc.find(0x0c)->second.mnemonic = "subc"; + m_simple_int_op_desc.find(0x18)->second.mnemonic = "addccc"; + m_simple_int_op_desc.find(0x1c)->second.mnemonic = "subccc"; + + add_state_reg_desc(V9_STATE_REG_DESC), + add_fpop1_desc(V9_FPOP1_DESC); + add_fpop2_desc(V9_FPOP2_DESC); + + m_ldst_desc.find(0x00)->second.mnemonic = "lduw"; + m_ldst_desc.find(0x04)->second.mnemonic = "stw"; + m_ldst_desc.find(0x10)->second.mnemonic = "lduwa"; + m_ldst_desc.find(0x14)->second.mnemonic = "stwa"; + m_ldst_desc.erase(0x30); // LDC + m_ldst_desc.erase(0x33); // LDDC + m_ldst_desc.erase(0x34); // STC + m_ldst_desc.erase(0x37); // STDC + add_ldst_desc(V9_LDST_DESC); + + add_asi_desc(V9_ASI_DESC); + + add_prftch_desc(V9_PRFTCH_DESC); + } +} + + +offs_t sparc_disassembler::dasm(char *buf, offs_t pc, UINT32 op) const +{ + switch (OP) + { + case 0: // Branches & SETHI + switch (OP2) { - UINT32 val = SIMM13 & 0x00001fff; - if (SIMM13 < 0) + case 0: + print(buf, "%-*s0x%06x", m_op_field_width, (m_version >= 9) ? "illtrap" : "unimp", CONST22); + break; + case 4: + if (IMM22 == 0 && RD == 0) + print(buf, "nop"); + else + print(buf, "%-*s%%hi(0x%08x),%s", m_op_field_width, "sethi", IMM22, REG_NAMES[RD]); + break; + default: + return dasm_branch(buf, pc, op); + } + return 4 | DASMFLAG_SUPPORTED; + case 1: + print(buf, "%-*s%%pc%c0x%08x ! %08x", m_op_field_width, "call", (DISP30 < 0) ? '-' : '+', std::abs(DISP30), pc + DISP30); + return 4 | DASMFLAG_SUPPORTED; + case 2: + switch (OP3) + { + case 0x00: + if (USEIMM && (RS1 == RD)) { - print(rs2, "-0x%x", val); + if (SIMM13 == 1) print(buf, "%-*s%s", m_op_field_width, "inc", REG_NAMES[RD]); + else print(buf, "%-*s%d,%s", m_op_field_width, "inc", SIMM13, REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x02: + if (RS1 == 0) + { + if (USEIMM) print(buf, "%-*s%d,%s", m_op_field_width, "mov", SIMM13, REG_NAMES[RD]); + else if (RS2 == 0) print(buf, "%-*s%s", m_op_field_width, "clr", REG_NAMES[RD]); + else print(buf, "%-*s%s,%s", m_op_field_width, "mov", REG_NAMES[RS2], REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + else if (RS1 == RD) + { + if (USEIMM) print(buf, "%-*s0x%08x,%s", m_op_field_width, "bset", SIMM13, REG_NAMES[RD]); + else print(buf, "%-*s%s,%s", m_op_field_width, "bset", REG_NAMES[RS2], REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x03: + if (RS1 == RD) + { + if (USEIMM) print(buf, "%-*s0x%08x,%s", m_op_field_width, "btog", SIMM13, REG_NAMES[RD]); + else print(buf, "%-*s%s,%s", m_op_field_width, "btog", REG_NAMES[RS2], REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x04: + if (USEIMM && (RS1 == RD)) + { + if (SIMM13 == 1) print(buf, "%-*s%s", m_op_field_width, "dec", REG_NAMES[RD]); + else print(buf, "%-*s%d,%s", m_op_field_width, "dec", SIMM13, REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x05: + if (RS1 == RD) + { + if (USEIMM) print(buf, "%-*s0x%08x,%s", m_op_field_width, "bclr", SIMM13, REG_NAMES[RD]); + else print(buf, "%-*s%s,%s", m_op_field_width, "bclr", REG_NAMES[RS2], REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x07: + if ((USEIMM && (SIMM13 == 0)) || (!USEIMM && (RS2 == 0))) + { + if (RS1 == RD) print(buf, "%-*s%s", m_op_field_width, "not", REG_NAMES[RD]); + else print(buf, "%-*s%s,%s", m_op_field_width, "not", REG_NAMES[RS1], REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x10: + if (USEIMM && (RS1 == RD)) + { + if (SIMM13 == 1) print(buf, "%-*s%s", m_op_field_width, "inccc", REG_NAMES[RD]); + else print(buf, "%-*s%d,%s", m_op_field_width, "inccc", SIMM13, REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x11: + if (RD == 0) + { + if (USEIMM) print(buf, "%-*s0x%08x,%s", m_op_field_width, "btst", SIMM13, REG_NAMES[RS1]); + else print(buf, "%-*s%s,%s", m_op_field_width, "btst", REG_NAMES[RS2], REG_NAMES[RS1]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x14: + if (RD == 0) + { + if (USEIMM) print(buf, "%-*s%s,%d", m_op_field_width, "cmp", REG_NAMES[RS1], SIMM13); + else print(buf, "%-*s%s,%s", m_op_field_width, "cmp", REG_NAMES[RS1], REG_NAMES[RS2]); + return 4 | DASMFLAG_SUPPORTED; + } + else if (USEIMM && (RS1 == RD)) + { + if (SIMM13 == 1) print(buf, "%-*s%s", m_op_field_width, "deccc", REG_NAMES[RD]); + else print(buf, "%-*s%d,%s", m_op_field_width, "deccc", SIMM13, REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x25: + return dasm_shift(buf, pc, op, "sll", "sllx", nullptr); + case 0x26: + return dasm_shift(buf, pc, op, "srl", "srlx", "clruw"); + case 0x27: + return dasm_shift(buf, pc, op, "sra", "srax", "signx"); + case 0x28: + return dasm_read_state_reg(buf, pc, op); + case 0x29: + if (m_version <= 8) + { + print(buf, "%-*s%%psr,%s", m_op_field_width, "rd", REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x2a: + if (m_version >= 9) + { + if (V9_PRIV_REG_NAMES[RS1]) + { + print(buf, "%-*s%s,%s", m_op_field_width, "rdpr", V9_PRIV_REG_NAMES[RS1], REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } } else { - print(rs2, "0x%x", val); + print(buf, "%-*s%%wim,%s", m_op_field_width, "rd", REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x2b: + if (m_version >= 9) + { + if (!USEIMM) + { + print(buf, "flushw"); + return 4 | DASMFLAG_SUPPORTED; + } + } + else + { + print(buf, "%-*s%%tbr,%s", m_op_field_width, "rd", REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x2c: + return dasm_move_cond(buf, pc, op); + case 0x2e: + if ((m_version >= 9) && (RS1 == 0)) + { + if (USEIMM) print(buf, "%-*s%d,%s", m_op_field_width, "popc", SIMM13, REG_NAMES[RD]); + else print(buf, "%-*s%s,%s", m_op_field_width, "popc", REG_NAMES[RS2], REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x2f: + return dasm_move_reg_cond(buf, pc, op); + case 0x30: + return dasm_write_state_reg(buf, pc, op); + case 0x31: + if (m_version >= 9) + { + switch (RD) + { + case 0: + print(buf, "saved"); + return 4 | DASMFLAG_SUPPORTED; + case 1: + print(buf, "restored"); + return 4 | DASMFLAG_SUPPORTED; + } + } + else + { + if (!USEIMM) print(buf, "%-*s%s,%s,%%psr", m_op_field_width, "wr", REG_NAMES[RS1], REG_NAMES[RS2]); + else if (RS1 == 0) print(buf, "%-*s0x%08x,%%psr", m_op_field_width, "wr", SIMM13); + else print(buf, "%-*s%s,0x%08x,%%psr", m_op_field_width, "wr", REG_NAMES[RS1], SIMM13); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x32: + if (m_version >= 9) + { + if (V9_PRIV_REG_NAMES[RD]) + { + // FIXME: this disassembles wrpr to %fq and %ver which are actually illegal + if (!USEIMM) print(buf, "%-*s%s,%s,%s", m_op_field_width, "wrpr", REG_NAMES[RS1], REG_NAMES[RS2], V9_PRIV_REG_NAMES[RD]); + else if (RS1 == 0) print(buf, "%-*s0x%08x,%s", m_op_field_width, "wrpr", SIMM13, V9_PRIV_REG_NAMES[RD]); + else print(buf, "%-*s%s,0x%08x,%s", m_op_field_width, "wrpr", REG_NAMES[RS1], SIMM13, V9_PRIV_REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + } + else + { + if (!USEIMM) print(buf, "%-*s%s,%s,%%wim", m_op_field_width, "wr", REG_NAMES[RS1], REG_NAMES[RS2]); + else if (RS1 == 0) print(buf, "%-*s0x%08x,%%wim", m_op_field_width, "wr", SIMM13); + else print(buf, "%-*s%s,0x%08x,%%wim", m_op_field_width, "wr", REG_NAMES[RS1], SIMM13); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x33: + if (m_version <= 8) + { + if (!USEIMM) print(buf, "%-*s%s,%s,%%tbr", m_op_field_width, "wr", REG_NAMES[RS1], REG_NAMES[RS2]); + else if (RS1 == 0) print(buf, "%-*s0x%08x,%%tbr", m_op_field_width, "wr", SIMM13); + else print(buf, "%-*s%s,0x%08x,%%tbr", m_op_field_width, "wr", REG_NAMES[RS1], SIMM13); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x34: + return dasm_fpop1(buf, pc, op); + case 0x35: + return dasm_fpop2(buf, pc, op); + case 0x36: + // TODO: hooks for IMPDEP1/CPop1 + break; + case 0x37: + // TODO: hooks for IMPDEP2/CPop2 + break; + case 0x38: + return dasm_jmpl(buf, pc, op); + case 0x39: + return dasm_return(buf, pc, op); + case 0x3a: + return dasm_tcc(buf, pc, op); + case 0x3b: + if (m_version >= 8) + { + print(buf, "%-*s", m_op_field_width, "flush"); + dasm_address(buf, op); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x3c: + if (!USEIMM && (RS1 == RS2) && (RS2 == RD) && (RD == 0)) + { + print(buf, "save"); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x3d: + if (!USEIMM && (RS1 == RS2) && (RS2 == RD) && (RD == 0)) + { + print(buf, "restore"); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x3e: + if ((m_version >= 9) & ((op & 0x7ffff) == 0)) + { + switch (RD) + { + case 0: print(buf, "done"); return 4 | DASMFLAG_SUPPORTED; + case 1: print(buf, "retry"); return 4 | DASMFLAG_SUPPORTED; + } + } + break; + } + { + const auto it(m_simple_int_op_desc.find(OP3)); + if ((it != m_simple_int_op_desc.end()) && (m_version >= it->second.min_version)) + { + if (!USEIMM) + print(buf, "%-*s%s,%s,%s", m_op_field_width, it->second.mnemonic, REG_NAMES[RS1], REG_NAMES[RS2], REG_NAMES[RD]); + else if (it->second.hex_imm) + print(buf, "%-*s%s,0x%08x,%s", m_op_field_width, it->second.mnemonic, REG_NAMES[RS1], SIMM13, REG_NAMES[RD]); + else + print(buf, "%-*s%s,%d,%s", m_op_field_width, it->second.mnemonic, REG_NAMES[RS1], SIMM13, REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; } } - else if (!rs1present) - { - print(rs2, "0x0"); - } + break; + case 3: + return dasm_ldst(buf, pc, op); + } + return dasm_invalid(buf, pc, op); +} + + +offs_t sparc_disassembler::dasm_invalid(char *buf, offs_t pc, UINT32 op) const +{ + print(buf, "%-*s0x%08x ! ", m_op_field_width, ".word", op); + if (OP == 0) + { + print(buf, "op=%x op2=%01x a=%01x cond=%01x", OP, OP2, ANNUL, COND); + } + else if ((OP == 2) && ((OP3 == 0x34) || (OP3 == 0x35))) + { + print(buf, "FPop%d opf=%03x rd=%d rs1=%d rs2=%d", 1 + (OP3 & 1), OPF, RD, RS1, RS2); + } + else if ((OP == 2) && ((OP3 == 0x36) || (OP3 == 0x37))) + { + if (m_version >= 9) + print(buf, "IMPDEP%d impl-dep=%02x impl-dep=%05x", 1 + (OP3 & 1), RD, op & 0x7ffff); + else + print(buf, "CPop%d opf=%03x rd=%d rs1=%d rs2=%d", 1 + (OP3 & 1), OPC, RD, RS1, RS2); } else { - if (RS2 != 0) - { - if (rs1present) - { - print(rs2, "+%s", regnames[RS2]); - } - else - { - print(rs2, "%s", regnames[RS2]); - } - } - else if (!rs1present) - { - print(rs2, "%s", regnames[RS2]); - } + print(buf, "op=%x op3=%02x i=%01x rd=%d", OP, OP3, USEIMM, RD); } - print(address, "[%s%s]", rs1, rs2); + return 4 | DASMFLAG_SUPPORTED; } -void sparc_dasm_fpop1(char *buffer, UINT32 op) + +offs_t sparc_disassembler::dasm_branch(char *buf, offs_t pc, UINT32 op) const { - switch (OPF) - { - case 0x01: print(buffer, "fmovs %%f%d,%%f%d", RS2, RD); break; - case 0x05: print(buffer, "fnegs %%f%d,%%f%d", RS2, RD); break; - case 0x09: print(buffer, "fabss %%f%d,%%f%d", RS2, RD); break; - case 0x29: print(buffer, "fsqrts %%f%d,%%f%d", RS2, RD); break; - case 0x2a: print(buffer, "fsqrtd %%f%d,%%f%d", RS2, RD); break; - case 0x2b: print(buffer, "fsqrtq %%f%d,%%f%d", RS2, RD); break; - case 0x41: print(buffer, "fadds %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x42: print(buffer, "faddd %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x43: print(buffer, "faddq %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x45: print(buffer, "fsubs %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x46: print(buffer, "fsubd %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x47: print(buffer, "fsubq %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x49: print(buffer, "fmuls %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x4a: print(buffer, "fmuld %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x4b: print(buffer, "fmulq %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x4d: print(buffer, "fdivs %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x4e: print(buffer, "fdivd %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x4f: print(buffer, "fdivq %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x69: print(buffer, "fsmuld %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0x6e: print(buffer, "fdmulq %%f%d,%%f%d,%%f%d", RS1, RS2, RD); break; - case 0xc4: print(buffer, "fitos %%f%d,%%f%d", RS2, RD); break; - case 0xc6: print(buffer, "fdtos %%f%d,%%f%d", RS2, RD); break; - case 0xc7: print(buffer, "fqtos %%f%d,%%f%d", RS2, RD); break; - case 0xc8: print(buffer, "fitod %%f%d,%%f%d", RS2, RD); break; - case 0xc9: print(buffer, "fstod %%f%d,%%f%d", RS2, RD); break; - case 0xcb: print(buffer, "fqtod %%f%d,%%f%d", RS2, RD); break; - case 0xcc: print(buffer, "fitoq %%f%d,%%f%d", RS2, RD); break; - case 0xcd: print(buffer, "fstoq %%f%d,%%f%d", RS2, RD); break; - case 0xce: print(buffer, "fdtoq %%f%d,%%f%d", RS2, RD); break; - case 0xd1: print(buffer, "fstoi %%f%d,%%f%d", RS2, RD); break; - case 0xd2: print(buffer, "fdtoi %%f%d,%%f%d", RS2, RD); break; - case 0xd3: print(buffer, "fqtoi %%f%d,%%f%d", RS2, RD); break; - } -} + char *ptr(buf); + const branch_desc &desc(m_branch_desc[OP2]); + const char * const mnemonic(desc.mnemonic[COND]); + if (!mnemonic || (desc.use_cc && !desc.reg_cc[BRCC])) return dasm_invalid(buf, pc, op); -void sparc_dasm_ldst(char *buffer, UINT32 op) -{ - static const char * const ldstnames[64] = { - "ld ", "ldub ", "lduh ", "ldd ", "st ", "stb ", "sth ", "std ", - "invalid ", "ldsb ", "ldsh ", "invalid ", "invalid ", "ldstub ", "invalid ", "swap ", - "lda ", "lduba ", "lduha ", "ldda ", "sta ", "stba ", "stha ", "stda ", - "invalid ", "ldsba ", "ldsha ", "invalid ", "invalid ", "ldstuba ", "invalid ", "swapa ", - "ld ", "ld ", "invalid ", "ldd ", "st ", "st ", "std ", "std ", - "ld ", "ld ", "invalid ", "ldd ", "st ", "st ", "std ", "std ", - "invalid ", "invalid ", "invalid ", "invalid ", "invalid ", "invalid ", "invalid ", "invalid ", - "invalid ", "invalid ", "invalid ", "invalid ", "invalid ", "invalid ", "invalid ", "invalid " - }; - - static const int LOAD = 0; - static const int STORE = 1; - static const int LOAD_ALT = 2; - static const int STORE_ALT = 3; - static const int LOAD_PR = 4; - static const int STORE_PR = 5; - static const int LDST_SR = 6; - static const int INVALID = 7; - - static const int ldsttype[64] = { - LOAD, LOAD, LOAD, LOAD, STORE, STORE, STORE, STORE, - INVALID, LOAD, LOAD, INVALID, INVALID, LOAD, INVALID, LOAD, - LOAD_ALT, LOAD_ALT, LOAD_ALT, LOAD_ALT, STORE_ALT, STORE_ALT, STORE_ALT, STORE_ALT, - INVALID, LOAD_ALT, LOAD_ALT, INVALID, INVALID, LOAD_ALT, INVALID, LOAD_ALT, - LOAD_PR, LDST_SR, INVALID, LOAD_PR, STORE_PR, LDST_SR, LDST_SR, STORE_PR, - LOAD_PR, LDST_SR, INVALID, LOAD_PR, STORE_PR, LDST_SR, LDST_SR, STORE_PR, - INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, - }; - - static const char * const ldstformats[64] = { - "%s%s,%s", "%s%s,%s", "%s%s,%s", "%s%s,%s", "%s%s,%s", "%s%s,%s", "%s%s,%s", "%s%s,%s", - INVALFMT, "%s%s,%s", "%s%s,%s", INVALFMT, INVALFMT, "%s%s,%s", INVALFMT, "%s%s,%s", - "%s%s%d,%s", "%s%s%d,%s", "%s%s%d,%s", "%s%s%d,%s", "%s%s,%s%d", "%s%s,%s%d", "%s%s,%s%d", "%s%s,%s%d", - INVALFMT, "%s%s%d,%s", "%s%s%d,%s", INVALFMT, INVALFMT, "%s%s%d,%s", INVALFMT, "%s%s%d,%s", - "%s%s,%%f%d", "%s%s,%%fsr", INVALFMT, "%s%s,%%f%d", "%s%%f%d,%s", "%s%%fsr,%s", "%s%%fq,%s", "%s%%f%d,%s", - "%s%s,%%c%d", "%s%s,%%csr", INVALFMT, "%s%s,%%c%d", "%s%%c%d,%s", "%s%%csr,%s", "%s%%cq,%s", "%s%%c%d,%s", - INVALFMT, INVALFMT, INVALFMT, INVALFMT, INVALFMT, INVALFMT, INVALFMT, INVALFMT, - INVALFMT, INVALFMT, INVALFMT, INVALFMT, INVALFMT, INVALFMT, INVALFMT, INVALFMT, - }; - - char address[256]; - sparc_dasm_address(address, op); - - switch (ldsttype[OP3]) - { - case LOAD: print(buffer, ldstformats[OP3], ldstnames[OP3], address, regnames[RD]); break; - case STORE: print(buffer, ldstformats[OP3], ldstnames[OP3], regnames[RD], address); break; - case LOAD_ALT: print(buffer, ldstformats[OP3], ldstnames[OP3], address, ASI, regnames[RD]); break; - case STORE_ALT: print(buffer, ldstformats[OP3], ldstnames[OP3], regnames[RD], address, ASI); break; - case LOAD_PR: print(buffer, ldstformats[OP3], ldstnames[OP3], address, RD); break; - case STORE_PR: print(buffer, ldstformats[OP3], ldstnames[OP3], RD, address); break; - case LDST_SR: print(buffer, ldstformats[OP3], ldstnames[OP3], address); break; - default: print(buffer, ldstformats[OP3], ldstnames[OP3], op, RS1, RD, SIMM13, USEIMM, ASI, RS2); break; - } -} - -offs_t sparc_dasm(char *buffer, offs_t pc, UINT32 op) -{ - static const char * const branchnames[32] = { - "bn ", "be ", "ble ", "bl ", "bleu ", "bcs ", "bneg ", "bvs ", - "ba ", "bne ", "bg ", "bge ", "bgu ", "bcc ", "bpos ", "bvc ", - "bn,a ", "be,a ", "ble,a ", "bl,a ", "bleu,a ", "bcs,a ", "bneg,a ", "bvs,a ", - "ba,a ", "bne,a ", "bg,a ", "bge,a ", "bgu,a ", "bcc,a ", "bpos,a ", "bvc,a " - }; - static const char * const fpbranchnames[32] = { - "fbn ", "fbne ", "fblg ", "fbul ", "fbl ", "fbug ", "fbg ", "fbu ", - "fba ", "fbe ", "fbue ", "fbge ", "fbuge ", "fble ", "fbule ", "fbo ", - "fbn,a ", "fbne,a ", "fblg,a ", "fbul,a ", "fbl,a ", "fbug,a ", "fbg,a ", "fbu,a ", - "fba,a ", "fbe,a ", "fbue,a ", "fbge,a ", "fbuge,a ", "fble,a ", "fbule,a ", "fbo,a " - }; - static const char * const copbranchnames[32] = { - "cbn ", "cb123 ", "cb12 ", "cb13 ", "cb1 ", "cb23 ", "cb2 ", "cb3 ", - "cba ", "cb0 ", "cb03 ", "cb02 ", "cb023 ", "cb01 ", "cb013 ", "cb012 ", - "cbn,a ", "cb123,a ", "cb12,a ", "cb13,a ", "cb1,a ", "cb23,a ", "cb2,a ", "cb3,a ", - "cba,a ", "cb0,a ", "cb03,a ", "cb02,a ", "cb023,a ", "cb01,a ", "cb013,a ", "cb012,a " - }; - static const char * const trapnames[16] = { - "tn ", "te ", "tle ", "tl ", "tleu ", "tcs ", "tneg ", "tvs ", - "ta ", "tne ", "tg ", "tge ", "tgu ", "tcc ", "tpos ", "tvc " - }; - - switch (OP) - { - case 0: // Bicc, SETHI, FBfcc - switch (OP2) - { - case 0: // unimp - print(buffer, "unimp %06x", CONST22); - break; - case 2: // branch on integer condition codes - case 6: // branch on floating-point condition codes - case 7: // branch on coprocessor condition codes, SPARCv8 - { - int index = (ANNUL << 4) | COND; - char sign[2]; - memset(sign, 0, 2); - INT32 disp = DISP22; - if (disp < 0) - { - print(sign, "-"); - disp = -disp; - } - print(buffer, "%s%s0x%06x ; %08x", (OP2 == 2) ? branchnames[index] : ((OP2 == 6) ? fpbranchnames[index] : copbranchnames[index]), sign, disp, pc + DISP22); - break; - } - case 4: // SETHI - if (IMM22 == 0 && RD == 0) - print(buffer, "nop "); - else - print(buffer, "sethi %%hi(0x%08x),%s", IMM22, regnames[RD]); - break; - default: - print(buffer, "invalid"); - break; - } - break; - case 1: // CALL - print(buffer, "call 0x%08x ; %08x", DISP30, DISP30 << 2); - break; - case 2: - if (USEIMM) - { - switch (OP3) - { - case 0: - if (RS1 == RD) - if (SIMM13 == 1) - print(buffer, "inc %s", regnames[RD]); - else - print(buffer, "inc %d,%s", SIMM13, regnames[RD]); - else - print(buffer, "add %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); - break; - case 1: print(buffer, "and %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 2: - if (RS1 == 0) - print(buffer, "mov %d,%s", SIMM13, regnames[RD]); - else if (RS1 == RD) - print(buffer, "bset %d,%s", SIMM13, regnames[RD]); - else - print(buffer, "or %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); - break; - case 3: - if (RS1 == RD) - print(buffer, "btog %d,%s", SIMM13, regnames[RD]); - else - print(buffer, "xor %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); - break; - case 4: - if (RS1 == RD) - if (SIMM13 == 1) - print(buffer, "dec %s", regnames[RD]); - else - print(buffer, "dec %d,%s", SIMM13, regnames[RD]); - else - print(buffer, "sub %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); - break; - case 5: - if (RS1 == RD) - print(buffer, "bclr %d,%s", SIMM13, regnames[RD]); - else - print(buffer, "andn %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); - break; - case 6: print(buffer, "orn %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 7: - if (SIMM13 == 0) - if (RS1 == RD) - print(buffer, "not %s", regnames[RD]); - else - print(buffer, "not %s,%s", regnames[RS1], regnames[RD]); - else - print(buffer, "xnor %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); - break; - case 8: print(buffer, "addx %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 10: print(buffer, "umul %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; // SPARCv8 - case 11: print(buffer, "smul %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; // SPARCv8 - case 12: print(buffer, "subx %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 14: print(buffer, "udiv %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; // SPARCv8 - case 15: print(buffer, "sdiv %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; // SPARCv8 - case 16: - if (RS1 == RD) - if (SIMM13 == 1) - print(buffer, "inccc %s", regnames[RD]); - else - print(buffer, "inccc %d,%s", SIMM13, regnames[RD]); - else - print(buffer, "addcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); - break; - case 17: - if (RD == 0) - print(buffer, "btst %d,%s", SIMM13, regnames[RS1]); - else - print(buffer, "andcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); - break; - case 18: print(buffer, "orcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 19: print(buffer, "xorcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 20: - if (RD == 0) - print(buffer, "cmp %s,%d", regnames[RS1], SIMM13); - else if (RS1 == RD) - if (SIMM13 == 1) - print(buffer, "deccc %s", regnames[RD]); - else - print(buffer, "deccc %d,%s", SIMM13, regnames[RD]); - else - print(buffer, "subcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); - break; - case 21: print(buffer, "andncc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 22: print(buffer, "orncc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 23: print(buffer, "xnorcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 24: print(buffer, "addxcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 26: print(buffer, "umulcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; // SPARCv8 - case 27: print(buffer, "smulcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; // SPARCv8 - case 28: print(buffer, "subxcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 30: print(buffer, "udivcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; // SPARCv8 - case 31: print(buffer, "sdivcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; // SPARCv8 - case 32: print(buffer, "taddcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 33: print(buffer, "tsubcc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 34: print(buffer, "taddcctv %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 35: print(buffer, "tsubcctv %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 36: print(buffer, "mulscc %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 37: print(buffer, "sll %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 38: print(buffer, "srl %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 39: print(buffer, "sra %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 40: - if (RS1 == 0) - print(buffer, "rd %%y,%s", regnames[RD]); - else if (RS1 == 15 && RD == 0) - print(buffer, "stbar "); // SPARCv8 - else - print(buffer, "rd %%asr%d,%s", RS1, regnames[RD]); // SPARCv8 - break; - case 41: print(buffer, "rd %%psr,%s", regnames[RD]); break; - case 42: print(buffer, "rd %%wim,%s", regnames[RD]); break; - case 43: print(buffer, "rd %%tbr,%s", regnames[RD]); break; - case 48: - if (RD == 0) - print(buffer, "wr %s,%d,%%y", regnames[RS1], SIMM13); - else - print(buffer, "wr %s,%d,%%asr%d", regnames[RS1], SIMM13, RD); - break; - case 49: - if (RS1 == 0) - print(buffer, "wr %d,%%psr", SIMM13); - else - print(buffer, "wr %s,%d,%%psr", regnames[RS1], SIMM13); - break; - case 50: - if (RS1 == 0) - print(buffer, "wr %d,%%wim", SIMM13); - else - print(buffer, "wr %s,%d,%%wim", regnames[RS1], SIMM13); - break; - case 51: - if (RS1 == 0) - print(buffer, "wr %d,%%tbr", SIMM13); - else - print(buffer, "wr %s,%d,%%tbr", regnames[RS1], SIMM13); - break; - case 52: // FPop1 - sparc_dasm_fpop1(buffer, op); - break; - case 53: // FPop2 - switch (OPF) - { - case 0x51: print(buffer, "fcmps %%f%d,%%f%d", RS1, RS2); break; - case 0x52: print(buffer, "fcmpd %%f%d,%%f%d", RS1, RS2); break; - case 0x53: print(buffer, "fcmpq %%f%d,%%f%d", RS1, RS2); break; - case 0x55: print(buffer, "fcmpes %%f%d,%%f%d", RS1, RS2); break; - case 0x56: print(buffer, "fcmped %%f%d,%%f%d", RS1, RS2); break; - case 0x57: print(buffer, "fcmpeq %%f%d,%%f%d", RS1, RS2); break; - } - break; - case 56: - if (RS1 == 31 && SIMM13 == 8) - print(buffer, "ret "); - else if (RS1 == 15 && SIMM13 == 8) - print(buffer, "retl "); - else if (RD == 0) - print(buffer, "jmp %s,%d", regnames[RS1], SIMM13); - else if (RD == 15) - print(buffer, "call %s,%d", regnames[RS1], SIMM13); - else - print(buffer, "jmpl %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); - break; - case 57: - { - char address[256]; - sparc_dasm_address(address, op); - print(buffer, "rett %s", address); - break; - } - case 58: print(buffer, "%s%s,%d,%s", trapnames[COND], regnames[RS1], IMM7, regnames[RD]); break; - case 59: - if (RD == 0) - print(buffer, "flush %s.%d", regnames[RS1], SIMM13); // SPARCv8 - else - print(buffer, "invalid "); - break; - case 60: print(buffer, "save %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - case 61: print(buffer, "restore %s,%d,%s", regnames[RS1], SIMM13, regnames[RD]); break; - default: print(buffer, "invalid "); break; - } - } - else - { - switch (OP3) - { - case 0: print(buffer, "add %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 1: print(buffer, "and %s,%d,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 2: - if (RS1 == 0) - print(buffer, "mov %s,%s", regnames[RS2], regnames[RD]); - else if (RS1 == RD) - print(buffer, "bset %s,%s", regnames[RS2], regnames[RD]); - else - print(buffer, "or %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); - break; - case 3: - if (RS1 == RD) - print(buffer, "btog %s,%s", regnames[RS2], regnames[RD]); - else - print(buffer, "xor %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); - break; - case 4: print(buffer, "sub %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 5: - if (RS1 == RD) - print(buffer, "bclr %s,%s", regnames[RS2], regnames[RD]); - else - print(buffer, "andn %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); - break; - case 6: print(buffer, "orn %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 7: - if (RS2 == 0) - if (RS1 == RD) - print(buffer, "not %s", regnames[RD]); - else - print(buffer, "not %s,%s", regnames[RS1], regnames[RD]); - else - print(buffer, "xnor %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); - break; - case 8: print(buffer, "addx %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 10: print(buffer, "umul %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; // SPARCv8 - case 11: print(buffer, "smul %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; // SPARCv8 - case 12: print(buffer, "subx %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 14: print(buffer, "udiv %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; // SPARCv8 - case 15: print(buffer, "sdiv %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; // SPARCv8 - case 16: print(buffer, "addcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 17: - if (RD == 0) - print(buffer, "btst %s,%s", regnames[RS2], regnames[RS1]); - else - print(buffer, "andcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); - break; - case 18: print(buffer, "orcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 19: print(buffer, "xorcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 20: - if (RD == 0) - print(buffer, "cmp %s,%s", regnames[RS1], regnames[RS2]); - else - print(buffer, "subcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); - break; - case 21: print(buffer, "andncc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 22: print(buffer, "orncc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 23: print(buffer, "xnorcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 24: print(buffer, "addxcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 26: print(buffer, "umulcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; // SPARCv8 - case 27: print(buffer, "smulcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; // SPARCv8 - case 28: print(buffer, "subxcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 30: print(buffer, "udivcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; // SPARCv8 - case 31: print(buffer, "sdivcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; // SPARCv8 - case 32: print(buffer, "taddcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 33: print(buffer, "tsubcc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 34: print(buffer, "taddcctv %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 35: print(buffer, "tsubcctv %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 36: print(buffer, "mulscc %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 37: print(buffer, "sll %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 38: print(buffer, "srl %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 39: print(buffer, "sra %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 40: - if (RS1 == 0) - print(buffer, "rd %%y,%s", regnames[RD]); - else if (RS1 == 15 && RD == 0) - print(buffer, "stbar "); // SPARCv8 - else - print(buffer, "rd %%asr%d,%s", RS1, regnames[RD]); // SPARCv8 - break; - case 41: print(buffer, "rd %%psr,%s", regnames[RD]); break; - case 42: print(buffer, "rd %%wim,%s", regnames[RD]); break; - case 43: print(buffer, "rd %%tbr,%s", regnames[RD]); break; - case 48: - if (RD == 0) - print(buffer, "wr %s,%s,%%y", regnames[RS1], regnames[RS2]); - else - print(buffer, "wr %s,%s,%%asr%d", regnames[RS1], regnames[RS2], RD); - break; - case 49: print(buffer, "wr %s,%s,%%psr", regnames[RS1], regnames[RS2]); break; - case 50: print(buffer, "wr %s,%s,%%wim", regnames[RS1], regnames[RS2]); break; - case 51: print(buffer, "wr %s,%s,%%tbr", regnames[RS1], regnames[RS2]); break; - case 52: // FPop1 - sparc_dasm_fpop1(buffer, op); - break; - case 53: // FPop2 - switch (OPF) - { - case 0x51: print(buffer, "fcmps %%f%d,%%f%d", RS1, RS2); break; - case 0x52: print(buffer, "fcmpd %%f%d,%%f%d", RS1, RS2); break; - case 0x53: print(buffer, "fcmpq %%f%d,%%f%d", RS1, RS2); break; - case 0x55: print(buffer, "fcmpes %%f%d,%%f%d", RS1, RS2); break; - case 0x56: print(buffer, "fcmped %%f%d,%%f%d", RS1, RS2); break; - case 0x57: print(buffer, "fcmpeq %%f%d,%%f%d", RS1, RS2); break; - } - break; - case 56: - if (RD == 0) - if (RS1 == 0 && RS2 == 0) - print(buffer, "jmp %s", regnames[RS1]); - else if (RS1 == 0) - print(buffer, "jmp %s", regnames[RS2]); - else if (RS2 == 0) - print(buffer, "jmp %s", regnames[RS1]); - else - print(buffer, "jmp %s,%s", regnames[RS1], regnames[RS2]); - else if (RD == 15) - print(buffer, "call %s,%s", regnames[RS1], regnames[RS2]); - else - print(buffer, "jmpl %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); - break; - case 57: print(buffer, "rett %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); break; - case 58: print(buffer, "%s%s,%s,%s", trapnames[COND], regnames[RS1], regnames[RS2], regnames[RD]); break; - case 59: - if (RD == 0) - print(buffer, "flush %s.%s", regnames[RS1], regnames[RS2]); // SPARCv8 - else - print(buffer, "invalid "); - break; - case 60: - if (RS1 == RS2 && RS2 == RD && RD == 0) - print(buffer, "save "); - else - print(buffer, "save %s,%s,%s", regnames[RS1], regnames[RS2], regnames[RD]); - break; - case 61: - if (RS1 == RS2 && RS2 == RD && RD == 0) - print(buffer, "restore "); - else - print(buffer, "restore %s,%s,%s", regnames[RS1], regnames[RS1], regnames[RD]); - break; - default: print(buffer, "invalid "); break; - } - } - break; - case 3: // loads, stores - sparc_dasm_ldst(buffer, op); - break; - default: - print(buffer, "invalid "); - break; - } + print(ptr, "%s%s%s", mnemonic, ANNUL ? ",a" : "", (m_branch_desc[OP2].use_pred && !PRED) ? ",pn" : ""); + pad_op_field(buf, ptr); + if (desc.use_cc) print(ptr, "%s,", desc.reg_cc[BRCC]); + if (OP2 == 3) print(ptr, "%s,", REG_NAMES[RS1]); + const INT32 disp(desc.get_disp(op)); + print(ptr, "%%pc%c0x%0*x ! 0x%08x", (disp < 0) ? '-' : '+', desc.disp_width, std::abs(disp), pc + disp); return 4 | DASMFLAG_SUPPORTED; } -/*****************************************************************************/ -CPU_DISASSEMBLE( sparc ) +offs_t sparc_disassembler::dasm_shift(char *buf, offs_t pc, UINT32 op, const char *mnemonic, const char *mnemonicx, const char *mnemonicx0) const { - UINT32 op = *(UINT32 *)oprom; - op = BIG_ENDIANIZE_INT32(op); - return sparc_dasm(buffer, pc, op); + if ((m_version >= 9) && USEEXT) + { + if (USEIMM) + print(buf, "%-*s%s,%d,%s", m_op_field_width, mnemonicx, REG_NAMES[RS1], SHCNT64, REG_NAMES[RD]); + else if (!mnemonicx0 || (RS2 != 0)) + print(buf, "%-*s%s,%s,%s", m_op_field_width, mnemonicx, REG_NAMES[RS1], REG_NAMES[RS2], REG_NAMES[RD]); + else if (RS1 == RD) + print(buf, "%-*s%s", m_op_field_width, mnemonicx0, REG_NAMES[RD]); + else + print(buf, "%-*s%s,%s", m_op_field_width, mnemonicx0, REG_NAMES[RS1], REG_NAMES[RD]); + } + else if (USEIMM) + { + print(buf, "%-*s%s,%d,%s", m_op_field_width, mnemonic, REG_NAMES[RS1], SHCNT32, REG_NAMES[RD]); + } + else + { + print(buf, "%-*s%s,%s,%s", m_op_field_width, mnemonic, REG_NAMES[RS1], REG_NAMES[RS2], REG_NAMES[RD]); + } + return 4 | DASMFLAG_SUPPORTED; +} + + +offs_t sparc_disassembler::dasm_read_state_reg(char *buf, offs_t pc, UINT32 op) const +{ + if (RS1 == 0) + { + print(buf, "%-*s%%y,%s", m_op_field_width, "rd", REG_NAMES[RD]); + return 4 | DASMFLAG_SUPPORTED; + } + else if ((m_version == 8) || ((m_version >= 9) && !USEIMM)) + { + if (!USEIMM && (RS1 == 15) && (RD == 0)) + { + print(buf, "stbar"); + return 4 | DASMFLAG_SUPPORTED; + } + else + { + const auto it(m_state_reg_desc.find(RS1)); + if ((it == m_state_reg_desc.end()) || !it->second.reserved) + { + if ((it != m_state_reg_desc.end()) && it->second.read_name) + print(buf, "%-*s%s,%s", m_op_field_width, "rd", it->second.read_name, REG_NAMES[RD]); + else + print(buf, "%-*s%%asr%d,%s ! %s", m_op_field_width, "rd", RS1, REG_NAMES[RD], (RS1 < 16) ? "reserved" : "implementation-dependent"); + return 4 | DASMFLAG_SUPPORTED; + } + } + } + else if ((m_version >= 9) && USEIMM && (RS1 == 15) && (RD == 0)) + { + print(buf, "%-*s", m_op_field_width, "membar"); + UINT32 mask(MMASK | (CMASK << 4)); + if (mask == 0) print(buf, "0"); + if (mask & 1) print(buf, "#LoadLoad%s", (mask >> 1) ? "|" : ""); + mask >>= 1; + if (mask & 1) print(buf, "#StoreLoad%s", (mask >> 1) ? "|" : ""); + mask >>= 1; + if (mask & 1) print(buf, "#LoadStore%s", (mask >> 1) ? "|" : ""); + mask >>= 1; + if (mask & 1) print(buf, "#StoreStore%s", (mask >> 1) ? "|" : ""); + mask >>= 1; + if (mask & 1) print(buf, "#Lookaside%s", (mask >> 1) ? "|" : ""); + mask >>= 1; + if (mask & 1) print(buf, "#MemIssue%s", (mask >> 1) ? "|" : ""); + mask >>= 1; + if (mask & 1) print(buf, "#Sync"); + return 4 | DASMFLAG_SUPPORTED; + } + return dasm_invalid(buf, pc, op); +} + + +offs_t sparc_disassembler::dasm_write_state_reg(char *buf, offs_t pc, UINT32 op) const +{ + if (RD == 0) + { + if (USEIMM) print(buf, "%-*s%s,%d,%%y", m_op_field_width, "wr", REG_NAMES[RS1], SIMM13); + else print(buf, "%-*s%s,%s,%%y", m_op_field_width, "wr", REG_NAMES[RS1], REG_NAMES[RS2]); + return 4 | DASMFLAG_SUPPORTED; + } + else if (m_version >= 8) + { + if ((m_version >= 9) && USEIMM && (RS1 == 0) && (RD == 15)) + { + print(buf, "%-*s%d", m_op_field_width, "sir", SIMM13); + return 4 | DASMFLAG_SUPPORTED; + } + else + { + const auto it(m_state_reg_desc.find(RD)); + if ((it == m_state_reg_desc.end()) || !it->second.reserved) + { + if ((it != m_state_reg_desc.end()) && it->second.write_name) + { + if (USEIMM) print(buf, "%-*s%s,%d,%s", m_op_field_width, "wr", REG_NAMES[RS1], SIMM13, it->second.write_name); + else print(buf, "%-*s%s,%s,%s", m_op_field_width, "wr", REG_NAMES[RS1], REG_NAMES[RS2], it->second.write_name); + } + else + { + const char *const comment((RD < 16) ? "reserved" : "implementation-dependent"); + if (USEIMM) print(buf, "%-*s%s,%d,%%asr%d ! %s", m_op_field_width, "wr", REG_NAMES[RS1], SIMM13, RD, comment); + else print(buf, "%-*s%s,%s,%%asr%d ! %s", m_op_field_width, "wr", REG_NAMES[RS1], REG_NAMES[RS2], RD, comment); + } + return 4 | DASMFLAG_SUPPORTED; + } + } + } + return dasm_invalid(buf, pc, op); +} + + +offs_t sparc_disassembler::dasm_move_cond(char *buf, offs_t pc, UINT32 op) const +{ + if ((m_version < 9) || !MOVCC_CC_NAMES[MOVCC]) return dasm_invalid(buf, pc, op); + + char *ptr(buf); + print(ptr, "mov%s", MOVCC_COND_NAMES[MOVCOND | ((MOVCC << 2) & 16)]); + pad_op_field(buf, ptr); + if (USEIMM) + print(ptr, "%s,%d,%s", MOVCC_CC_NAMES[MOVCC], SIMM11, REG_NAMES[RD]); + else + print(ptr, "%s,%s,%s", MOVCC_CC_NAMES[MOVCC], REG_NAMES[RS2], REG_NAMES[RD]); + + return 4 | DASMFLAG_SUPPORTED; +} + +offs_t sparc_disassembler::dasm_move_reg_cond(char *buf, offs_t pc, UINT32 op) const +{ + if ((m_version < 9) || !MOVE_INT_COND_MNEMONICS[RCOND]) return dasm_invalid(buf, pc, op); + + if (USEIMM) + print(buf, "%-*s%s,%d,%s", m_op_field_width, MOVE_INT_COND_MNEMONICS[RCOND], REG_NAMES[RS1], SIMM10, REG_NAMES[RD]); + else + print(buf, "%-*s%s,%s,%s", m_op_field_width, MOVE_INT_COND_MNEMONICS[RCOND], REG_NAMES[RS1], REG_NAMES[RS2], REG_NAMES[RD]); + + return 4 | DASMFLAG_SUPPORTED; +} + + +offs_t sparc_disassembler::dasm_fpop1(char *buf, offs_t pc, UINT32 op) const +{ + const auto it(m_fpop1_desc.find(OPF)); + if (it == m_fpop1_desc.end()) return dasm_invalid(buf, pc, op); + + if (it->second.three_op) + print(buf, "%-*s%%f%d,%%f%d,%%f%d", m_op_field_width, it->second.mnemonic, freg(RS1, it->second.rs1_shift), freg(RS2, it->second.rs2_shift), freg(RD, it->second.rd_shift)); + else + print(buf, "%-*s%%f%d,%%f%d", m_op_field_width, it->second.mnemonic, freg(RS2, it->second.rs2_shift), freg(RD, it->second.rd_shift)); + return 4 | DASMFLAG_SUPPORTED; +} + + +offs_t sparc_disassembler::dasm_fpop2(char *buf, offs_t pc, UINT32 op) const +{ + // Move Floating-Point Register on Condition + if ((m_version >= 9) && (((op >> 18) & 1) == 0) && MOVCC_CC_NAMES[OPFCC]) + { + const char *mnemonic; + bool shift; + switch (OPFLOW) + { + case 1: mnemonic = "fmovs"; shift = false; break; + case 2: mnemonic = "fmovd"; shift = true; break; + case 3: mnemonic = "fmovq"; shift = true; break; + default: mnemonic = nullptr; + } + if (mnemonic) + { + char *ptr(buf); + print(ptr, "%s%s", mnemonic, MOVCC_COND_NAMES[MOVCOND | ((OPFCC << 2) & 16)]); + pad_op_field(buf, ptr); + print(ptr, "%s,%%f%d,%%f%d", MOVCC_CC_NAMES[OPFCC], freg(RS2, shift), freg(RD, shift)); + return 4 | DASMFLAG_SUPPORTED; + } + } + + const auto it(m_fpop2_desc.find(OPF)); + if (it != m_fpop2_desc.end()) + { + if (m_version >= 9) + { + if (it->second.int_rs1) + { + print(buf, "%-*s%s,%%f%d,%%f%d", m_op_field_width, it->second.mnemonic, REG_NAMES[RS1], freg(RS2, it->second.shift), freg(RD, it->second.shift)); + return 4 | DASMFLAG_SUPPORTED; + } + else if (RD < 4) + { + print(buf, "%-*s%%fcc%d,%%f%d,%%f%d", m_op_field_width, it->second.mnemonic, RD, freg(RS1, it->second.shift), freg(RS2, it->second.shift)); + return 4 | DASMFLAG_SUPPORTED; + } + } + else if (!it->second.int_rs1) + { + print(buf, "%-*s%%f%d,%%f%d", m_op_field_width, it->second.mnemonic, freg(RS1, it->second.shift), freg(RS2, it->second.shift)); + return 4 | DASMFLAG_SUPPORTED; + } + } + + return dasm_invalid(buf, pc, op); +} + + +offs_t sparc_disassembler::dasm_jmpl(char *buf, offs_t pc, UINT32 op) const +{ + if (USEIMM && (RD == 0) && ((RS1 == 15) || (RS1 == 31)) && (SIMM13 == 8)) + { + print(buf, (RS1 == 31) ? "ret" : "retl"); + } + else + { + print(buf, "%-*s", m_op_field_width, (RD == 0) ? "jmp" : (RD == 15) ? "call" : "jmpl"); + dasm_address(buf, op); + if ((RD != 0) && (RD != 15)) + print(buf, ",%s", REG_NAMES[RD]); + } + return 4 | DASMFLAG_SUPPORTED; +} + + +offs_t sparc_disassembler::dasm_return(char *buf, offs_t pc, UINT32 op) const +{ + print(buf, "%-*s", m_op_field_width, (m_version >= 9) ? "return" : "rett"); + dasm_address(buf, op); + return 4 | DASMFLAG_SUPPORTED; +} + + +offs_t sparc_disassembler::dasm_tcc(char *buf, offs_t pc, UINT32 op) const +{ + static const char *const tcc_names[16] = { + "tn", "te", "tle", "tl", "tleu", "tcs", "tneg", "tvs", + "ta", "tne", "tg", "tge", "tgu", "tcc", "tpos", "tvc" + }; + static const char *const cc_names[4] = { "%icc", nullptr, "%xcc", nullptr }; + const char *const mnemonic(tcc_names[COND]); + if (m_version >= 9) + { + const char *const cc(cc_names[TCCCC]); + if (!cc) return dasm_invalid(buf, pc, op); + print(buf, "%-*s%s,", m_op_field_width, mnemonic, cc); + } + else + { + print(buf, "%-*s", m_op_field_width, mnemonic); + } + if (USEIMM) + { + if (RS1 == 0) print(buf, "%d", IMM7); + else print(buf, "%s,%d", REG_NAMES[RS1], IMM7); + } + else + { + if (RS1 == 0) print(buf, "%s", REG_NAMES[RS2]); + else if (RS2 == 0) print(buf, "%s", REG_NAMES[RS1]); + else print(buf, "%s,%s", REG_NAMES[RS1], REG_NAMES[RS2]); + } + return 4 | DASMFLAG_SUPPORTED; +} + + +offs_t sparc_disassembler::dasm_ldst(char *buf, offs_t pc, UINT32 op) const +{ + if (m_version >= 9) + { + switch (OP3) + { + case 0x21: // Load floating-point state register + if ((RD == 0) || (RD == 1)) + { + print(buf, "%-*s[", m_op_field_width, (RD == 1) ? "ldx" : "ld"); + dasm_address(buf, op); + print(buf, "],%%fsr"); + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x25: // Store floating-point state register + if ((RD == 0) || (RD == 1)) + { + print(buf, "%-*s%%fsr,[", m_op_field_width, (RD == 1) ? "stx" : "st"); + dasm_address(buf, op); + *buf++ = ']'; + return 4 | DASMFLAG_SUPPORTED; + } + break; + case 0x3c: // Compare and swap word in alternate space + case 0x3e: // Compare and swap doubleword in alternate space + { + bool print_asi(true); + const char *mnemonic((OP3 == 0x3e) ? "casxa" : "casa"); + if (!USEIMM) + { + if (ASI == 0x80) + { + print_asi = false; + mnemonic = (OP3 == 0x3e) ? "casx" : "cas"; + } + else if (ASI == 0x88) + { + print_asi = false; + mnemonic = (OP3 == 0x3e) ? "casxl" : "casl"; + } + } + print(buf, "%-*s[%s]", m_op_field_width, mnemonic, REG_NAMES[RS1]); + if (print_asi) dasm_asi(buf, op); + print(buf, ",%s,%s", REG_NAMES[RS2], REG_NAMES[RD]); + if (print_asi) dasm_asi_comment(buf, op); + } + return 4 | DASMFLAG_SUPPORTED; + case 0x2d: // Prefetch data + case 0x3d: // Prefetch data from alternate space + { + print(buf, "%-*s[", m_op_field_width, (OP3 == 0x3d) ? "prefetcha" : "prefetch"); + dasm_address(buf, op); + *buf++ = ']'; + if (OP3 == 0x3d) dasm_asi(buf, op); + const auto it(m_prftch_desc.find(RD)); + if (it != m_prftch_desc.end()) print(buf, ",%s", it->second.name); + else print(buf, ",0x%02x", RD); + if (OP3 == 0x3d) dasm_asi_comment(buf, op); + } + return 4 | DASMFLAG_SUPPORTED; + } + } + else + { + switch (OP3) + { + case 0x21: // Load Floating-point State Register + case 0x31: // Load Coprocessor State Register + print(buf, "%-*s[", m_op_field_width, "ld"); + dasm_address(buf, op); + print(buf, "],%%%csr", (OP3 == 0x31) ? 'c' : 'f'); + return 4 | DASMFLAG_SUPPORTED; + case 0x25: // Store Floating-point State Register + case 0x35: // Store Coprocessor State Register + print(buf, "%-*s%%%csr,[", m_op_field_width, "st", (OP3 == 0x35) ? 'c' : 'f'); + dasm_address(buf, op); + *buf++ = ']'; + return 4 | DASMFLAG_SUPPORTED; + case 0x26: // Store Floating-point deferred-trap Queue + case 0x36: // Store Coprocessor deferred-trap Queue + print(buf, "%-*s%%%cq,[", m_op_field_width, "std", (OP3 == 0x36) ? 'c' : 'f'); + dasm_address(buf, op); + *buf++ = ']'; + return 4 | DASMFLAG_SUPPORTED; + } + } + + const auto it(m_ldst_desc.find(OP3)); + if (it == m_ldst_desc.end()) + return dasm_invalid(buf, pc, op); + + if (it->second.alternate && USEIMM && (m_version < 9)) + return dasm_invalid(buf, pc, op); + + if (it->second.g0_synth && (RD == 0)) + { + print(buf, "%-*s[", m_op_field_width, it->second.g0_synth); + dasm_address(buf, op); + *buf++ = ']'; + if (it->second.alternate) + { + dasm_asi(buf, op); + dasm_asi_comment(buf, op); + } + } + else + { + print(buf, "%-*s", m_op_field_width, it->second.mnemonic); + if (it->second.rd_first) + { + if (it->second.rd_alt_reg) print(buf, "%%%c%d,", it->second.rd_alt_reg, freg(RD, it->second.rd_shift)); + else print(buf, "%s,", REG_NAMES[RD]); + } + *buf++ = '['; + dasm_address(buf, op); + *buf++ = ']'; + if (it->second.alternate) dasm_asi(buf, op); + if (!it->second.rd_first) + { + if (it->second.rd_alt_reg) print(buf, ",%%%c%d", it->second.rd_alt_reg, freg(RD, it->second.rd_shift)); + else print(buf, ",%s", REG_NAMES[RD]); + } + if (it->second.alternate) dasm_asi_comment(buf, op); + } + return 4 | DASMFLAG_SUPPORTED; +} + + +void sparc_disassembler::dasm_address(char *&output, UINT32 op) const +{ + if (USEIMM) + { + if (RS1 == 0) print(output, "0x%08x", SIMM13); + else print(output, "%s%c0x%04x", REG_NAMES[RS1], (SIMM13 < 0) ? '-' : '+', std::abs(SIMM13)); + } + else + { + if (RS1 == 0) print(output, "%s", REG_NAMES[RS2]); + else if (RS2 == 0) print(output, "%s", REG_NAMES[RS1]); + else print(output, "%s+%s", REG_NAMES[RS1], REG_NAMES[RS2]); + } +} + + +void sparc_disassembler::dasm_asi(char *&output, UINT32 op) const +{ + if (USEIMM) + { + print(output, "%%asi"); + } + else + { + const auto it(m_asi_desc.find(ASI)); + if ((it != m_asi_desc.end()) && it->second.name) + print(output, "%s", it->second.name); + else + print(output, "0x%02x", ASI); + } +} + + +void sparc_disassembler::dasm_asi_comment(char *&output, UINT32 op) const +{ + if (!USEIMM) + { + const auto it(m_asi_desc.find(ASI)); + if ((it != m_asi_desc.end()) && it->second.desc) + print(output, " ! %s", it->second.desc); + } +} + + +CPU_DISASSEMBLE( sparcv7 ) +{ + UINT32 op = *reinterpret_cast(oprom); + return DASM_V7.dasm(buffer, pc, BIG_ENDIANIZE_INT32(op)); +} + +CPU_DISASSEMBLE( sparcv8 ) +{ + UINT32 op = *reinterpret_cast(oprom); + return DASM_V8.dasm(buffer, pc, BIG_ENDIANIZE_INT32(op)); +} + +CPU_DISASSEMBLE( sparcv9 ) +{ + UINT32 op = *reinterpret_cast(oprom); + return DASM_V9.dasm(buffer, pc, BIG_ENDIANIZE_INT32(op)); } diff --git a/src/devices/cpu/sparc/sparcdasm.h b/src/devices/cpu/sparc/sparcdasm.h new file mode 100644 index 00000000000..e745de4721d --- /dev/null +++ b/src/devices/cpu/sparc/sparcdasm.h @@ -0,0 +1,201 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz, Vas Crabb +/* + SPARC disassembler +*/ + +#ifndef MAME_DEVICES_CPU_SPARC_SPARC_DASM_H +#define MAME_DEVICES_CPU_SPARC_SPARC_DASM_H + +#pragma once + +#include + + +class sparc_disassembler +{ +public: + struct asi_desc + { + const char *name = nullptr; + const char *desc = nullptr; + }; + typedef std::map asi_desc_map; + + struct state_reg_desc + { + bool reserved = false; + const char *read_name = nullptr; + const char *write_name = nullptr; + }; + typedef std::map state_reg_desc_map; + + struct prftch_desc + { + const char *name = nullptr; + }; + typedef std::map prftch_desc_map; + + sparc_disassembler(unsigned version); + + template void add_state_reg_desc(const T &desc) + { + for (const auto &it : desc) + { + auto ins = m_state_reg_desc.insert(it); + if (!ins.second) + { + ins.first->second.reserved = it.second.reserved; + if (it.second.read_name) + ins.first->second.read_name = it.second.read_name; + if (it.second.write_name) + ins.first->second.write_name = it.second.write_name; + } + } + } + + template void add_asi_desc(const T &desc) + { + // TODO: support ranges + for (const auto &it : desc) + { + auto ins = m_asi_desc.insert(it); + if (!ins.second) + { + if (it.second.name) + ins.first->second.name = it.second.name; + if (it.second.desc) + ins.first->second.desc = it.second.desc; + } + } + } + + template void add_prftch_desc(const T &desc) + { + for (const auto &it : desc) + { + auto ins = m_prftch_desc.insert(it); + if (!ins.second) + { + if (it.second.name) + ins.first->second.name = it.second.name; + } + } + } + + offs_t dasm(char *buf, offs_t pc, UINT32 op) const; + +private: + struct branch_desc + { + INT32 (*get_disp)(UINT32 op); + int disp_width; + bool use_pred, use_cc; + const char *reg_cc[4]; + const char *mnemonic[16]; + }; + + struct int_op_desc + { + unsigned min_version; + bool hex_imm; + const char *mnemonic; + }; + typedef std::map int_op_desc_map; + + struct fpop1_desc + { + bool three_op = true; + bool rs1_shift = false; + bool rs2_shift = false; + bool rd_shift = false; + const char *mnemonic = nullptr; + }; + typedef std::map fpop1_desc_map; + + struct fpop2_desc + { + bool int_rs1 = false; + bool shift = false; + const char *mnemonic = nullptr; + }; + typedef std::map fpop2_desc_map; + + struct ldst_desc + { + bool rd_first = false; + bool alternate = false; + char rd_alt_reg = '\0'; + bool rd_shift = false; + const char *mnemonic = nullptr; + const char *g0_synth = nullptr; + }; + typedef std::map ldst_desc_map; + + offs_t dasm_invalid(char *buf, offs_t pc, UINT32 op) const; + offs_t dasm_branch(char *buf, offs_t pc, UINT32 op) const; + offs_t dasm_shift(char *buf, offs_t pc, UINT32 op, const char *mnemonic, const char *mnemonicx, const char *mnemonicx0) const; + offs_t dasm_read_state_reg(char *buf, offs_t pc, UINT32 op) const; + offs_t dasm_write_state_reg(char *buf, offs_t pc, UINT32 op) const; + offs_t dasm_move_cond(char *buf, offs_t pc, UINT32 op) const; + offs_t dasm_move_reg_cond(char *buf, offs_t pc, UINT32 op) const; + offs_t dasm_fpop1(char *buf, offs_t pc, UINT32 op) const; + offs_t dasm_fpop2(char *buf, offs_t pc, UINT32 op) const; + offs_t dasm_jmpl(char *buf, offs_t pc, UINT32 op) const; + offs_t dasm_return(char *buf, offs_t pc, UINT32 op) const; + offs_t dasm_tcc(char *buf, offs_t pc, UINT32 op) const; + offs_t dasm_ldst(char *buf, offs_t pc, UINT32 op) const; + + void dasm_address(char *&output, UINT32 op) const; + void dasm_asi(char *&output, UINT32 op) const; + void dasm_asi_comment(char *&output, UINT32 op) const; + + UINT32 freg(UINT32 val, bool shift) const; + + template void add_fpop1_desc(const T &desc); + template void add_fpop2_desc(const T &desc); + template void add_ldst_desc(const T &desc); + + void pad_op_field(char *buf, char *&output) const; + ATTR_PRINTF(2, 3) static void print(char *&output, const char *fmt, ...); + + static const char * const REG_NAMES[32]; + static const branch_desc EMPTY_BRANCH_DESC; + static const branch_desc BPCC_DESC; + static const branch_desc BICC_DESC; + static const branch_desc BPR_DESC; + static const branch_desc FBPFCC_DESC; + static const branch_desc FBFCC_DESC; + static const branch_desc CBCCC_DESC; + static const int_op_desc_map::value_type SIMPLE_INT_OP_DESC[]; + static const state_reg_desc_map::value_type V9_STATE_REG_DESC[]; + static const char * const MOVCC_CC_NAMES[8]; + static const char * const MOVCC_COND_NAMES[32]; + static const char * const MOVE_INT_COND_MNEMONICS[8]; + static const char * const V9_PRIV_REG_NAMES[32]; + static const fpop1_desc_map::value_type V7_FPOP1_DESC[]; + static const fpop1_desc_map::value_type V9_FPOP1_DESC[]; + static const fpop2_desc_map::value_type V7_FPOP2_DESC[]; + static const fpop2_desc_map::value_type V9_FPOP2_DESC[]; + static const ldst_desc_map::value_type V7_LDST_DESC[]; + static const ldst_desc_map::value_type V9_LDST_DESC[]; + static const asi_desc_map::value_type V9_ASI_DESC[]; + static const prftch_desc_map::value_type V9_PRFTCH_DESC[]; + + unsigned m_version; + int m_op_field_width; + branch_desc m_branch_desc[8]; + int_op_desc_map m_simple_int_op_desc; + state_reg_desc_map m_state_reg_desc; + fpop1_desc_map m_fpop1_desc; + fpop2_desc_map m_fpop2_desc; + ldst_desc_map m_ldst_desc; + asi_desc_map m_asi_desc; + prftch_desc_map m_prftch_desc; +}; + +CPU_DISASSEMBLE( sparcv7 ); +CPU_DISASSEMBLE( sparcv8 ); +CPU_DISASSEMBLE( sparcv9 ); + +#endif // MAME_DEVICES_CPU_SPARC_SPARC_DASM_H diff --git a/src/devices/cpu/sparc/sparcdefs.h b/src/devices/cpu/sparc/sparcdefs.h index 185845c1d4f..2d988c5605c 100644 --- a/src/devices/cpu/sparc/sparcdefs.h +++ b/src/devices/cpu/sparc/sparcdefs.h @@ -83,20 +83,39 @@ #define OP2 ((op >> 22) & 7) #define OP3 ((op >> 19) & 63) #define OPF ((op >> 5) & 0x1ff) +#define OPC ((op >> 5) & 0x1ff) +#define OPFLOW ((op >> 5) & 0x3f) -#define DISP30 (op << 2) -#define DISP22 (((INT32)(op << 10)) >> 8) +#define DISP30 (INT32(op << 2)) +#define DISP22 (INT32(op << 10) >> 8) +#define DISP19 (INT32(op << 13) >> 11) +#define DISP16 (INT32(((op << 10) & 0xc0000000) | ((op << 16) & 0x3fff0000)) >> 14) #define IMM22 (op << 10) #define CONST22 (op & 0x3fffff) -#define SIMM13 (((INT32)(op << 19)) >> 19) +#define SIMM13 (INT32(op << 19) >> 19) +#define SIMM11 (INT32(op << 21) >> 21) +#define SIMM10 (INT32(op << 22) >> 22) #define IMM7 (op & 0x7f) -#define SIMM7 (((INT32)(op << 25)) >> 25) -#define OPIMM (op & 0x00002000) +#define SIMM7 (INT32(op << 25) >> 25) +#define SIMM8 (INT32(op << 24) >> 24) +#define SHCNT32 (op & 31) +#define SHCNT64 (op & 63) #define USEIMM ((op >> 13) & 1) +#define USEEXT ((op >> 12) & 1) + #define COND ((op >> 25) & 15) +#define RCOND ((op >> 10) & 7) +#define MOVCOND ((op >> 14) & 15) +#define PRED ((op >> 19) & 1) #define ANNUL ((op >> 29) & 1) -#define ASI ((op >> 5) & 0xff) +#define BRCC ((op >> 20) & 3) +#define MOVCC (((op >> 11) & 3) | ((op >> 16) & 4)) +#define OPFCC ((op >> 11) & 7) +#define TCCCC ((op >> 11) & 3) +#define ASI ((op >> 5) & 255) +#define MMASK (op & 15) +#define CMASK ((op >> 4) & 7) #define RD ((op >> 25) & 31) #define RS1 ((op >> 14) & 31) @@ -107,7 +126,7 @@ #define RS1REG *m_regs[RS1] #define RS2REG *m_regs[RS2] #define SET_RDREG(x) if(RD) { RDREG = x; } -#define ADDRESS (OPIMM ? (RS1REG + SIMM13) : (RS1REG + RS2REG)) +#define ADDRESS (USEIMM ? (RS1REG + SIMM13) : (RS1REG + RS2REG)) #define PC m_pc #define nPC m_npc