summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Olivier Galibert <galibert@pobox.com>2020-03-28 19:45:28 +0100
committer Olivier Galibert <galibert@pobox.com>2020-03-28 19:45:41 +0100
commitd35c3977c9dfaf07a0bc5d026d08ba38e5dc50db (patch)
treea6b48e3ad31b310efcdd1d22aa8c20e6ba3b9aed
parentfa530a8625bf853a388f61627e65035cc4da0669 (diff)
unidasm: Add pic16 generic disassembler with extended instructions [O. Galibert]
-rw-r--r--scripts/src/cpu.lua10
-rw-r--r--src/devices/cpu/pic16/pic16d.cpp174
-rw-r--r--src/devices/cpu/pic16/pic16d.h39
-rw-r--r--src/tools/unidasm.cpp2
4 files changed, 225 insertions, 0 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua
index 774511e1881..a0dbdb27e35 100644
--- a/scripts/src/cpu.lua
+++ b/scripts/src/cpu.lua
@@ -1291,6 +1291,16 @@ if (CPUS["PIC16C62X"]~=null or _OPTIONS["with-tools"]) then
end
--------------------------------------------------
+-- Generic PIC16 - Disassembler only
+--@src/devices/cpu/pic16/pic16.h,CPUS["PIC16"] = true
+--------------------------------------------------
+
+if (CPUS["PIC16"]~=null or _OPTIONS["with-tools"]) then
+ table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/pic16/pic16d.cpp")
+ table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/pic16/pic16d.h")
+end
+
+--------------------------------------------------
-- MIPS R3000 (MIPS I/II) series
--@src/devices/cpu/mips/mips1.h,CPUS["MIPS1"] = true
--------------------------------------------------
diff --git a/src/devices/cpu/pic16/pic16d.cpp b/src/devices/cpu/pic16/pic16d.cpp
new file mode 100644
index 00000000000..65f28f863cd
--- /dev/null
+++ b/src/devices/cpu/pic16/pic16d.cpp
@@ -0,0 +1,174 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// PIC16 generic disassembler, with extended opcodes
+
+#include "emu.h"
+#include "pic16d.h"
+
+u32 pic16_disassembler::opcode_alignment() const
+{
+ return 1;
+}
+
+std::string pic16_disassembler::freg(u16 opcode) const
+{
+ return util::string_format("f_%02x", opcode & 0x7f);
+}
+
+std::string pic16_disassembler::imm8(u16 opcode)
+{
+ return util::string_format("%02x", opcode & 0xff);
+}
+
+std::string pic16_disassembler::imm7(u16 opcode)
+{
+ return util::string_format("%02x", opcode & 0x7f);
+}
+
+std::string pic16_disassembler::imm6(u16 opcode)
+{
+ return util::string_format("%02x", opcode & 0x3f);
+}
+
+std::string pic16_disassembler::imm6s(u16 opcode)
+{
+ if(opcode & 0x20)
+ return util::string_format("-%02x", (-opcode) & 0x1f);
+ else
+ return util::string_format("%02x", opcode & 0x1f);
+}
+
+std::string pic16_disassembler::imm5(u16 opcode)
+{
+ return util::string_format("%02x", opcode & 0x1f);
+}
+
+std::string pic16_disassembler::rel9(u16 opcode, u16 pc)
+{
+ u16 off = opcode & 0x1ff;
+ if(off & 0x100)
+ off -= 0x200;
+ return util::string_format("%04x", (pc + off + 1) & 0x7fff);
+}
+
+std::string pic16_disassembler::abs11(u16 opcode, u16 pc) const
+{
+ return util::string_format("%04x", (pc & 0x7800) | (opcode & 0x7ff));
+}
+
+#define P std::ostream &stream, const pic16_disassembler *d, u16 opcode, u16 pc
+const pic16_disassembler::instruction pic16_disassembler::instructions[] {
+ { 0x0700, 0x3f80, [](P) -> u32 { util::stream_format(stream, "addwf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0780, 0x3f80, [](P) -> u32 { util::stream_format(stream, "addwf %s", d->freg(opcode)); return 1; } },
+ { 0x3d00, 0x3f80, [](P) -> u32 { util::stream_format(stream, "addwfc %s, w", d->freg(opcode)); return 1; } },
+ { 0x3d80, 0x3f80, [](P) -> u32 { util::stream_format(stream, "addwfc %s", d->freg(opcode)); return 1; } },
+ { 0x0500, 0x3f80, [](P) -> u32 { util::stream_format(stream, "andwf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0580, 0x3f80, [](P) -> u32 { util::stream_format(stream, "andwf %s", d->freg(opcode)); return 1; } },
+ { 0x3700, 0x3f80, [](P) -> u32 { util::stream_format(stream, "asrf %s, w", d->freg(opcode)); return 1; } },
+ { 0x3780, 0x3f80, [](P) -> u32 { util::stream_format(stream, "asrf %s", d->freg(opcode)); return 1; } },
+ { 0x3500, 0x3f80, [](P) -> u32 { util::stream_format(stream, "lslf %s, w", d->freg(opcode)); return 1; } },
+ { 0x3580, 0x3f80, [](P) -> u32 { util::stream_format(stream, "lslf %s", d->freg(opcode)); return 1; } },
+ { 0x3600, 0x3f80, [](P) -> u32 { util::stream_format(stream, "lsrf %s, w", d->freg(opcode)); return 1; } },
+ { 0x3680, 0x3f80, [](P) -> u32 { util::stream_format(stream, "lsrf %s", d->freg(opcode)); return 1; } },
+ { 0x0180, 0x3f80, [](P) -> u32 { util::stream_format(stream, "clrf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0100, 0x3ffc, [](P) -> u32 { util::stream_format(stream, "clrw" ); return 1; } },
+ { 0x0900, 0x3f80, [](P) -> u32 { util::stream_format(stream, "comf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0980, 0x3f80, [](P) -> u32 { util::stream_format(stream, "comf %s", d->freg(opcode)); return 1; } },
+ { 0x0300, 0x3f80, [](P) -> u32 { util::stream_format(stream, "decf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0380, 0x3f80, [](P) -> u32 { util::stream_format(stream, "decf %s", d->freg(opcode)); return 1; } },
+ { 0x0a00, 0x3f80, [](P) -> u32 { util::stream_format(stream, "incf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0a80, 0x3f80, [](P) -> u32 { util::stream_format(stream, "incf %s", d->freg(opcode)); return 1; } },
+ { 0x0400, 0x3f80, [](P) -> u32 { util::stream_format(stream, "iorwf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0480, 0x3f80, [](P) -> u32 { util::stream_format(stream, "iorwf %s", d->freg(opcode)); return 1; } },
+ { 0x0800, 0x3f80, [](P) -> u32 { util::stream_format(stream, "movf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0880, 0x3f80, [](P) -> u32 { util::stream_format(stream, "movf %s", d->freg(opcode)); return 1; } },
+ { 0x0080, 0x3f80, [](P) -> u32 { util::stream_format(stream, "movwf %s", d->freg(opcode)); return 1; } },
+ { 0x0d00, 0x3f80, [](P) -> u32 { util::stream_format(stream, "rlf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0d80, 0x3f80, [](P) -> u32 { util::stream_format(stream, "rlf %s", d->freg(opcode)); return 1; } },
+ { 0x0c00, 0x3f80, [](P) -> u32 { util::stream_format(stream, "rrf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0c80, 0x3f80, [](P) -> u32 { util::stream_format(stream, "rrf %s", d->freg(opcode)); return 1; } },
+ { 0x0200, 0x3f80, [](P) -> u32 { util::stream_format(stream, "subwf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0280, 0x3f80, [](P) -> u32 { util::stream_format(stream, "subwf %s", d->freg(opcode)); return 1; } },
+ { 0x3b00, 0x3f80, [](P) -> u32 { util::stream_format(stream, "subwfb %s, w", d->freg(opcode)); return 1; } },
+ { 0x3b80, 0x3f80, [](P) -> u32 { util::stream_format(stream, "subwfb %s", d->freg(opcode)); return 1; } },
+ { 0x0e00, 0x3f80, [](P) -> u32 { util::stream_format(stream, "swapf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0e80, 0x3f80, [](P) -> u32 { util::stream_format(stream, "swapf %s", d->freg(opcode)); return 1; } },
+ { 0x0600, 0x3f80, [](P) -> u32 { util::stream_format(stream, "xorwf %s, w", d->freg(opcode)); return 1; } },
+ { 0x0680, 0x3f80, [](P) -> u32 { util::stream_format(stream, "xorwf %s", d->freg(opcode)); return 1; } },
+
+ { 0x0b00, 0x3f80, [](P) -> u32 { util::stream_format(stream, "decfsz %s, w", d->freg(opcode)); return 1; } },
+ { 0x0b80, 0x3f80, [](P) -> u32 { util::stream_format(stream, "decfsz %s", d->freg(opcode)); return 1; } },
+ { 0x0f00, 0x3f80, [](P) -> u32 { util::stream_format(stream, "incfsz %s, w", d->freg(opcode)); return 1; } },
+ { 0x0f80, 0x3f80, [](P) -> u32 { util::stream_format(stream, "incfsz %s", d->freg(opcode)); return 1; } },
+
+ { 0x1000, 0x3c00, [](P) -> u32 { util::stream_format(stream, "bcf %d, %s", (opcode >> 7) & 7, d->freg(opcode)); return 1; } },
+ { 0x1400, 0x3c00, [](P) -> u32 { util::stream_format(stream, "bsf %d, %s", (opcode >> 7) & 7, d->freg(opcode)); return 1; } },
+
+ { 0x1800, 0x3c00, [](P) -> u32 { util::stream_format(stream, "btfsc %d, %s", (opcode >> 7) & 7, d->freg(opcode)); return 1; } },
+ { 0x1c00, 0x3c00, [](P) -> u32 { util::stream_format(stream, "btfss %d, %s", (opcode >> 7) & 7, d->freg(opcode)); return 1; } },
+
+ { 0x3e00, 0x3f00, [](P) -> u32 { util::stream_format(stream, "addlw %s", imm8(opcode)); return 1; } },
+ { 0x3900, 0x3f00, [](P) -> u32 { util::stream_format(stream, "andlw %s", imm8(opcode)); return 1; } },
+ { 0x3800, 0x3f00, [](P) -> u32 { util::stream_format(stream, "iorlw %s", imm8(opcode)); return 1; } },
+ { 0x0020, 0x3fe0, [](P) -> u32 { util::stream_format(stream, "movlb %s", imm5(opcode)); return 1; } },
+ { 0x3180, 0x3f80, [](P) -> u32 { util::stream_format(stream, "movlp %s", imm7(opcode)); return 1; } },
+ { 0x3000, 0x3f00, [](P) -> u32 { util::stream_format(stream, "movlw %s", imm8(opcode)); return 1; } },
+ { 0x3c00, 0x3f00, [](P) -> u32 { util::stream_format(stream, "sublw %s", imm8(opcode)); return 1; } },
+ { 0x3a00, 0x3f00, [](P) -> u32 { util::stream_format(stream, "xorlw %s", imm8(opcode)); return 1; } },
+
+ { 0x3200, 0x3e00, [](P) -> u32 { util::stream_format(stream, "bra %s", rel9(opcode, pc) ); return 1; } },
+ { 0x000b, 0x3fff, [](P) -> u32 { util::stream_format(stream, "brw" ); return 1; } },
+ { 0x2000, 0x3800, [](P) -> u32 { util::stream_format(stream, "call %s", d->abs11(opcode, pc)); return 1 | STEP_OVER; } },
+ { 0x000a, 0x3fff, [](P) -> u32 { util::stream_format(stream, "callw" ); return 1 | STEP_OVER; } },
+ { 0x2800, 0x3800, [](P) -> u32 { util::stream_format(stream, "goto %s", d->abs11(opcode, pc)); return 1; } },
+ { 0x0009, 0x3fff, [](P) -> u32 { util::stream_format(stream, "retfie" ); return 1 | STEP_OUT; } },
+ { 0x3400, 0x3f00, [](P) -> u32 { util::stream_format(stream, "retlw %s", imm8(opcode) ); return 1 | STEP_OUT; } },
+ { 0x0008, 0x3fff, [](P) -> u32 { util::stream_format(stream, "return" ); return 1 | STEP_OUT; } },
+
+ { 0x0064, 0x3fff, [](P) -> u32 { util::stream_format(stream, "clrwdt" ); return 1; } },
+ { 0x0000, 0x3fff, [](P) -> u32 { util::stream_format(stream, "nop" ); return 1; } },
+ { 0x0062, 0x3fff, [](P) -> u32 { util::stream_format(stream, "option" ); return 1; } },
+ { 0x0001, 0x3fff, [](P) -> u32 { util::stream_format(stream, "reset" ); return 1; } },
+ { 0x0063, 0x3fff, [](P) -> u32 { util::stream_format(stream, "sleep" ); return 1; } },
+ { 0x0065, 0x3fff, [](P) -> u32 { util::stream_format(stream, "tris a" ); return 1; } },
+ { 0x0066, 0x3fff, [](P) -> u32 { util::stream_format(stream, "tris b" ); return 1; } },
+ { 0x0067, 0x3fff, [](P) -> u32 { util::stream_format(stream, "tris c" ); return 1; } },
+
+ { 0x3100, 0x3fc0, [](P) -> u32 { util::stream_format(stream, "addfsr fsr0, %s", imm6(opcode)); return 1; } },
+ { 0x3140, 0x3fc0, [](P) -> u32 { util::stream_format(stream, "addfsr fsr1, %s", imm6(opcode)); return 1; } },
+ { 0x0010, 0xffff, [](P) -> u32 { util::stream_format(stream, "moviw ++fsr0" ); return 1; } },
+ { 0x0011, 0xffff, [](P) -> u32 { util::stream_format(stream, "moviw --fsr0" ); return 1; } },
+ { 0x0012, 0xffff, [](P) -> u32 { util::stream_format(stream, "moviw fsr0++" ); return 1; } },
+ { 0x0013, 0xffff, [](P) -> u32 { util::stream_format(stream, "moviw fsr0--" ); return 1; } },
+ { 0x0014, 0xffff, [](P) -> u32 { util::stream_format(stream, "moviw ++fsr1" ); return 1; } },
+ { 0x0015, 0xffff, [](P) -> u32 { util::stream_format(stream, "moviw --fsr1" ); return 1; } },
+ { 0x0016, 0xffff, [](P) -> u32 { util::stream_format(stream, "moviw fsr1++" ); return 1; } },
+ { 0x0017, 0xffff, [](P) -> u32 { util::stream_format(stream, "moviw fsr1--" ); return 1; } },
+ { 0x3f00, 0xffc0, [](P) -> u32 { util::stream_format(stream, "moviw %s[fsr0]", imm6s(opcode)); return 1; } },
+ { 0x3f40, 0xffc0, [](P) -> u32 { util::stream_format(stream, "moviw %s[fsr1]", imm6s(opcode)); return 1; } },
+ { 0x0018, 0xffff, [](P) -> u32 { util::stream_format(stream, "movwi ++fsr0" ); return 1; } },
+ { 0x0019, 0xffff, [](P) -> u32 { util::stream_format(stream, "movwi --fsr0" ); return 1; } },
+ { 0x001a, 0xffff, [](P) -> u32 { util::stream_format(stream, "movwi fsr0++" ); return 1; } },
+ { 0x001b, 0xffff, [](P) -> u32 { util::stream_format(stream, "movwi fsr0--" ); return 1; } },
+ { 0x001c, 0xffff, [](P) -> u32 { util::stream_format(stream, "movwi ++fsr1" ); return 1; } },
+ { 0x001d, 0xffff, [](P) -> u32 { util::stream_format(stream, "movwi --fsr1" ); return 1; } },
+ { 0x001e, 0xffff, [](P) -> u32 { util::stream_format(stream, "movwi fsr1++" ); return 1; } },
+ { 0x001f, 0xffff, [](P) -> u32 { util::stream_format(stream, "movwi fsr1--" ); return 1; } },
+ { 0x3f80, 0xffc0, [](P) -> u32 { util::stream_format(stream, "movwi %s[fsr0]", imm6s(opcode)); return 1; } },
+ { 0x3fc0, 0xffc0, [](P) -> u32 { util::stream_format(stream, "movwi %s[fsr1]", imm6s(opcode)); return 1; } },
+
+ { 0x0000, 0x0000, [](P) -> u32 { util::stream_format(stream, "?%04x", opcode); return 1; } },
+};
+
+#undef P
+
+offs_t pic16_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
+{
+ u16 opcode = opcodes.r16(pc);
+
+ for(u32 i=0;; i++)
+ if((opcode & instructions[i].mask) == instructions[i].value)
+ return instructions[i].cb(stream, this, opcode, pc) | SUPPORTED;
+ return 0;
+}
diff --git a/src/devices/cpu/pic16/pic16d.h b/src/devices/cpu/pic16/pic16d.h
new file mode 100644
index 00000000000..4dc5cd55621
--- /dev/null
+++ b/src/devices/cpu/pic16/pic16d.h
@@ -0,0 +1,39 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// PIC16 generic disassembler, with extended opcodes
+
+#ifndef MAME_CPU_PIC16_PIC16D_H
+#define MAME_CPU_PIC16_PIC16D_H
+
+#pragma once
+
+class pic16_disassembler : public util::disasm_interface
+{
+public:
+ pic16_disassembler() = default;
+ virtual ~pic16_disassembler() = default;
+
+ virtual u32 opcode_alignment() const override;
+ virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
+
+private:
+ struct instruction {
+ u16 value;
+ u16 mask;
+ u32 (*cb)(std::ostream &, const pic16_disassembler *, u16, u16);
+ };
+
+ static const instruction instructions[];
+
+ std::string freg(u16 opcode) const;
+ static std::string imm8(u16 opcode);
+ static std::string imm7(u16 opcode);
+ static std::string imm6(u16 opcode);
+ static std::string imm6s(u16 opcode);
+ static std::string imm5(u16 opcode);
+ static std::string rel9(u16 opcode, u16 pc);
+ std::string abs11(u16 opcode, u16 pc) const;
+};
+
+#endif // MAME_CPU_PIC16_PIC16D_H
diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp
index d82d2cf5792..91082741c8d 100644
--- a/src/tools/unidasm.cpp
+++ b/src/tools/unidasm.cpp
@@ -116,6 +116,7 @@ using util::BIT;
#include "cpu/pdp1/pdp1dasm.h"
#include "cpu/pdp1/tx0dasm.h"
#include "cpu/pdp8/pdp8dasm.h"
+#include "cpu/pic16/pic16d.h"
#include "cpu/pic16c5x/16c5xdsm.h"
#include "cpu/pic16c62x/16c62xdsm.h"
#include "cpu/powerpc/ppc_dasm.h"
@@ -467,6 +468,7 @@ static const dasm_table_entry dasm_table[] =
{ "patinho_feio", le, 0, []() -> util::disasm_interface * { return new patinho_feio_disassembler; } },
{ "pdp1", be, 0, []() -> util::disasm_interface * { return new pdp1_disassembler; } },
{ "pdp8", be, 0, []() -> util::disasm_interface * { return new pdp8_disassembler; } },
+ { "pic16", le, -1, []() -> util::disasm_interface * { return new pic16_disassembler; } },
{ "pic16c5x", le, -1, []() -> util::disasm_interface * { return new pic16c5x_disassembler; } },
{ "pic16c62x", le, -1, []() -> util::disasm_interface * { return new pic16c62x_disassembler; } },
{ "powerpc", be, 0, []() -> util::disasm_interface * { return new powerpc_disassembler; } },