diff options
Diffstat (limited to 'src/devices/cpu/pic17/pic17d.cpp')
-rw-r--r-- | src/devices/cpu/pic17/pic17d.cpp | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/src/devices/cpu/pic17/pic17d.cpp b/src/devices/cpu/pic17/pic17d.cpp new file mode 100644 index 00000000000..139e5058631 --- /dev/null +++ b/src/devices/cpu/pic17/pic17d.cpp @@ -0,0 +1,244 @@ + // license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + Microchip PIC17 disassembler + +***************************************************************************/ + +#include "emu.h" +#include "pic17d.h" + +const char *const pic17_disassembler::s_peripheral_regs[0x20] = +{ + "INDF0", "FSR0", "PCL", "PCLATH", "ALUSTA", "T0STA", "CPUSTA", "INTSTA", + "INDF1", "FSR1", "WREG", "TMR0L", "TMR0H", "TBLPTRL", "TBLPTRH", "BSR", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // banked + "PRODL", "PRODH", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr +}; + +const char *const pic17_disassembler::s_tb_ops[4] = +{ + "TLRD", "TLWT", "TABLRD", "TABLWT" +}; + +const char *const pic17_disassembler::s_bit_ops[4] = +{ + "BSF", "BCF", "BTFSS", "BTFSC" +}; + +const char *const pic17_disassembler::s_cp_ops[4] = +{ + "CPFSLT", "CPFSEQ", "CPFSGT", "TSTFSZ" +}; + +const char *const pic17_disassembler::s_alu_ops[0x30 / 2] = +{ + "MOVWF", "SUBWFB", "SUBWF", "DECF", "IORWF", "ANDWF", "XORWF", "ADDWF", + "ADDWFC", "COMF", "INCF", "DECFSZ", "RRCF", "RLCF", "SWAPF", "INCFSZ", + "RRNCF", "RLNCF", "INFSNZ", "DCFSNZ", "CLRF", "SETF", "NEGW", "DAW" +}; + +pic17_disassembler::pic17_disassembler() + : util::disasm_interface() +{ +} + +u32 pic17_disassembler::opcode_alignment() const +{ + return 1; +} + +void pic17_disassembler::format_register(std::ostream &stream, u8 reg) const +{ + if (reg < 0x20 && s_peripheral_regs[reg] != nullptr) + stream << s_peripheral_regs[reg]; + else + util::stream_format(stream, "R%02X", reg); +} + +void pic17_disassembler::format_literal(std::ostream &stream, u8 data) const +{ + util::stream_format(stream, "%02Xh", data); +} + +void pic17_disassembler::format_address(std::ostream &stream, u16 dst) const +{ + util::stream_format(stream, "%04Xh", dst); +} + +offs_t pic17_disassembler::disassemble(std::ostream &stream, offs_t pc, const pic17_disassembler::data_buffer &opcodes, const pic17_disassembler::data_buffer ¶ms) +{ + u16 opcode = opcodes.r16(pc); + offs_t words = 1; + + if (opcode >= 0xc000) + { + if (BIT(opcode, 13)) + { + util::stream_format(stream, "%-8s", "CALL"); + words |= STEP_OVER; + } + else + util::stream_format(stream, "%-8s", "GOTO"); + format_address(stream, ((pc + 1) & 0xe000) | (opcode & 0x1fff)); + } + else if (opcode >= 0xb000) + { + // Literal and control operations + switch (opcode & 0x0f00) + { + case 0x000: + util::stream_format(stream, "%-8s", "MOVLW"); + format_literal(stream, opcode & 0x00ff); + break; + + case 0x100: + util::stream_format(stream, "%-8s", "ADDLW"); + format_literal(stream, opcode & 0x00ff); + break; + + case 0x200: + util::stream_format(stream, "%-8s", "SUBLW"); + format_literal(stream, opcode & 0x00ff); + break; + + case 0x300: + util::stream_format(stream, "%-8s", "IORLW"); + format_literal(stream, opcode & 0x00ff); + break; + + case 0x400: + util::stream_format(stream, "%-8s", "XORLW"); + format_literal(stream, opcode & 0x00ff); + break; + + case 0x500: + util::stream_format(stream, "%-8s", "ANDLW"); + format_literal(stream, opcode & 0x00ff); + break; + + case 0x600: + util::stream_format(stream, "%-8s", "RETLW"); + format_literal(stream, opcode & 0x00ff); + words |= STEP_OUT; + break; + + case 0x700: + util::stream_format(stream, "%-8s", "LCALL"); + format_literal(stream, opcode & 0x00ff); + words |= STEP_OVER; + break; + + case 0x800: + util::stream_format(stream, "%-8s%d", "MOVLB", opcode & 0x000f); + break; + + case 0xa00: case 0xb00: + util::stream_format(stream, "%-8s%d", "MOVLR", (opcode & 0x00f0) >> 4); + break; + + case 0xc00: + util::stream_format(stream, "%-8s", "MULLW"); + format_literal(stream, opcode & 0x00ff); + break; + + default: + util::stream_format(stream, "%-8s%04Xh", "DW", opcode); + break; + } + } + else if (opcode >= 0xa000) + { + util::stream_format(stream, "%-8s%d,", s_tb_ops[BIT(opcode, 10, 2)], BIT(opcode, 9)); + if (BIT(opcode, 11)) + util::stream_format(stream, "%d,", BIT(opcode, 8)); + format_register(stream, opcode & 0x00ff); + } + else if (opcode >= 0x8000) + { + // Bit-oriented file register operations + util::stream_format(stream, "%-8s", s_bit_ops[BIT(opcode, 11, 2)]); + format_register(stream, opcode & 0x00ff); + util::stream_format(stream, ",%d", BIT(opcode, 8, 3)); + if (BIT(opcode, 12)) + words |= STEP_COND; + } + else if (opcode >= 0x6000) + { + // Byte-to-byte move operations + util::stream_format(stream, "%-8s", "MOVFP"); + format_register(stream, opcode & 0x00ff); + stream << ","; + format_register(stream, (opcode & 0x1f00) >> 8); + } + else if (opcode >= 0x4000) + { + util::stream_format(stream, "%-8s", "MOVPF"); + format_register(stream, (opcode & 0x1f00) >> 8); + stream << ","; + format_register(stream, opcode & 0x00ff); + } + else if (opcode >= 0x3800) + { + util::stream_format(stream, "%-8s", "BTG"); + format_register(stream, opcode & 0x00ff); + util::stream_format(stream, ",%d", BIT(opcode, 8, 3)); + } + else if (opcode >= 0x3000) + { + if (opcode < 0x3400) + { + util::stream_format(stream, "%-8s", s_cp_ops[BIT(opcode, 8, 2)]); + format_register(stream, opcode & 0x00ff); + words |= STEP_COND; + } + else if (opcode < 0x3500) + { + util::stream_format(stream, "%-8s", "MULWF"); + format_register(stream, opcode & 0x00ff); + } + else + util::stream_format(stream, "%-8s%04Xh", "DW", opcode); + } + else if (opcode >= 0x0100) + { + // Byte-oriented file register operations + util::stream_format(stream, "%-8s", s_alu_ops[BIT(opcode, 9, 5)]); + format_register(stream, opcode & 0x00ff); + if (opcode >= 0x0200) + util::stream_format(stream, ",%c", BIT(opcode, 8) ? 'F' : 'W'); + if ((opcode & 0x3600) == 0x1600 || (opcode & 0x3c00) == 0x2400) + words |= STEP_COND; + } + else switch (opcode) + { + case 0x0000: + stream << "NOP"; + break; + + case 0x0002: + stream << "RETURN"; + words |= STEP_OUT; + break; + + case 0x0003: + stream << "SLEEP"; + break; + + case 0x0004: + stream << "CLRWDT"; + break; + + case 0x0005: + stream << "RETFIE"; + words |= STEP_OUT; + break; + + default: + util::stream_format(stream, "%-8s%04Xh", "DW", opcode); + break; + } + + return words | SUPPORTED; +} |