diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index cc9e80987c3..a91e36ab0c6 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -3125,6 +3125,16 @@ if opt_tool(CPUS, "ALPHA") then table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/alpha/alphad.h") end +-------------------------------------------------- +-- Hewlett-Packard HP2100 (disassembler only) +--@src/devices/cpu/hp2100/hp2100.h,CPUS["HP2100"] = true +-------------------------------------------------- + +if opt_tool(CPUS, "HP2100") then + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/hp2100/hp2100d.cpp") + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/hp2100/hp2100d.h") +end + -------------------------------------------------- -- National Semiconductor HPC --@src/devices/cpu/hpc/hpc.h,CPUS["HPC"] = true @@ -3580,3 +3590,12 @@ if opt_tool(CPUS, "M68HC16") then table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/m68hc16/cpu16dasm.cpp") table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/m68hc16/cpu16dasm.h") end + +-------------------------------------------------- +-- Varian 620, disassembler only +-------------------------------------------------- + +if opt_tool(CPUS, "V620") then + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/v620/v620dasm.cpp") + table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/v620/v620dasm.h") +end diff --git a/src/devices/cpu/hp2100/hp2100d.cpp b/src/devices/cpu/hp2100/hp2100d.cpp new file mode 100644 index 00000000000..06463ea2b4a --- /dev/null +++ b/src/devices/cpu/hp2100/hp2100d.cpp @@ -0,0 +1,551 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Hewlett-Packard HP2100 disassembler + +***************************************************************************/ + +#include "emu.h" +#include "hp2100d.h" + +hp2100_disassembler::hp2100_disassembler() + : util::disasm_interface() +{ +} + +u32 hp2100_disassembler::opcode_alignment() const +{ + return 1; +} + +void hp2100_disassembler::format_address(std::ostream &stream, u16 addr) const +{ + if ((addr & 077776) == 0) + stream << char('A' + BIT(addr, 0)); + else + util::stream_format(stream, "%05oB", addr & 077777); + + // Indirect addressing? + if (BIT(addr, 15)) + stream << ",I"; +} + +void hp2100_disassembler::format_sc(std::ostream &stream, u8 sc) const +{ + util::stream_format(stream, "%o", sc); + if (sc > 7) + stream << 'B'; +} + +// Memory reference group +offs_t hp2100_disassembler::dasm_mrg(std::ostream &stream, u16 inst, offs_t pc) const +{ + offs_t flags = SUPPORTED; + switch (BIT(inst, 12, 3)) + { + case 1: + if (BIT(inst, 11)) + { + stream << "JSB "; + flags |= STEP_OVER; + } + else + stream << "AND "; + break; + + case 2: + if (BIT(inst, 11)) + { + stream << "JMP "; + if (BIT(inst, 15)) + flags |= STEP_OUT; + } + else + stream << "XOR "; + break; + + case 3: + if (BIT(inst, 11)) + { + stream << "ISZ "; + flags |= STEP_COND; + } + else + stream << "IOR "; + break; + + case 4: + util::stream_format(stream, "AD%c ", cab(inst)); + break; + + case 5: + util::stream_format(stream, "CP%c ", cab(inst)); + flags |= STEP_COND; + break; + + case 6: + util::stream_format(stream, "LD%c ", cab(inst)); + break; + + case 7: + util::stream_format(stream, "ST%c ", cab(inst)); + break; + } + + // Page zero or current page + format_address(stream, (BIT(inst, 10) ? (pc & 077600) : 0) | (inst & 0100177)); + + return 1 | flags; +} + +const char *const hp2100_disassembler::s_shift_ops[2][8] = +{ + { "ALS", "ARS", "RAR", "RAL", "ALR", "ERA", "ELA", "ALF" }, + { "BLS", "BRS", "RBR", "RBL", "BLR", "ERB", "ELB", "BLF" } +}; + +// Shift-rotate group +offs_t hp2100_disassembler::dasm_srg(std::ostream &stream, u16 inst) const +{ + offs_t flags = SUPPORTED; + + if ((inst & 001070) == 0) + { + if (inst == 0) + stream << "NOP"; + else + util::stream_format(stream, "OCT %o", inst); + } + else + { + if (BIT(inst, 9)) + stream << s_shift_ops[BIT(inst, 11)][BIT(inst, 6, 3)]; + + if (BIT(inst, 5)) + { + if (BIT(inst, 9)) + stream << ','; + stream << "CLE"; + } + + // Skip on LSB + if (BIT(inst, 3)) + { + if ((inst & 001040) != 0) + stream << ','; + util::stream_format(stream, "SL%c", cab(inst)); + flags |= STEP_COND; + } + + if (BIT(inst, 4)) + { + if ((inst & 001050) != 0) + stream << ','; + stream << s_shift_ops[BIT(inst, 11)][BIT(inst, 0, 3)]; + } + } + + return 1 | flags; +} + +// Alter-skip group +offs_t hp2100_disassembler::dasm_asg(std::ostream &stream, u16 inst) const +{ + offs_t flags = SUPPORTED; + + if ((inst & 01777) == 0) + util::stream_format(stream, "OCT %o", inst); + else + { + if (BIT(inst, 8, 2) != 0) + util::stream_format(stream, "C%c%c", "LMC"[BIT(inst, 8, 2) - 1], cab(inst)); + + // Extend skip + if (BIT(inst, 5)) + { + if (BIT(inst, 8, 2) != 0) + stream << ','; + stream << "SEZ"; + flags |= STEP_COND; + } + + if (BIT(inst, 6, 2) != 0) + { + if ((inst & 01440) != 0) + stream << ','; + util::stream_format(stream, "C%cE", "LMC"[BIT(inst, 6, 2) - 1]); + } + + // Accumulator skips + if (BIT(inst, 4)) + { + if ((inst & 01740) != 0) + stream << ','; + util::stream_format(stream, "SS%c", cab(inst)); + flags |= STEP_COND; + } + if (BIT(inst, 3)) + { + if ((inst & 01760) != 0) + stream << ','; + util::stream_format(stream, "SL%c", cab(inst)); + flags |= STEP_COND; + } + if (BIT(inst, 2)) + { + if ((inst & 01770) != 0) + stream << ','; + util::stream_format(stream, "IN%c", cab(inst)); + flags |= STEP_COND; + } + if (BIT(inst, 1)) + { + if ((inst & 01774) != 0) + stream << ','; + util::stream_format(stream, "SZ%c", cab(inst)); + flags |= STEP_COND; + } + + // Reverse skip sense + if (BIT(inst, 0)) + { + if ((inst & 01776) != 0) + stream << ','; + stream << "RSS"; + } + } + + return 1 | flags; +} + +// Input-output group +offs_t hp2100_disassembler::dasm_iog(std::ostream &stream, u16 inst) const +{ + u8 sc = BIT(inst, 0, 6); + offs_t flags = SUPPORTED; + + switch (BIT(inst, 6, 3)) + { + case 0: + stream << "HLT"; + if (sc != 0) + { + stream << ' '; + format_sc(stream, sc); + } + break; + + case 1: + if (sc == 1) + { + // Clear or set overflow flag + if (BIT(inst, 9)) + stream << "CLO"; + else + stream << "STO"; + } + else + { + if (BIT(inst, 9)) + stream << "CLF "; + else + stream << "STF "; + format_sc(stream, sc); + } + break; + + case 2: + if (sc == 1) + stream << "SOC"; + else + { + stream << "SFC "; + format_sc(stream, sc); + } + flags |= STEP_COND; + break; + + case 3: + if (sc == 1) + stream << "SOS"; + else + { + stream << "SFS "; + format_sc(stream, sc); + } + flags |= STEP_COND; + break; + + case 4: + util::stream_format(stream, "MI%c ", cab(inst)); + format_sc(stream, sc); + break; + + case 5: + util::stream_format(stream, "LI%c ", cab(inst)); + format_sc(stream, sc); + break; + + case 6: + util::stream_format(stream, "OT%c ", cab(inst)); + format_sc(stream, sc); + break; + + case 7: + if (BIT(inst, 11)) + stream << "CLC "; + else + stream << "STC "; + format_sc(stream, sc); + break; + } + + // Clear flag + if (BIT(inst, 9) && BIT(inst, 6, 3) != 1) + stream << ",C"; + + return 1 | flags; +} + +// Macro instructions (including extended arithmetic group and 12901A floating-point instructions) +offs_t hp2100_disassembler::dasm_mac(std::ostream &stream, u16 inst, offs_t pc, const hp2100_disassembler::data_buffer &opcodes) const +{ + switch (inst & 05760) + { + case 00020: case 01020: + { + u8 n = BIT(inst, 0, 4); + util::stream_format(stream, "AS%c %d", BIT(inst, 9) ? 'R' : 'L', n == 0 ? 16 : n); + return 1 | SUPPORTED; + } + + case 00040: case 01040: + { + u8 n = BIT(inst, 0, 4); + util::stream_format(stream, "LS%c %d", BIT(inst, 9) ? 'R' : 'L', n == 0 ? 16 : n); + return 1 | SUPPORTED; + } + + case 00100: case 01100: + { + u8 n = BIT(inst, 0, 4); + util::stream_format(stream, "RR%c %d", BIT(inst, 9) ? 'R' : 'L', n == 0 ? 16 : n); + return 1 | SUPPORTED; + } + + case 00200: + stream << "MPY "; + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 00400: + stream << "DIV "; + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 04000: + stream << "DLD "; + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 04400: + stream << "DST "; + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 05000: + stream << "FAD "; + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 05020: + stream << "FSB "; + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 05040: + stream << "FML "; + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 05060: + stream << "FDV "; + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 05100: + stream << "FIX"; + return 1 | SUPPORTED; + + case 05120: + stream << "FLT"; + return 1 | SUPPORTED; + + default: + util::stream_format(stream, "MAC %oB", inst & 05777); + return 1 | SUPPORTED; + } +} + +offs_t hp21mx_disassembler::dasm_mac(std::ostream &stream, u16 inst, offs_t pc, const hp2100_disassembler::data_buffer &opcodes) const +{ + if ((inst & 01740) == 01740) + { + // Extended instruction group + switch (inst & 04027) + { + case 0000: case 04000: + util::stream_format(stream, "S%c%c ", cab(inst), xy(inst)); + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 0001: case 04001: + util::stream_format(stream, "C%c%c", cab(inst), xy(inst)); + return 1 | SUPPORTED; + + case 0002: case 04002: + util::stream_format(stream, "L%c%c ", cab(inst), xy(inst)); + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 04003: + util::stream_format(stream, "ST%c ", xy(inst)); + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 0004: case 04004: + util::stream_format(stream, "C%c%c", xy(inst), cab(inst)); + return 1 | SUPPORTED; + + case 04005: + util::stream_format(stream, "LD%c ", xy(inst)); + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 04006: + util::stream_format(stream, "AD%c ", xy(inst)); + format_address(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + + case 0007: case 04007: + util::stream_format(stream, "X%c%c", cab(inst), xy(inst)); + return 1 | SUPPORTED; + + case 04020: + util::stream_format(stream, "IS%c", xy(inst)); + return 1 | STEP_COND | SUPPORTED; + + case 04021: + util::stream_format(stream, "DS%c", xy(inst)); + return 1 | STEP_COND | SUPPORTED; + + case 04022: + if (BIT(inst, 3)) + { + stream << "JPY "; + format_address(stream, opcodes.r16(pc + 1) & 077777); + } + else + { + stream << "JLY "; + format_address(stream, opcodes.r16(pc + 1)); + } + return 2 | SUPPORTED; + + case 04023: + if (BIT(inst, 3)) + { + stream << "SBS "; + format_address(stream, opcodes.r16(pc + 1)); + stream << ','; + format_address(stream, opcodes.r16(pc + 2)); + return 3 | SUPPORTED; + } + else + { + stream << "LBT"; + return 1 | SUPPORTED; + } + + case 04024: + if (BIT(inst, 3)) + { + stream << "CBS "; + format_address(stream, opcodes.r16(pc + 1)); + stream << ','; + format_address(stream, opcodes.r16(pc + 2)); + return 3 | STEP_COND | SUPPORTED; + } + else + { + stream << "SBT"; + return 1 | SUPPORTED; + } + + case 04025: + if (BIT(inst, 3)) + { + stream << "TBS "; + format_address(stream, opcodes.r16(pc + 1)); + stream << ','; + format_address(stream, opcodes.r16(pc + 2)); + return 3 | STEP_COND | SUPPORTED; + } + else + { + stream << "MBT "; + format_address(stream, opcodes.r16(pc + 1)); + return 3 | SUPPORTED; // one extra word reserved for microcode use + } + + case 04026: + if (BIT(inst, 3)) + stream << "CMW "; + else + stream << "CBT "; + format_address(stream, opcodes.r16(pc + 1)); + return 3 | STEP_COND | SUPPORTED; // one extra word reserved for microcode use + + case 04027: + if (BIT(inst, 3)) + { + stream << "MVW "; + format_address(stream, opcodes.r16(pc + 1)); + return 3 | SUPPORTED; // one extra word reserved for microcode use + } + else + { + stream << "SBT"; + return 1 | STEP_COND | SUPPORTED; + } + + default: + util::stream_format(stream, "MAC %oB", inst & 05777); + return 1 | SUPPORTED; + } + } + else + return hp2100_disassembler::dasm_mac(stream, inst, pc, opcodes); +} + +offs_t hp2100_disassembler::disassemble(std::ostream &stream, offs_t pc, const hp2100_disassembler::data_buffer &opcodes, const hp2100_disassembler::data_buffer ¶ms) +{ + u16 inst = opcodes.r16(pc); + if (BIT(inst, 12, 3) != 0) + return dasm_mrg(stream, inst, pc); + else if (BIT(inst, 15)) + { + if (BIT(inst, 10)) + return dasm_iog(stream, inst); + else + return dasm_mac(stream, inst, pc, opcodes); + } + else + { + if (BIT(inst, 10)) + return dasm_asg(stream, inst); + else + return dasm_srg(stream, inst); + } +} diff --git a/src/devices/cpu/hp2100/hp2100d.h b/src/devices/cpu/hp2100/hp2100d.h new file mode 100644 index 00000000000..78fd9596275 --- /dev/null +++ b/src/devices/cpu/hp2100/hp2100d.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_CPU_HP2100_HP2100D_H +#define MAME_CPU_HP2100_HP2100D_H + +#pragma once + +class hp2100_disassembler : public util::disasm_interface +{ +public: + // construction/destruction + hp2100_disassembler(); + +protected: + // disassembler overrides + virtual u32 opcode_alignment() const override; + virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + + static char cab(u16 inst) { return char('A' + BIT(inst, 11)); } + + void format_address(std::ostream &stream, u16 addr) const; + virtual offs_t dasm_mac(std::ostream &stream, u16 inst, offs_t pc, const data_buffer &opcodes) const; + +private: + // internal helpers + void format_sc(std::ostream &stream, u8 sc) const; + offs_t dasm_mrg(std::ostream &stream, u16 inst, offs_t pc) const; + offs_t dasm_asg(std::ostream &stream, u16 inst) const; + offs_t dasm_srg(std::ostream &stream, u16 inst) const; + offs_t dasm_iog(std::ostream &stream, u16 inst) const; + + // internal tables + static const char *const s_shift_ops[2][8]; +}; + +class hp21mx_disassembler : public hp2100_disassembler +{ +public: + // construction/destruction + using hp2100_disassembler::hp2100_disassembler; + +protected: + virtual offs_t dasm_mac(std::ostream &stream, u16 inst, offs_t pc, const data_buffer &opcodes) const override; + +private: + static char xy(u16 inst) { return char('X' + BIT(inst, 3)); } +}; + +#endif // MAME_CPU_HP2100_HP2100D_H diff --git a/src/devices/cpu/v620/v620dasm.cpp b/src/devices/cpu/v620/v620dasm.cpp new file mode 100644 index 00000000000..e050bb9463e --- /dev/null +++ b/src/devices/cpu/v620/v620dasm.cpp @@ -0,0 +1,589 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Varian (Data Machines) 620 series disassembler + +***************************************************************************/ + +#include "emu.h" +#include "v620dasm.h" + +#include +#include + +v620_disassembler::v620_disassembler() + : util::disasm_interface() +{ +} + +v75_disassembler::v75_disassembler() + : v620_disassembler() +{ +} + +u32 v620_disassembler::opcode_alignment() const +{ + return 1; +} + + +namespace { + +static const char *const s_alu_ops[16] = +{ + "000", "LDA", "LDB", "LDX", "INR", "STA", "STB", "STX", + "100", "ORA", "ADD", "ERA", "SUB", "ANA", "MUL", "DIV" +}; + +static const char *const s_shift_ops[4] = +{ + "ASL", "LRL", "ASR", "LSR" +}; + +static const char *const s_in_out_ops[12] = +{ + "IME", "INA", "INB", "INAB", + "024", "CIA", "CIB", "CIAB", + "OME", "OAR", "OBR", "OAB" +}; + +static const char *const s_index_tags[2] = +{ + ",X", ",B" +}; + +static const char *const s_reg_names[8] = +{ + "A", "B", "X", "R3", "R4", "R5", "R6", "R7" +}; + +static const char *const s_reg_mem_ops[4] = +{ + "LD", "ST", "AD", "SB" +}; + +static const char *const s_dp_ops[7] = +{ + "DLD", "DST", "DADD", "DSUB", "DAN", "DOR", "DER" +}; + +static const char *const s_reg_jumps[6] = +{ + "JZ", "JNZ", "JN", "JP", "JDZ", "JDNZ" +}; + +static const char *const s_single_reg_ops[3] = +{ + "INC", "DEC", "COM" +}; + +static const char *const s_rr_ops[3] = +{ + "ADR", "SBR", "T" +}; + +const std::unordered_map> s_cond_map = +{ + { 0000, { "JMP", "JMPM", "XEC" } }, // unconditional + { 0001, { "JOF", "JOFM", "XOF" } }, // overflow set + { 0002, { "JAP", "JAPM", "XAP" } }, // A positive + { 0004, { "JAN", "JANM", "XAN" } }, // A negative + { 0007, { "JOFN", "JOFNM", "XOFN" } }, // overflow not set (620/f) + { 0010, { "JAZ", "JAZM", "XAZ" } }, // A zero + { 0016, { "JANZ", "JANZM", "XANZ" } }, // A not zero (620/f) + { 0020, { "JBZ", "JBZM", "XBZ" } }, // B zero + { 0026, { "JBNZ", "JBNZM", "XBNZ" } }, // B not zero (620/f) + { 0040, { "JXZ", "JXZM", "XXZ" } }, // X zero + { 0046, { "JXNZ", "JXNZM", "XXNZ" } }, // X not zero (620/f) + { 0100, { "JSS1", "JS1M", "XS1M" } }, // sense switch 1 set + { 0106, { "JS1N", "JS1NM", "XS1NM" } }, // sense switch 1 not set (620/f) + { 0200, { "JSS2", "JS2M", "XS2M" } }, // sense switch 2 set + { 0206, { "JS2N", "JS2NM", "XS2NM" } }, // sense switch 2 not set (620/f) + { 0400, { "JSS3", "JS3M", "XS3M" } }, // sense switch 3 set + { 0406, { "JS3N", "JS3NM", "XS3NM" } } // sense switch 3 not set (620/f) +}; + +const std::unordered_map s_fpp_map = +{ + { 0001, "FDV" }, + { 0010, "FAD" }, + { 0016, "FMU" }, + { 0020, "FLD" }, + { 0025, "FLT" }, + { 0050, "FSB" }, + { 0103, "FADD" }, + { 0106, "FMUD" }, + { 0122, "FLDD" }, + { 0135, "FDVD" }, + { 0143, "FSBD" }, + { 0200, "FST" }, + { 0221, "FIX" }, + { 0310, "FSTD" } +}; + +} // anonymous namespace + +void v620_disassembler::format_number(std::ostream &stream, u16 n) const +{ + if (n > 7) + stream << '0'; + util::stream_format(stream, "%o", n); +} + +void v620_disassembler::format_address(std::ostream &stream, u16 addr) const +{ + if (addr >= 010000) + stream << '0'; + util::stream_format(stream, "%05o", addr); +} + +offs_t v620_disassembler::dasm_004xxx(std::ostream &stream, u16 inst, offs_t pc, const v620_disassembler::data_buffer &opcodes) const +{ + if (inst < 004600) + { + // Shift instruction group + if (BIT(inst, 8)) + util::stream_format(stream, "L%-7s", s_shift_ops[BIT(inst, 5, 2)]); + else + util::stream_format(stream, "%s%-5c", s_shift_ops[BIT(inst, 5, 2)], BIT(inst, 7) ? 'A' : 'B'); + util::stream_format(stream, "%d", BIT(inst, 0, 5)); + } + else + { + util::stream_format(stream, "%-8s", "DATA"); + format_number(stream, inst); + } + return 1 | SUPPORTED; +} + +offs_t v75_disassembler::dasm_004xxx(std::ostream &stream, u16 inst, offs_t pc, const v75_disassembler::data_buffer &opcodes) const +{ + if (inst >= 004600 && BIT(inst, 3, 3) != 7) + { + // Double-precision instructions + u16 addr = opcodes.r16(pc + 1); + util::stream_format(stream, "%-7s ", util::string_format("%s%s,%s", s_dp_ops[BIT(inst, 3, 3)], BIT(addr, 15) ? "*" : "", s_reg_names[BIT(inst, 6) ? 4 : 0])); + if (BIT(inst, 0, 3) == 0) + format_address(stream, addr & 077777); + else + { + format_number(stream, addr & 077777); + stream << ',' << s_reg_names[BIT(inst, 0, 3)]; + } + return 2 | SUPPORTED; + } + else + return v620_disassembler::dasm_004xxx(stream, inst, pc, opcodes); +} + +offs_t v620_disassembler::dasm_misc(std::ostream &stream, u16 inst, offs_t pc, const v620_disassembler::data_buffer &opcodes) const +{ + if ((inst & 0177700) == 006400) + { + // Bit test (620/f) + u16 dest = opcodes.r16(pc + 1); + util::stream_format(stream, "%s%-6c", "BT", BIT(dest, 15) ? '*' : ' '); + format_number(stream, BIT(inst, 0, 6)); + stream << ','; + format_address(stream, dest & 077777); + return 2 | STEP_COND | SUPPORTED; + } + else if (inst == 006505 || inst == 006506) + { + // Jump and set return in index (620/f) + u16 dest = opcodes.r16(pc + 1); + util::stream_format(stream, "%s%-5c", "JSR", BIT(dest, 15) ? '*' : ' '); + format_address(stream, dest & 077777); + stream << s_index_tags[inst - 006505]; + return 2 | STEP_OVER | SUPPORTED; + } + else if ((inst & 0177704) == 006604) + { + // Skip on register equal (620/f) + u8 mode = BIT(inst, 0, 3); + u16 addr = opcodes.r16(pc + 1); + util::stream_format(stream, "%s%-5c", "SRE", BIT(addr, 15) ? '*' : ' '); + if (mode == 5 || mode == 6) + { + format_number(stream, addr & 077777); + stream << s_index_tags[mode - 5]; + } + else + format_address(stream, (mode == 4 ? pc + 1 + addr : addr) & 077777); + stream << ','; + format_number(stream, inst & 000070); + return 2 | STEP_COND | SUPPORTED; + } + else if ((inst & 0177774) == 006704) + { + // Indexed jump (620/f) + u8 mode = BIT(inst, 0, 3); + u16 dest = opcodes.r16(pc + 1); + util::stream_format(stream, "%s%-4c", "IJMP", BIT(dest, 15) ? '*' : ' '); + if (mode == 5 || mode == 6) + { + format_number(stream, dest & 077777); + stream << s_index_tags[mode - 5]; + } + else + format_address(stream, (mode == 4 ? pc + 1 + dest : dest) & 077777); + return 2 | SUPPORTED; + } + else + { + if (inst == 007400) + stream << "ROF"; + else if (inst == 007401) + stream << "SOF"; + else if (inst == 007402) + stream << "TSA"; // switches to A (620/f) + else + { + util::stream_format(stream, "%-8s", "DATA"); + format_number(stream, inst); + } + return 1 | SUPPORTED; + } +} + +offs_t v75_disassembler::dasm_misc(std::ostream &stream, u16 inst, offs_t pc, const v75_disassembler::data_buffer &opcodes) const +{ + if (inst >= 007500) + { + // Register-to-register instructions + util::stream_format(stream, "%s,%s,%s", s_rr_ops[BIT(inst, 6, 2) - 1], s_reg_names[BIT(inst, 3, 3)], s_reg_names[BIT(inst, 0, 3)]); + return 1 | SUPPORTED; + } + else if (inst >= 007460) + { + // Byte instructions (register is always R0, i.e. A) + u16 addr = opcodes.r16(pc + 1); + util::stream_format(stream, "%-8s", util::string_format("%cBT%c", BIT(inst, 3) ? 'S' : 'L', BIT(addr, 15) ? '*' : ' ')); + if (BIT(inst, 0, 3) == 0) + format_address(stream, addr & 077777); + else + { + format_number(stream, addr & 077777); + stream << ',' << s_reg_names[BIT(inst, 0, 3)]; + } + return 2 | SUPPORTED; + } + else if (inst >= 007440) + { + // Immediate instructions + util::stream_format(stream, "%-8s", util::string_format("%sI,%s", BIT(inst, 3) ? "AD" : "LD", s_reg_names[BIT(inst, 0, 3)])); + format_number(stream, opcodes.r16(pc + 1)); + return 2 | SUPPORTED; + } + else if (inst >= 007410) + { + // Single-register instructions + util::stream_format(stream, "%s,%s", s_single_reg_ops[BIT(inst, 3, 2) - 1], s_reg_names[BIT(inst, 0, 3)]); + return 1 | SUPPORTED; + } + else if ((inst & 0177400) == 007000) + { + // Register-to-memory instructions + u16 addr = opcodes.r16(pc + 1); + util::stream_format(stream, "%-8s", util::string_format("%s%s,%s", s_reg_mem_ops[BIT(inst, 6, 2)], BIT(addr, 15) ? "*" : "", s_reg_names[BIT(inst, 3, 3)])); + if (BIT(inst, 0, 3) == 0) + format_address(stream, addr & 077777); + else + { + format_number(stream, addr & 077777); + stream << ',' << s_reg_names[BIT(inst, 0, 3)]; + } + return 2 | SUPPORTED; + } + else if (inst >= 06720 && inst < 07000) + { + // Jump-if instructions + u16 dest = opcodes.r16(pc + 1); + util::stream_format(stream, "%-8s", util::string_format("%s%s,%s", s_reg_jumps[BIT(inst, 3, 3) - 2], BIT(dest, 15) ? "*" : "", s_reg_names[BIT(inst, 0, 3)])); + format_address(stream, dest & 077777); + return 2 | STEP_COND | SUPPORTED; + } + else + return v620_disassembler::dasm_misc(stream, inst, pc, opcodes); +} + +offs_t v620_disassembler::dasm_io(std::ostream &stream, u16 inst, offs_t pc, const v620_disassembler::data_buffer &opcodes) const +{ + if (inst < 0101000) + { + // External control + util::stream_format(stream, "%-8s", "EXC"); + format_number(stream, BIT(inst, 0, 9)); + return 1 | SUPPORTED; + } + else if (inst < 0102000) + { + u16 dest = opcodes.r16(pc + 1); + util::stream_format(stream, "%s%-5s", "SEN", BIT(dest, 15) ? '*' : ' '); + format_number(stream, BIT(inst, 0, 9)); + stream << ','; + format_address(stream, dest & 077777); + return 2 | STEP_COND | SUPPORTED; + } + else if (inst < 0103400 && BIT(inst, 9, 4) != 4) + { + util::stream_format(stream, "%-8s", s_in_out_ops[BIT(inst, 9, 4)]); + format_number(stream, BIT(inst, 0, 6)); + if (BIT(inst, 9, 3) == 0) + { + stream << ','; + format_address(stream, opcodes.r16(pc + 1) & 077777); + return 2 | SUPPORTED; + } + else + return 1 | SUPPORTED; + } + else + { + util::stream_format(stream, "%-8s", "DATA"); + format_number(stream, inst); + return 1 | SUPPORTED; + } +} + +offs_t v75_disassembler::dasm_io(std::ostream &stream, u16 inst, offs_t pc, const v620_disassembler::data_buffer &opcodes) const +{ + if ((inst & 0177000) == 0104000) + { + util::stream_format(stream, "%-8s", "EXC2"); + format_number(stream, BIT(inst, 0, 9)); + return 1 | SUPPORTED; + } + + if ((inst & 0177400) == 0105400) + { + // Floating point processor option + auto lookup = s_fpp_map.find(BIT(inst, 0, 8)); + if (lookup != s_fpp_map.end()) + { + u16 addr = opcodes.r16(pc + 1); + if (BIT(addr, 15)) + util::stream_format(stream, "%-8s", std::string(lookup->second) + "*"); + else + util::stream_format(stream, "%-8s", lookup->second); + format_address(stream, addr & 077777); + return 2 | SUPPORTED; + } + } + + return v620_disassembler::dasm_io(stream, inst, pc, opcodes); +} + +offs_t v620_disassembler::disassemble(std::ostream &stream, offs_t pc, const v620_disassembler::data_buffer &opcodes, const v620_disassembler::data_buffer ¶ms) +{ + u16 inst = opcodes.r16(pc); + if (BIT(inst, 12, 3) != 0) + { + // Single-word addressing instructions + u8 mode = BIT(inst, 9, 3); + util::stream_format(stream, "%s%-5c", s_alu_ops[BIT(inst, 12, 4)], mode == 7 ? '*' : ' '); + switch (mode) + { + case 0: case 1: case 2: case 3: + format_address(stream, BIT(inst, 0, 11)); + break; + + case 4: + format_address(stream, (pc + 1 + BIT(inst, 0, 9)) & 077777); + break; + + case 5: case 6: + format_number(stream, BIT(inst, 0, 9)); + stream << s_index_tags[mode - 5]; + break; + + case 7: + format_address(stream, BIT(inst, 0, 9)); + break; + } + return 1 | SUPPORTED; + } + else if (inst >= 0100000) + return dasm_io(stream, inst, pc, opcodes); + else if (inst >= 006000) + { + if (inst < (BIT(inst, 2) ? 006400 : 006200) && BIT(inst, 3, 3) != 0) + { + // Extended-addressing instruction group + if (BIT(inst, 2)) + { + u8 mode = BIT(inst, 0, 3); + u16 addr = opcodes.r16(pc + 1); + util::stream_format(stream, "%sE%-4c", s_alu_ops[BIT(inst, 3, 4)], BIT(addr, 15) ? '*' : ' '); + if (mode == 5 || mode == 6) + { + format_number(stream, addr & 077777); + stream << s_index_tags[mode - 5]; + } + else + format_address(stream, (mode == 4 ? pc + 1 + addr : addr) & 077777); + if (BIT(inst, 7)) + { + // Postindexing (620/f) + stream << ','; + format_number(stream, 0200); + } + } + else + { + util::stream_format(stream, "%s%-5c", s_alu_ops[BIT(inst, 3, 4)], 'I'); + format_number(stream, opcodes.r16(pc + 1)); + } + return 2 | SUPPORTED; + } + else + return dasm_misc(stream, inst, pc, opcodes); + } + else if (inst >= 005000) + { + // Register change group + if (BIT(inst, 6)) + { + // Increment or decrement + switch (inst & 000477) + { + case 011: + util::stream_format(stream, "%cAR", BIT(inst, 7) ? 'D' : 'I'); + break; + + case 022: + util::stream_format(stream, "%cBR", BIT(inst, 7) ? 'D' : 'I'); + break; + + case 044: + util::stream_format(stream, "%cXR", BIT(inst, 7) ? 'D' : 'I'); + break; + + case 0411: + util::stream_format(stream, "%cOFA", BIT(inst, 7) ? 'S' : 'A'); + break; + + case 0422: + util::stream_format(stream, "%cOFB", BIT(inst, 7) ? 'S' : 'A'); + break; + + case 0444: + util::stream_format(stream, "%cOFX", BIT(inst, 7) ? 'S' : 'A'); + break; + + default: + util::stream_format(stream, "%-8s", BIT(inst, 7) ? "DECR" : "INCR"); + format_number(stream, inst & 000477); + break; + } + } + else + { + // Transfer true or complement + switch (inst & 000677) + { + case 000: + stream << "NOP"; + break; + + case 001: + stream << "TZA"; + break; + + case 002: + stream << "TZB"; + break; + + case 004: + stream << "TZX"; + break; + + case 012: + stream << "TAB"; + break; + + case 014: + stream << "TAX"; + break; + + case 021: + stream << "TBA"; + break; + + case 024: + stream << "TBX"; + break; + + case 041: + stream << "TXA"; + break; + + case 042: + stream << "TXB"; + break; + + case 0211: + stream << "CPA"; + break; + + case 0222: + stream << "CPB"; + break; + + case 0244: + stream << "CPX"; + break; + + default: + util::stream_format(stream, "%-8s", BIT(inst, 7) ? "COMP" : BIT(inst, 3, 3) == 0 ? "ZERO" : "MERG"); + format_number(stream, inst & 000477); + break; + } + } + return 1 | SUPPORTED; + } + else if (inst >= 004000) + return dasm_004xxx(stream, inst, pc, opcodes); + else if (inst >= 001000 && inst < 004000) + { + // Jump and execute instructions + u16 dest = opcodes.r16(pc + 1); + u16 cond = BIT(inst, 0, 9); + auto lookup = s_cond_map.find(cond); + if (lookup != s_cond_map.end()) + { + if (BIT(dest, 15)) + util::stream_format(stream, "%-8s", std::string(lookup->second[BIT(inst, 9, 2) - 1]) + "*"); + else + util::stream_format(stream, "%-8s", lookup->second[BIT(inst, 9, 2) - 1]); + } + else + { + std::string name = util::string_format("%cIF", inst < 03000 ? 'J' : 'X'); + if (!BIT(inst, 9)) + name += 'M'; + if (BIT(dest, 15)) + name += '*'; + util::stream_format(stream, "%-8s", name); + format_number(stream, cond); + stream << ','; + } + format_address(stream, dest & 077777); + if (inst == 001000 && BIT(dest, 15)) + return 2 | STEP_OUT | SUPPORTED; + else + return 2 | (BIT(inst, 10) ? STEP_OVER : 0) | (cond != 0 ? STEP_COND : 0) | SUPPORTED; + } + else + { + if (inst == 0) + stream << "HLT"; + else + { + util::stream_format(stream, "%-8s", "DATA"); + format_number(stream, inst); + } + return 1 | SUPPORTED; + } +} diff --git a/src/devices/cpu/v620/v620dasm.h b/src/devices/cpu/v620/v620dasm.h new file mode 100644 index 00000000000..50054231c57 --- /dev/null +++ b/src/devices/cpu/v620/v620dasm.h @@ -0,0 +1,41 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_CPU_V620_V620_H +#define MAME_CPU_V620_V620_H + +#pragma once + +class v620_disassembler : public util::disasm_interface +{ +public: + // construction/destruction + v620_disassembler(); + +protected: + // disassembler overrides + virtual u32 opcode_alignment() const override; + virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + + virtual offs_t dasm_004xxx(std::ostream &stream, u16 inst, offs_t pc, const data_buffer &opcodes) const; + virtual offs_t dasm_misc(std::ostream &stream, u16 inst, offs_t pc, const data_buffer &opcodes) const; + virtual offs_t dasm_io(std::ostream &stream, u16 inst, offs_t pc, const data_buffer &opcodes) const; + + // internal helpers + void format_number(std::ostream &stream, u16 n) const; + void format_address(std::ostream &stream, u16 addr) const; +}; + +class v75_disassembler : public v620_disassembler +{ +public: + // construction/destruction + v75_disassembler(); + +protected: + virtual offs_t dasm_004xxx(std::ostream &stream, u16 inst, offs_t pc, const data_buffer &opcodes) const override; + virtual offs_t dasm_misc(std::ostream &stream, u16 inst, offs_t pc, const data_buffer &opcodes) const override; + virtual offs_t dasm_io(std::ostream &stream, u16 inst, offs_t pc, const data_buffer &opcodes) const override; +}; + +#endif // MAME_CPU_V620_V620_H diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index aa08ba7d7ca..708fc9bf7a1 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -66,6 +66,7 @@ using util::BIT; #include "cpu/hcd62121/hcd62121d.h" #include "cpu/hd61700/hd61700d.h" #include "cpu/hmcs40/hmcs40d.h" +#include "cpu/hp2100/hp2100d.h" #include "cpu/hpc/hpcdasm.h" #include "cpu/hphybrid/hphybrid_dasm.h" #include "cpu/i386/i386dasm.h" @@ -186,6 +187,7 @@ using util::BIT; #include "cpu/upd78k/upd78k3d.h" #include "cpu/upd78k/upd78k4d.h" #include "cpu/v60/v60d.h" +#include "cpu/v620/v620dasm.h" #include "cpu/v810/v810dasm.h" #include "cpu/v850/v850dasm.h" #include "cpu/vax/vaxdasm.h" @@ -448,6 +450,8 @@ static const dasm_table_entry dasm_table[] = { "hd6309", be, 0, []() -> util::disasm_interface * { return new hd6309_disassembler; } }, { "hd63701", be, 0, []() -> util::disasm_interface * { return new m680x_disassembler(63701); } }, { "hmcs40", le, -1, []() -> util::disasm_interface * { return new hmcs40_disassembler; } }, + { "hp2100", be, -1, []() -> util::disasm_interface * { return new hp2100_disassembler; } }, + { "hp21mx", be, -1, []() -> util::disasm_interface * { return new hp21mx_disassembler; } }, { "hp_5061_3001", be, -1, []() -> util::disasm_interface * { return new hp_5061_3001_disassembler; } }, { "hp_5061_3011", be, -1, []() -> util::disasm_interface * { return new hp_5061_3011_disassembler; } }, { "hp_09825_67907", be, -1, []() -> util::disasm_interface * { return new hp_09825_67907_disassembler; } }, @@ -655,6 +659,8 @@ static const dasm_table_entry dasm_table[] = { "upd78k0kx2", le, 0, []() -> util::disasm_interface * { return new upd78k0kx2_disassembler; } }, { "upi41", le, 0, []() -> util::disasm_interface * { return new mcs48_disassembler(true, false); } }, { "v60", le, 0, []() -> util::disasm_interface * { return new v60_disassembler; } }, + { "v620", be, -1, []() -> util::disasm_interface * { return new v620_disassembler; } }, + { "v75", be, -1, []() -> util::disasm_interface * { return new v75_disassembler; } }, { "v810", le, 0, []() -> util::disasm_interface * { return new v810_disassembler; } }, { "v850", le, 0, []() -> util::disasm_interface * { return new v850_disassembler; } }, { "v850es", le, 0, []() -> util::disasm_interface * { return new v850es_disassembler; } },