summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/pic17/pic17d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/pic17/pic17d.cpp')
-rw-r--r--src/devices/cpu/pic17/pic17d.cpp244
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 &params)
+{
+ 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;
+}