diff options
Diffstat (limited to 'src/devices/cpu/sigma2/sigma2d.cpp')
-rw-r--r-- | src/devices/cpu/sigma2/sigma2d.cpp | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/src/devices/cpu/sigma2/sigma2d.cpp b/src/devices/cpu/sigma2/sigma2d.cpp new file mode 100644 index 00000000000..6acc7f2ea68 --- /dev/null +++ b/src/devices/cpu/sigma2/sigma2d.cpp @@ -0,0 +1,393 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + SDS/XDS Sigma 2/3 & Xerox 530 (16-bit) disassemblers + +***************************************************************************/ + +#include "emu.h" +#include "sigma2d.h" + +namespace { + +const char *const s_inst_names[16] = +{ + "WD", "RD", + "S", "MUL", + "B", "DIV", + "BC", "COPY", // non-memory instructions + "LDA", "AND", + "ADD", "SUB", + "LDX", "CP", + "STA", "IM" +}; + +const char *const s_shift_names[8] = +{ + "SARS", "SALS", "SCRS", "SCLS", // Single shifts + "SARD", "SALD", "SCRD", "SCLD" // Double shifts +}; + +const char *const s_bc_names[8] = +{ + "BNO", "BNC", "BAZ", "BIX", + "BXNO", "BXNC", "BEN", "BAN" +}; + +const char *const s_copy_names[32] = +{ + "RAND", "", "RANDI", "", "RANDC", "", "", "", + "ROR", "RCPY", "RORI", "RCPYI", "RORC", "RCPYC", "", "", + "REOR", "", "REORI", "", "REORC", "", "", "", + "RADD", "RCLA", "RADDI", "RCLAI", "RADDC", "RCLAC", "", "" +}; + +const char *const s_sigma2_reg_names[8] = +{ + "Z", "P", + "L", "T", + "X1", "X2", + "E", "A" +}; + +const char *const s_xerox530_reg_names[8] = +{ + "Z", "P", + "L", "T", + "X", "B", + "E", "A" +}; + +} // anonymous namespace + +sigma2_disassembler::sigma2_disassembler(const char *const *reg_names) + : util::disasm_interface() + , m_reg_names(reg_names) +{ +} + +sigma2_disassembler::sigma2_disassembler() + : sigma2_disassembler(s_sigma2_reg_names) +{ +} + +xerox530_disassembler::xerox530_disassembler() + : sigma2_disassembler(s_xerox530_reg_names) +{ +} + +u32 sigma2_disassembler::opcode_alignment() const +{ + return 1; +} + +offs_t sigma2_disassembler::dasm_memory_reference(std::ostream &stream, offs_t pc, const data_buffer &opcodes, u16 inst) const +{ + if (BIT(inst, 10)) + { + // Indirect addressing + stream << '*'; + } + if (BIT(inst, 11)) + { + // Self-relative addressing + util::stream_format(stream, "X'%04X'", (pc + util::sext(inst, 9)) & 0xffff); + if (BIT(inst, 9)) + stream << ',' << m_reg_names[4]; + } + else if (BIT(inst, 8, 2) == 0 || BIT(inst, 8, 3) == 6) + { + // Nonrelative direct addressing + util::stream_format(stream, "X'%04X'", inst & 0x00ff); + if (BIT(inst, 9)) + stream << ',' << m_reg_names[4]; + + // Interrupt exit sequence (very special case in which LDX loads PSD and not X1) + if (inst == 0x00d8 && (opcodes.r16(pc + 1) & 0xf000) == 0xc000) + return 1 | STEP_OUT | step_over_extra(1) | SUPPORTED; + } + else + { + // Indexed addressing + if ((inst & 0x00ff) <= 9) + util::stream_format(stream, "%d,", inst & 0x00ff); + else + util::stream_format(stream, "X'%X',", inst & 0x00ff); + if (BIT(inst, 9)) + stream << m_reg_names[4]; + if (BIT(inst, 8)) + stream << ',' << m_reg_names[5]; + } + + return 1 | SUPPORTED; +} + +offs_t sigma2_disassembler::dasm_read_direct(std::ostream &stream, offs_t pc, const data_buffer &opcodes, u16 inst) const +{ + // RD internal control functions + if (inst == 0x1041) + { + stream << "SIO"; + return 1 | SUPPORTED; + } + else if (inst == 0x1042) + { + stream << "TIO"; + return 1 | SUPPORTED; + } + else if (inst == 0x1044) + { + stream << "TDV"; + return 1 | SUPPORTED; + } + else if (inst == 0x1048) + { + stream << "HIO"; + return 1 | SUPPORTED; + } + else if (inst == 0x1050) + { + stream << "AIO"; + return 1 | SUPPORTED; + } + else if (inst > 0x1080 && inst <= 0x10bf) + { + // Multiple precision mode prefix + util::stream_format(stream, "%-8s%s,%d", "SMP", m_reg_names[BIT(inst, 0, 3)], BIT(inst, 3, 3)); + return 1 | SUPPORTED; + } + else + { + // Fall back to disassembling RD using RIXS modes + util::stream_format(stream, "%-8s", "RD"); + return dasm_memory_reference(stream, pc, opcodes, inst); + } +} + +offs_t xerox530_disassembler::dasm_read_direct(std::ostream &stream, offs_t pc, const data_buffer &opcodes, u16 inst) const +{ + // RD internal control functions + if (inst == 0x1041) + { + stream << "SIO"; + return 1 | SUPPORTED; + } + else if (inst == 0x1042) + { + stream << "TIO"; + return 1 | SUPPORTED; + } + else if (inst == 0x1044) + { + stream << "TDV"; + return 1 | SUPPORTED; + } + else if (inst == 0x1048) + { + stream << "HIO"; + return 1 | SUPPORTED; + } + else if (inst == 0x1050) + { + stream << "AIO"; + return 1 | SUPPORTED; + } + else if (inst >= 0x108a && inst <= 0x108e) + { + // General register instructions + u16 inst2 = opcodes.r16(pc + 1); + switch (BIT(inst2, 12, 4)) + { + case 8: + util::stream_format(stream, "LW,%-5s", m_reg_names[BIT(inst, 0, 3)]); + break; + + case 9: + util::stream_format(stream, "AND,%-4s", m_reg_names[BIT(inst, 0, 3)]); + break; + + case 0xa: + util::stream_format(stream, "AW,%-5s", m_reg_names[BIT(inst, 0, 3)]); + break; + + case 0xb: + util::stream_format(stream, "SW,%-5s", m_reg_names[BIT(inst, 0, 3)]); + break; + + case 0xd: + util::stream_format(stream, "CW,%-5s", m_reg_names[BIT(inst, 0, 3)]); + break; + + case 0xe: + util::stream_format(stream, "STW,%-4s", m_reg_names[BIT(inst, 0, 3)]); + break; + + default: + util::stream_format(stream, "%-8sX'%04X'", "DATA", inst); + return 1 | SUPPORTED; + } + return 1 + dasm_memory_reference(stream, pc + 1, opcodes, inst2); + } + else if (inst == 0x109e) + { + // Floating mode: LDA, STA, ADD, SUB, MUL, DIV, CP executed as FLD, FST, FAD, FSB, FML, FDV, FCP until next branch + stream << "SFM"; + return 1 | SUPPORTED; + } + else if (inst >= 0x1088 && inst <= 0x10bf) + { + u16 inst2 = opcodes.r16(pc + 1); + if (BIT(inst, 0, 3) <= 1 || BIT(inst, 0, 3) == 7) + { + // Field addressing instructions + switch (BIT(inst2, 12, 4)) + { + case 5: + stream << "CLF"; + break; + + case 8: + stream << "LLF"; + break; + + case 9: + stream << "LAF"; + break; + + case 0xa: + stream << "STF"; + break; + + case 0xb: + stream << "SZF"; + break; + + case 0xc: + stream << "SOF"; + break; + + case 0xd: + stream << "CAF"; + break; + + case 0xf: + stream << "SLF"; + break; + + default: + util::stream_format(stream, "%-8sX'%04X'", "DATA", inst); + return 1 | SUPPORTED; + } + util::stream_format(stream, ",%s,%d ", BIT(inst, 3, 3) == 1 ? "0" : m_reg_names[BIT(inst, 3, 3)], util::sext(inst, 3)); + return 1 + dasm_memory_reference(stream, pc + 1, opcodes, inst2); + } + else if (inst == 0x1096) + { + // Double-register instructions + switch (BIT(inst2, 12, 4)) + { + case 8: + util::stream_format(stream, "%-8s", "LDD"); + break; + + case 0xa: + util::stream_format(stream, "%-8s", "DAD"); + break; + + case 0xb: + util::stream_format(stream, "%-8s", "DSB"); + break; + + case 0xd: + util::stream_format(stream, "%-8s", "CPD"); + break; + + case 0xe: + util::stream_format(stream, "%-8s", "STD"); + break; + + default: + util::stream_format(stream, "%-8sX'%04X'", "DATA", inst); + return 1 | SUPPORTED; + } + return 1 + dasm_memory_reference(stream, pc + 1, opcodes, inst2); + } + else if (BIT(inst, 3, 3) + BIT(inst, 0, 3) <= 8 && (BIT(inst2, 12, 4) == 8 || BIT(inst2, 12, 4) == 0xe)) + { + // Multiple-register load and store instructions + util::stream_format(stream, "%-8s", inst2 >= 0xe000 ? "STM" : "LDM"); + offs_t result = 1 + dasm_memory_reference(stream, pc + 1, opcodes, inst2); + util::stream_format(stream, ",%s,%d", m_reg_names[BIT(inst, 0, 3)], BIT(inst, 3, 3)); + return result; + } + else + { + util::stream_format(stream, "%-8sX'%04X'", "DATA", inst); + return 1 | SUPPORTED; + } + } + else + { + // Fall back to disassembling RD using RIXS modes + util::stream_format(stream, "%-8s", "RD"); + return dasm_memory_reference(stream, pc, opcodes, inst); + } +} + +offs_t sigma2_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) +{ + u16 inst = opcodes.r16(pc); + if ((inst & 0xf000) == 0x6000) + { + // Conditional branch instructions use self-relative addressing only + util::stream_format(stream, "%-8sX'%04X'", s_bc_names[BIT(inst, 9, 3)], (pc + util::sext(inst, 9)) & 0xffff); + return 1 | STEP_COND | SUPPORTED; + } + else if ((inst & 0xf000) == 0x7000) + { + // Copy instructions + const char *name = s_copy_names[BIT(inst, 7, 5)]; + if (name[0] != '\0') + { + util::stream_format(stream, "%-8s", name); + + // Optionally invert source + if (BIT(inst, 3)) + stream << '*'; + util::stream_format(stream, "%s,%s", m_reg_names[BIT(inst, 0, 3)], m_reg_names[BIT(inst, 4, 3)]); + + // Recognize branch-and-link calling convention + if (inst == 0x75a1 && (opcodes.r16(pc + 1) & 0xf000) == 0x4000) + return 1 | STEP_OVER | step_over_extra(1) | SUPPORTED; + else if ((inst & 0xfcff) == 0x7492) + return 1 | STEP_OUT | SUPPORTED; + } + else + util::stream_format(stream, "%-8sX'%04X'", "DATA", inst); + return 1 | SUPPORTED; + } + else if ((inst & 0xfc00) == 0x2000) + { + // Shift instructions + util::stream_format(stream, "%-8s%d", s_shift_names[BIT(inst, 5, 3)], BIT(inst, 0, 5)); + if (BIT(inst, 8, 2) != 0) + { + // Shift count may be indexed + stream << ','; + if (BIT(inst, 9)) + stream << m_reg_names[4]; + if (BIT(inst, 8)) + stream << ',' << m_reg_names[5]; + } + return 1 | SUPPORTED; + } + else if ((inst & 0xf000) == 0x1000) + return dasm_read_direct(stream, pc, opcodes, inst); + else + { + // Memory reference instructions (RIXS) + util::stream_format(stream, "%-8s", s_inst_names[BIT(inst, 12, 4)]); + return dasm_memory_reference(stream, pc, opcodes, inst); + } +} |