diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/cpu/ibm1800/ibm1800d.cpp | 258 | ||||
-rw-r--r-- | src/devices/cpu/ibm1800/ibm1800d.h | 35 | ||||
-rw-r--r-- | src/devices/cpu/nova/novadasm.cpp | 262 | ||||
-rw-r--r-- | src/devices/cpu/nova/novadasm.h | 25 | ||||
-rw-r--r-- | src/tools/unidasm.cpp | 5 |
5 files changed, 585 insertions, 0 deletions
diff --git a/src/devices/cpu/ibm1800/ibm1800d.cpp b/src/devices/cpu/ibm1800/ibm1800d.cpp new file mode 100644 index 00000000000..0b151eae291 --- /dev/null +++ b/src/devices/cpu/ibm1800/ibm1800d.cpp @@ -0,0 +1,258 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + IBM 1130/1800 disassembler + + The 1800 has a few more instructions than the 1130 (and some later 1800 + clones have further extensions to the instruction set). The most + significant difference, however, is that the index registers are part + of core storage on the 1130 but not memory-mapped on the 1800; some + 1130 programs take advantage of this fact, and IBM's diagnostics use it + to distinguish the two processors. + + Endianness note: the architectural format for double-word operands in + memory requires the upper 16 bits to be located at an even address and + the lower 16 bits at the next higher address. However, in the 1442 + packed binary card format, words are punched with the lower 8 bits in + positions 12 to 5 of odd-numbered columns and the upper 8 bits in the + same positions of the even-numbered columns to their right. Punched + card dumps will therefore likely need byte-swapping to be correctly + parsed by tools such as unidasm. Similar byte-swapping might also be + necessary for disk pack dumps. + + The 1130/1800 assembler source format requires that the format and tag + fields be placed in specific columns to the left of the operand field. + This is particularly significant for shift instructions, whose count + is obtained either from the operand field or from an index register. + +***************************************************************************/ + +#include "emu.h" +#include "ibm1800d.h" + +namespace { + +const char *const s_memory_ops[32] = +{ + "", "XIO", "", "", + "", "STS", "", "", + "BSI", "", "", "", + "LDX", "STX", "MDX", "", + "A", "AD", "S", "SD", + "M", "D", "CMP", "DCM", + "LD", "LDD", "STO", "STD", + "AND", "OR", "EOR", "" +}; + +const char *const s_shift_ops[8] = +{ + "SLA", "SLCA", "SLT", "SLC", + "SRA", "", "SRT", "RTE" +}; + +} // anonymous namespace + +ibm1800_disassembler::ibm1800_disassembler(bool type_1130) + : util::disasm_interface() + , m_1130(type_1130) +{ +} + +ibm1130_disassembler::ibm1130_disassembler() + : ibm1800_disassembler(true) +{ +} + +u32 ibm1800_disassembler::opcode_alignment() const +{ + return 1; +} + +void ibm1800_disassembler::format_cond(std::ostream &stream, u8 cond) +{ + if (cond == 0) + { + stream << '0'; + return; + } + + for (int b = 5; b != 0; --b) + { + if (BIT(cond, b)) + stream << "OCE+-Z"[b]; + } +} + +void ibm1800_disassembler::format_disp(std::ostream &stream, int disp) +{ + if (disp < 0) + { + stream << '-'; + disp = -disp; + } + if (unsigned(disp) > 9) + stream << '/'; + util::stream_format(stream, "%X", unsigned(disp)); +} + +offs_t ibm1800_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) +{ + u16 inst = opcodes.r16(pc); + + if ((inst & 0xf400) == 0x1000 && (inst & 0x08c0) != 0x0840) + { + // Shift instructions + if (inst == 0x1000) + stream << "NOP"; + else if (inst == 0x18d0) + stream << "XCH"; + else + { + util::stream_format(stream, "%-5s", s_shift_ops[bitswap<3>(inst, 11, 7, 6)]); + if (BIT(inst, 8, 2) != 0) + util::stream_format(stream, " %d", BIT(inst, 8, 2)); + else + util::stream_format(stream, " %d", inst & 0x003f); + } + return 1 | SUPPORTED; + } + else if ((inst & 0xff00) == 0x2000) + { + // LDS sets or resets carry and overflow indicators + util::stream_format(stream, "%-8s%d", "LDS", inst & 0x0003); + return 1 | SUPPORTED; + } + else if ((inst & 0xff00) == 0x3000) + { + u8 disp = inst & 0x00ff; + if (disp != 0) + util::stream_format(stream, "%-8s/%02X", "WAIT", disp); + else + stream << "WAIT"; + return 1 | SUPPORTED; + } + else if ((inst & 0xff80) == 0x4800) + { + // Single word skip instructions + util::stream_format(stream, "%-8s", BIT(inst, 6) ? "BOSC" : "SKP"); + format_cond(stream, inst & 0x003f); + return 1 | STEP_COND | SUPPORTED; + } + else if ((inst & 0xfc00) == 0x4c00) + { + // Long branch instructions + bool bsc = false; + switch (inst & 0x007f) + { + case 0x00: + util::stream_format(stream, "%-5s", "B"); + break; + + case 0x01: + util::stream_format(stream, "%-5s", "BO"); + break; + + case 0x02: + util::stream_format(stream, "%-5s", "BC"); + break; + + case 0x04: + util::stream_format(stream, "%-5s", "BOD"); + break; + + case 0x08: + util::stream_format(stream, "%-5s", "BNP"); + break; + + case 0x10: + util::stream_format(stream, "%-5s", "BNN"); + break; + + case 0x18: + util::stream_format(stream, "%-5s", "BZ"); + break; + + case 0x20: + util::stream_format(stream, "%-5s", "BNZ"); + break; + + case 0x28: + util::stream_format(stream, "%-5s", "BN"); + break; + + case 0x30: + util::stream_format(stream, "%-5s", "BP"); + break; + + default: + util::stream_format(stream, "%-5s", BIT(inst, 6) ? "BOSC" : "BSC"); + bsc = true; + break; + } + util::stream_format(stream, "%c%c ", BIT(inst, 7) ? 'I' : bsc || (inst & 0x003f) == 0 ? 'L' : ' ', BIT(inst, 8, 2) != 0 ? '0' + BIT(inst, 8, 2) : ' '); + if (BIT(inst, 8, 2) != 0) + format_disp(stream, s16(opcodes.r16(pc + 1))); + else + util::stream_format(stream, "/%04X", opcodes.r16(pc + 1)); + if (bsc && (inst & 0x003f) != 0) + { + stream << ','; + format_cond(stream, inst & 0x003f); + } + return 2 | ((inst & 0x003f) != 0 ? STEP_COND : 0) | ((inst & 0x0380) == 0x0080 ? STEP_OUT : 0) | SUPPORTED; + } + else if ((inst & 0xff00) == 0x7400) + { + // Special long-format version of MDX which takes an 8-bit signed displacement and does not allow indirection + util::stream_format(stream, "%-8s/%04X,", "MDM", opcodes.r16(pc + 1)); + format_disp(stream, s8(inst & 0x00ff)); + return 2 | STEP_COND | SUPPORTED; + } + else + { + const char *op = s_memory_ops[BIT(inst, 11, 5)]; + if (*op != '\0' && ((inst & 0xf000) != 0xb000 || !m_1130)) + { + util::stream_format(stream, "%-5s", op); + offs_t flags = (inst & 0xf800) == 0x4000 ? STEP_OVER : (inst & 0xf800) == 0x7000 || (inst & 0xf000) == 0xb000 ? STEP_COND : 0; + if (BIT(inst, 10)) + { + // Long format + util::stream_format(stream, "%c%c ", BIT(inst, 7) ? 'I' : 'L', BIT(inst, 8, 2) != 0 ? '0' + BIT(inst, 8, 2) : ' '); + u16 addr = opcodes.r16(pc + 1); + if (BIT(inst, 8, 2) != 0 && (inst & 0xe880) != 0x6080 && (inst & 0xf800) != 0x6800) + format_disp(stream, s16(addr)); + else if (m_1130 && addr <= 0x0003 && addr != 0x0000) + util::stream_format(stream, "XR%d", addr); + else + util::stream_format(stream, "/%04X", addr); + // This extra field can be used on the 1800 for the storage protect status variation of STS (/40, /41, /C0, /C1) + if ((inst & 0x007f) != 0) + util::stream_format(stream, ",/%02X", inst & 0x007f); + return 2 | flags | SUPPORTED; + } + else if (BIT(inst, 8, 2) != 0) + { + // Short format with indexing + util::stream_format(stream, " %d ", BIT(inst, 8, 2)); + if ((inst & 0xf800) == 0x6800) + util::stream_format(stream, "/%04X", (pc + 1 + s8(inst & 0x00ff)) & 0xffff); + else + format_disp(stream, s8(inst & 0x00ff)); + return 1 | flags | SUPPORTED; + } + else + { + // Short format without indexing + util::stream_format(stream, " /%04X", (((inst & 0xf800) == 0x6000 ? 0 : pc + 1) + s8(inst & 0x00ff)) & 0xffff); + return 1 | ((inst & 0xf800) == 0x7000 ? 0 : flags) | SUPPORTED; // MDX branches unconditionally in this mode + } + } + else + { + util::stream_format(stream, "%-8s/%04X", "DC", inst); + return 1 | SUPPORTED; + } + } +} diff --git a/src/devices/cpu/ibm1800/ibm1800d.h b/src/devices/cpu/ibm1800/ibm1800d.h new file mode 100644 index 00000000000..47c7a9c3312 --- /dev/null +++ b/src/devices/cpu/ibm1800/ibm1800d.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_CPU_IBM1800_IBM1800D_H +#define MAME_CPU_IBM1800_IBM1800D_H + +#pragma once + +class ibm1800_disassembler : public util::disasm_interface +{ +public: + // construction/destruction + ibm1800_disassembler(bool type_1130 = false); + +protected: + // util::disasm_interface 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; + +private: + // formatting helpers + static void format_cond(std::ostream &stream, u8 cond); + static void format_disp(std::ostream &stream, int disp); + + const bool m_1130; +}; + +class ibm1130_disassembler : public ibm1800_disassembler +{ +public: + // construction/destrution + ibm1130_disassembler(); +}; + +#endif // MAME_CPU_IBM1800_IBM1800D_H diff --git a/src/devices/cpu/nova/novadasm.cpp b/src/devices/cpu/nova/novadasm.cpp new file mode 100644 index 00000000000..408f6329fb9 --- /dev/null +++ b/src/devices/cpu/nova/novadasm.cpp @@ -0,0 +1,262 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Data General Nova disassembler + +***************************************************************************/ + +#include "emu.h" +#include "novadasm.h" + +nova_disassembler::nova_disassembler() +{ +} + +u32 nova_disassembler::opcode_alignment() const +{ + return 1; +} + +namespace { + +const char *const s_alc_ops[8] = +{ + "COM", "NEG", "MOV", "INC", + "ADC", "SUB", "ADD", "AND" +}; + +const char *const s_skip_codes[8] = +{ + "0", "SKP", + "SZC", "SNC", + "SZR", "SNR", + "SEZ", "SBN" +}; + +const char *const s_io_ops[8] = +{ + "NIO", "DIA", "DOA", "DIB", + "DOB", "DIC", "DOC", "SKP" +}; + +} // anonymous namespace + +void nova_disassembler::format_effective_address(std::ostream &stream, offs_t pc, u16 inst) +{ + if (BIT(inst, 10)) + stream << '@'; + u8 disp = inst & 0377; + if (BIT(inst, 9)) + { + if (s8(disp) < 0) + { + stream << '-'; + disp = -disp; + } + util::stream_format(stream, "%o,%d", disp, BIT(inst, 8, 2)); + } + else + util::stream_format(stream, "%05o", BIT(inst, 8) ? (pc + int(s8(disp))) & 077777 : disp); +} + +void nova_disassembler::format_device_code(std::ostream &stream, u8 device) +{ + switch (device) + { + case 001: + stream << "MDV"; + break; + + case 002: case 003: case 004: + util::stream_format(stream, "MAP%d", device - 2); + break; + + case 006: + stream << "MCAT"; + break; + + case 007: + stream << "MCAR"; + break; + + case 010: + stream << "TTI"; + break; + + case 011: + stream << "TTO"; + break; + + case 012: + stream << "PTR"; + break; + + case 013: + stream << "PTP"; + break; + + case 014: + stream << "RTC"; + break; + + case 015: + stream << "PLT"; + break; + + case 016: + stream << "CDR"; + break; + + case 017: + stream << "LPT"; + break; + + case 020: + stream << "DSK"; + break; + + case 021: + stream << "ADCV"; + break; + + case 022: + stream << "MTA"; + break; + + case 023: + stream << "DACV"; + break; + + case 024: + stream << "DCM"; + break; + + case 033: + stream << "DKP"; + break; + + case 040: + stream << "SCR"; + break; + + case 041: + stream << "SCT"; + break; + + case 077: + stream << "CPU"; + break; + + default: + util::stream_format(stream, "%o", device); + break; + } +} + +offs_t nova_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) +{ + u16 inst = opcodes.r16(pc); + if (BIT(inst, 15)) + { + // ALC (arithmetic-logical) + std::string alcop(s_alc_ops[BIT(inst, 8, 3)]); + if (BIT(inst, 4, 2) != 0) + alcop.push_back("ZOC"[BIT(inst, 4, 2) - 1]); + if (BIT(inst, 6, 2) != 0) + alcop.push_back("LRS"[BIT(inst, 6, 2) - 1]); + if (BIT(inst, 3)) + alcop.push_back('#'); + util::stream_format(stream, "%-8s%d,%d", alcop, BIT(inst, 13, 2), BIT(inst, 11, 2)); + if (BIT(inst, 0, 3) != 0) + stream << ',' << s_skip_codes[BIT(inst, 0, 3)]; + return 1 | (BIT(inst, 1, 2) != 0 ? STEP_COND : 0) | SUPPORTED; + } + else if (inst >= 060000) + { + // I/O + switch (inst & 03777) + { + case 00177: + stream << "INTEN"; + return 1 | SUPPORTED; + + case 00277: + stream << "INTDS"; + return 1 | SUPPORTED; + + case 00477: + util::stream_format(stream, "%-8s%d", "READS", BIT(inst, 11, 2)); + return 1 | SUPPORTED; + + case 01477: + util::stream_format(stream, "%-8s%d", "INTA", BIT(inst, 11, 2)); + return 1 | SUPPORTED; + + case 02077: + util::stream_format(stream, "%-8s%d", "MSKO", BIT(inst, 11, 2)); + return 1 | SUPPORTED; + + case 02677: + stream << "IORST"; + return 1 | SUPPORTED; + + case 03077: + stream << "HALT"; + return 1 | SUPPORTED; + + case 03101: + if (BIT(inst, 11, 2) == 2) + { + stream << "DIV"; + return 1 | SUPPORTED; + } + break; + + case 03301: + if (BIT(inst, 11, 2) == 2) + { + stream << "MUL"; + return 1 | SUPPORTED; + } + break; + } + + stream << s_io_ops[BIT(inst, 8, 3)]; + if (BIT(inst, 8, 3) == 7) + { + util::stream_format(stream, "%c%-4c", BIT(inst, 7) ? 'D' : 'B', BIT(inst, 6) ? 'Z' : 'N'); + format_device_code(stream, BIT(inst, 0, 6)); + return 1 | STEP_COND | SUPPORTED; + } + else + { + util::stream_format(stream, "%-5c", " SCP"[BIT(inst, 6, 2)]); + if (BIT(inst, 8, 3) != 0) + util::stream_format(stream, "%d,", BIT(inst, 11, 2)); + format_device_code(stream, BIT(inst, 0, 6)); + return 1 | SUPPORTED; + } + } + else if (inst >= 020000) + { + // Memory reference with accumulator + util::stream_format(stream, "%-8s%d,", BIT(inst, 14) ? "STA" : "LDA", BIT(inst, 11, 2)); + format_effective_address(stream, pc, inst); + return 1 | SUPPORTED; + } + else if (BIT(inst, 12)) + { + // Memory reference with conditional skip + util::stream_format(stream, "%-8s", BIT(inst, 11) ? "DSZ" : "ISZ"); + format_effective_address(stream, pc, inst); + return 1 | STEP_COND | SUPPORTED; + } + else + { + // Memory reference with jump + util::stream_format(stream, "%-8s", BIT(inst, 11) ? "JSR" : "JMP"); + format_effective_address(stream, pc, inst); + return 1 | (BIT(inst, 11) ? STEP_OVER : 0) | SUPPORTED; + } +} diff --git a/src/devices/cpu/nova/novadasm.h b/src/devices/cpu/nova/novadasm.h new file mode 100644 index 00000000000..e5105c5efd7 --- /dev/null +++ b/src/devices/cpu/nova/novadasm.h @@ -0,0 +1,25 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_CPU_NOVA_NOVADASM_H +#define MAME_CPU_NOVA_NOVADASM_H + +#pragma once + +class nova_disassembler : public util::disasm_interface +{ +public: + // construction/destruction + nova_disassembler(); + +protected: + // util::disasm_interface 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; + + // formatting helpers + static void format_effective_address(std::ostream &stream, offs_t pc, u16 inst); + static void format_device_code(std::ostream &stream, u8 device); +}; + +#endif // MAME_CPU_NOVA_NOVADASM_H diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index 918c6fab73f..24123927902 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -74,6 +74,7 @@ using util::BIT; #include "cpu/i8089/i8089_dasm.h" #include "cpu/i860/i860dis.h" #include "cpu/i960/i960dis.h" +#include "cpu/ibm1800/ibm1800d.h" #include "cpu/ie15/ie15dasm.h" #include "cpu/jaguar/jagdasm.h" #include "cpu/ks0164/ks0164d.h" @@ -123,6 +124,7 @@ using util::BIT; #include "cpu/nanoprocessor/nanoprocessor_dasm.h" #include "cpu/nec/necdasm.h" #include "cpu/nios2/nios2dasm.h" +#include "cpu/nova/novadasm.h" #include "cpu/ns32000/ns32000dasm.h" #include "cpu/nuon/nuondasm.h" #include "cpu/pace/pacedasm.h" @@ -479,6 +481,8 @@ static const dasm_table_entry dasm_table[] = { "i8xc51fx", le, 0, []() -> util::disasm_interface * { return new i8xc51fx_disassembler; } }, { "i8xc51gb", le, 0, []() -> util::disasm_interface * { return new i8xc51gb_disassembler; } }, { "i960", le, 0, []() -> util::disasm_interface * { return new i960_disassembler; } }, + { "ibm1130", be, -1, []() -> util::disasm_interface * { return new ibm1130_disassembler; } }, + { "ibm1800", be, -1, []() -> util::disasm_interface * { return new ibm1800_disassembler; } }, { "ie15", le, 0, []() -> util::disasm_interface * { return new ie15_disassembler; } }, { "jaguardsp", be, 0, []() -> util::disasm_interface * { return new jaguar_disassembler(jaguar_disassembler::variant::DSP); } }, { "jaguargpu", be, 0, []() -> util::disasm_interface * { return new jaguar_disassembler(jaguar_disassembler::variant::GPU); } }, @@ -539,6 +543,7 @@ static const dasm_table_entry dasm_table[] = { "nanoprocessor", le, 0, []() -> util::disasm_interface * { return new hp_nanoprocessor_disassembler; } }, { "nec", le, 0, []() -> util::disasm_interface * { return new nec_disassembler(&nec_unidasm); } }, { "nios2", le, 0, []() -> util::disasm_interface * { return new nios2_disassembler; } }, + { "nova", be, -1, []() -> util::disasm_interface * { return new nova_disassembler; } }, { "ns32000", le, 0, []() -> util::disasm_interface * { return new ns32000_disassembler; } }, { "nuon", be, 0, []() -> util::disasm_interface * { return new nuon_disassembler; } }, { "nsc8105", be, 0, []() -> util::disasm_interface * { return new m680x_disassembler(8105); } }, |