summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/cpu.lua17
-rw-r--r--src/devices/cpu/palm/palm.cpp280
-rw-r--r--src/devices/cpu/palm/palm.h69
-rw-r--r--src/devices/cpu/palm/palmd.cpp179
-rw-r--r--src/devices/cpu/palm/palmd.h19
-rw-r--r--src/tools/unidasm.cpp2
6 files changed, 566 insertions, 0 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua
index 6c4d5b9a5c4..f2fd8127e77 100644
--- a/scripts/src/cpu.lua
+++ b/scripts/src/cpu.lua
@@ -3989,3 +3989,20 @@ if opt_tool(CPUS, "C33") then
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/c33/c33dasm.cpp")
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/c33/c33dasm.h")
end
+
+--------------------------------------------------
+-- IBM PALM
+--@src/devices/cpu/palm/palm.h,CPUS["PALM"] = true
+--------------------------------------------------
+
+if CPUS["PALM"] then
+ files {
+ MAME_DIR .. "src/devices/cpu/palm/palm.cpp",
+ MAME_DIR .. "src/devices/cpu/palm/palm.h",
+ }
+end
+
+if opt_tool(CPUS, "PALM") then
+ table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/palm/palmd.cpp")
+ table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/palm/palmd.h")
+end
diff --git a/src/devices/cpu/palm/palm.cpp b/src/devices/cpu/palm/palm.cpp
new file mode 100644
index 00000000000..4e7558770d6
--- /dev/null
+++ b/src/devices/cpu/palm/palm.cpp
@@ -0,0 +1,280 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * IBM PALM (apparently "Put All Logic in Microcode") single-card microprocessor.
+ *
+ * Sources:
+ * - IBM 5100 Maintenance Information Manual, SY31-0405-3, Fourth Edition (October 1979), International Business Machines Corporation
+ *
+ * TODO:
+ * - machine check/interrupts
+ * - instruction timing
+ */
+
+#include "emu.h"
+#include "palm.h"
+#include "palmd.h"
+
+//#define VERBOSE (LOG_GENERAL)
+#include "logmacro.h"
+
+ // helpers for IBM bit numbering
+template <typename T, typename U> constexpr T IBIT(T x, U n) noexcept
+{
+ return BIT(x, sizeof(T) * 8 - n - 1);
+}
+
+template <typename T, typename U, typename V> constexpr T IBIT(T x, U n, V w)
+{
+ return BIT(x, sizeof(T) * 8 - n - w, w);
+}
+
+DEFINE_DEVICE_TYPE(PALM, palm_device, "palm", "IBM PALM")
+
+palm_device::palm_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : cpu_device(mconfig, PALM, tag, owner, clock)
+ , m_ros_config("ros", ENDIANNESS_BIG, 16, 16)
+ , m_rws_config("rws", ENDIANNESS_BIG, 16, 16)
+ , m_ioc_config("ioc", ENDIANNESS_BIG, 8, 4)
+ , m_iod_config("iod", ENDIANNESS_BIG, 8, 4)
+ , m_icount(0)
+ , m_r{}
+ , m_il(0)
+ , m_il_pending(0)
+ , m_irpt_req(0)
+{
+}
+
+void palm_device::device_start()
+{
+ set_icountptr(m_icount);
+
+ state_add(STATE_GENPC, "GENPC", m_r[m_il][0]).mask(0xfffe).noshow();
+ state_add(STATE_GENPCBASE, "CURPC", m_r[m_il][0]).mask(0xfffe);
+
+ state_add(0, "IL", m_il);
+ for (unsigned i = 0; i < std::size(m_r[m_il]); i++)
+ state_add(i + 1, util::string_format("R%d", i).c_str(), m_r[m_il][i]);
+
+ save_item(NAME(m_r));
+ save_item(NAME(m_il));
+ save_item(NAME(m_il_pending));
+ save_item(NAME(m_irpt_req));
+
+ space(AS_ROS).specific(m_ros);
+ space(AS_RWS).specific(m_rws);
+ space(AS_IOC).specific(m_ioc);
+ space(AS_IOD).specific(m_iod);
+}
+
+void palm_device::device_reset()
+{
+ space(AS_RWS).install_ram(0, sizeof(m_r) - 1, m_r);
+
+ m_il = 0;
+
+ // read initial PC from ROS
+ m_r[m_il][0] = m_ros.read_word(0);
+}
+
+#define Rx r[IBIT(op, 4, 4)]
+#define Ry r[IBIT(op, 8, 4)]
+#define DA IBIT(op, 4, 4)
+#define IMM IBIT(op, 8, 8)
+#define MOD IBIT(op, 12, 4)
+
+void palm_device::execute_run()
+{
+ while (m_icount > 0)
+ {
+ // immediately switch to highest pending interrupt level
+ if (m_il != m_il_pending)
+ {
+ m_il = m_il_pending;
+
+ // notify the debugger
+ if (m_il && machine().debug_flags & DEBUG_FLAG_ENABLED)
+ debug()->interrupt_hook(m_il - 1, m_r[m_il][0] & ~1);
+ }
+
+ // select active register bank
+ u16 (&r)[16] = m_r[m_il];
+
+ // notify the debugger
+ debugger_instruction_hook(r[0] & ~1);
+
+ // fetch instruction
+ u16 const op = m_ros.read_word(r[0] & ~1);
+
+ // increment instruction address register
+ r[0] += 2;
+
+ switch (IBIT(op, 0, 4))
+ {
+ case 0x0:
+ switch (IBIT(op, 12, 4))
+ {
+ case 0x0: Rx = Ry - 2; break; // move minus 2
+ case 0x1: Rx = Ry - 1; break; // move minus 1
+ case 0x2: Rx = Ry + 1; break; // move plus 1
+ case 0x3: Rx = Ry + 2; break; // move plus 2
+ case 0x4: Rx = Ry; break; // move register
+ case 0x5: Rx &= 0xff00U | u8(Ry); break; // and byte
+ case 0x6: Rx |= u8(Ry); break; // or byte
+ case 0x7: Rx ^= u8(Ry); break; // xor byte
+ case 0x8: Rx += u8(Ry); break; // add
+ case 0x9: Rx -= u8(Ry); break; // subtract
+ case 0xa: Rx = u8(Ry) + (Rx >> 8); break; // add special #1
+ case 0xb: Rx = u8(Ry) + (Rx >> 8) - 0x100; break; // add special #2
+ case 0xc: Rx = (Rx & 0xff00U) | (Ry >> 8); break; // high to low
+ case 0xd: Rx = (Rx & 0x00ffU) | (Ry << 8); break; // low to high
+ case 0xe: Ry = (Ry & 0xff00U) | m_iod.read_byte(DA); break; // get to register
+ case 0xf: Ry += (7 - count_leading_ones_32(u32(m_iod.read_byte(DA)) << 24)) * 2; break; // get to register and add
+ }
+ break;
+ case 0x1: m_ioc.write_byte(DA, IMM); break; // control
+ case 0x2: Rx = m_rws.read_word(IMM * 2); break; // load halfword direct
+ case 0x3: m_rws.write_word(IMM * 2, Rx); break; // store halfword direct
+ case 0x4:
+ // put byte
+ m_iod.write_byte(DA, m_rws.read_byte(Ry));
+ Ry += modifier(MOD);
+ break;
+ case 0x5:
+ // store halfword indirect
+ m_rws.write_word(Ry, Rx);
+ Ry += modifier(MOD);
+ break;
+ case 0x6:
+ // load byte indirect
+ Rx = m_rws.read_byte(Ry);
+ Ry += modifier(MOD);
+ break;
+ case 0x7:
+ // store byte indirect
+ m_rws.write_byte(Ry, Rx);
+ Ry += modifier(MOD);
+ break;
+ case 0x8: Rx = (Rx & 0xff00U) | IMM; break; // emit byte
+ case 0x9: Rx &= ~IMM; break; // clear immediate
+ case 0xa: Rx += IMM + 1; break; // add immediate
+ case 0xb: Rx |= IMM; break; // set immediate
+ case 0xc:
+ // jump (skip next on condition)
+ if (condition(MOD, Rx, Ry))
+ r[0] += 2;
+ else
+ r[1] = r[0] + 2;
+ break;
+ case 0xd:
+ // load halfword indirect
+ Rx = m_rws.read_word(Ry);
+ Ry += modifier(MOD);
+ break;
+ case 0xe:
+ if (DA == 0 && MOD >= 0xc)
+ {
+ switch (MOD)
+ {
+ case 0xc: Ry = (Ry & 0xff00U) | u8(Ry >> 1); break; // shift right 1
+ case 0xd: Ry = (Ry & 0xff00U) | u8(Ry << 7) | u8(Ry) >> 1; break; // shift right and rotate 1
+ case 0xe: Ry = (Ry & 0xff00U) | u8(Ry << 5) | u8(Ry) >> 3; break; // shift right and rotate 3
+ case 0xf: Ry = (Ry & 0xff00U) | u8(Ry << 4) | u8(Ry) >> 4; break; // shift right and rotate 4
+ }
+ }
+ else
+ {
+ if (MOD < 0xc)
+ {
+ // get byte
+ m_rws.write_byte(Ry, m_iod.read_byte(DA));
+ Ry += modifier(MOD);
+ }
+ else
+ // get register byte
+ Ry = (Ry & 0xff00U) | m_ioc.read_byte(DA);
+ }
+ break;
+ case 0xf: Rx -= IMM + 1; break; // subtract immediate
+ }
+
+ // TODO: average instruction time quoted as 1.75µs (~27 machine cycles)
+ m_icount -= 27;
+ }
+}
+
+void palm_device::execute_set_input(int irqline, int state)
+{
+ u8 const il_priority[] = { 0, 1, 2, 3, 3, 3, 3, 3 };
+
+ switch (irqline)
+ {
+ case INPUT_LINE_NMI:
+ // TODO: machine check
+ break;
+
+ default:
+ // interrupt lines are active low
+ if (!state)
+ m_irpt_req |= 1U << irqline;
+ else
+ m_irpt_req &= ~(1U << irqline);
+
+ // update pending interrupt level
+ m_il_pending = il_priority[m_irpt_req & 7];
+ break;
+ }
+}
+
+device_memory_interface::space_config_vector palm_device::memory_space_config() const
+{
+ return space_config_vector
+ {
+ std::make_pair(AS_ROS, &m_ros_config),
+ std::make_pair(AS_RWS, &m_rws_config),
+ std::make_pair(AS_IOC, &m_ioc_config),
+ std::make_pair(AS_IOD, &m_iod_config),
+ };
+}
+
+std::unique_ptr<util::disasm_interface> palm_device::create_disassembler()
+{
+ return std::make_unique<palm_disassembler>();
+}
+
+bool palm_device::condition(unsigned const modifier, u16 const data, u8 const mask) const
+{
+ switch (modifier)
+ {
+ case 0x0: return u8(data) <= mask; // le: low or equal
+ case 0x1: return u8(data) < mask; // lo: low
+ case 0x2: return u8(data) == mask; // eq: equal
+ case 0x3: return u8(data) == 0x00; // no: no ones
+ case 0x4: return u8(data) == 0xff; // all: all ones
+ case 0x5: return u8(data & mask) == mask; // allm: all masked
+ case 0x6: return u8(data & mask) == 0x00; // nom: no ones masked
+ case 0x7: return u8((data >> 8) & mask) == mask; // ham: high all masked
+ case 0x8: return u8(data) > mask; // hi: high
+ case 0x9: return u8(data) >= mask; // he: high or equal
+ case 0xa: return u8(data) != mask; // hl: high or low
+ case 0xb: return u8(data) != 0x00; // sb: some bits
+ case 0xc: return u8(data) != 0xff; // sn: some not ones
+ case 0xd: return u8(data & mask) != mask; // snm: some not masked
+ case 0xe: return u8(data & mask) != 0x00; // sm: some masked
+ case 0xf: return u8((data >> 8) & mask) != mask; // hsnm: high some bit not masked
+ default:
+ // can't happen
+ abort();
+ }
+}
+
+s16 palm_device::modifier(unsigned const modifier) const
+{
+ if (modifier < 4)
+ return (modifier & 3) + 1;
+ else if (modifier < 8)
+ return -((modifier & 3) + 1);
+ else
+ return 0;
+}
diff --git a/src/devices/cpu/palm/palm.h b/src/devices/cpu/palm/palm.h
new file mode 100644
index 00000000000..ff2bc0c6d08
--- /dev/null
+++ b/src/devices/cpu/palm/palm.h
@@ -0,0 +1,69 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_CPU_PALM_PALM_H
+#define MAME_CPU_PALM_PALM_H
+
+#pragma once
+
+class palm_device : public cpu_device
+{
+public:
+ // interrupt lines are numbered 1..3
+ static unsigned constexpr IRPT_REQ1 = INPUT_LINE_IRQ0;
+ static unsigned constexpr IRPT_REQ2 = INPUT_LINE_IRQ1;
+ static unsigned constexpr IRPT_REQ3 = INPUT_LINE_IRQ2;
+
+ // four address spaces
+ static unsigned constexpr AS_ROS = AS_PROGRAM;
+ static unsigned constexpr AS_RWS = AS_DATA;
+ static unsigned constexpr AS_IOC = AS_IO;
+ static unsigned constexpr AS_IOD = 4;
+
+ palm_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+protected:
+ // device_t implementation
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_execute_interface implementation
+ virtual u32 execute_min_cycles() const noexcept override { return 17; }
+ virtual u32 execute_max_cycles() const noexcept override { return 54; }
+ virtual u32 execute_input_lines() const noexcept override { return 3; }
+ virtual void execute_run() override;
+ virtual void execute_set_input(int inputnum, int state) override;
+
+ // device_memory_interface implementation
+ virtual space_config_vector memory_space_config() const override;
+
+ // device_disasm_interface implementation
+ virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
+
+ bool condition(unsigned const modifier, u16 const data, u8 const mask) const;
+ s16 modifier(unsigned const modifier) const;
+
+private:
+ // address spaces
+ address_space_config const m_ros_config;
+ address_space_config const m_rws_config;
+ address_space_config const m_ioc_config;
+ address_space_config const m_iod_config;
+
+ memory_access<16, 1, 0, ENDIANNESS_BIG>::specific m_ros;
+ memory_access<16, 1, 0, ENDIANNESS_BIG>::specific m_rws;
+ memory_access<4, 0, 0, ENDIANNESS_BIG>::specific m_ioc;
+ memory_access<4, 0, 0, ENDIANNESS_BIG>::specific m_iod;
+
+ // mame state
+ int m_icount;
+
+ u16 m_r[4][16]; // registers
+ u8 m_il; // interrupt level
+ u8 m_il_pending; // pending interrupt level
+ u8 m_irpt_req; // interrupt line state
+};
+
+DECLARE_DEVICE_TYPE(PALM, palm_device)
+
+#endif // MAME_CPU_PALM_PALM_H
diff --git a/src/devices/cpu/palm/palmd.cpp b/src/devices/cpu/palm/palmd.cpp
new file mode 100644
index 00000000000..39b6c358971
--- /dev/null
+++ b/src/devices/cpu/palm/palmd.cpp
@@ -0,0 +1,179 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#include "emu.h"
+#include "palmd.h"
+
+static const char *const r[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
+static const char *const jm[] = { "le", "lo", "eq", "no", "all", "allm", "nom", "ham", "hi", "he", "hl", "sb", "sn", "snm", "sm", "hsnm" };
+static const char *const im[] = { "+1", "+2", "+3", "+4", "-1", "-2", "-3", "-4" };
+
+// helper for IBM bit numbering
+template <typename T, typename U, typename V> constexpr T IBIT(T x, U n, V w)
+{
+ return BIT(x, sizeof(T) * 8 - n - w, w);
+}
+
+// instruction field shorthand
+#define Rx r[IBIT(op, 4, 4)]
+#define Ry r[IBIT(op, 8, 4)]
+#define DA IBIT(op, 4, 4)
+#define IMM IBIT(op, 8, 8)
+#define MOD IBIT(op, 12, 4)
+
+offs_t palm_disassembler::disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const &params)
+{
+ u16 const op = opcodes.r16(pc);
+ u32 flags = 0;
+
+ pc += 2;
+
+ switch (IBIT(op, 0, 4))
+ {
+ case 0x0:
+ switch (MOD)
+ {
+ case 0x0:
+ if (IBIT(op, 4, 8))
+ // move minus 2
+ util::stream_format(stream, "mvm2 %s,%s", Rx, Ry);
+ else
+ // synthetic halt (branch to self)
+ util::stream_format(stream, "halt");
+ break;
+ case 0x1: util::stream_format(stream, "mvm1 %s,%s", Rx, Ry); break; // move minus 1
+ case 0x2: util::stream_format(stream, "mvp1 %s,%s", Rx, Ry); break; // move plus 1
+ case 0x3: util::stream_format(stream, "mvp2 %s,%s", Rx, Ry); break; // move plus 2
+ case 0x4:
+ if (Rx)
+ // move register
+ util::stream_format(stream, "move %s,%s", Rx, Ry);
+ else if (Ry)
+ {
+ // synthetic jump to register
+ util::stream_format(stream, "jump %s", Ry);
+ flags |= STEP_COND;
+ }
+ else // synthetic no operation
+ util::stream_format(stream, "noop");
+ break;
+ case 0x5: util::stream_format(stream, "and %s,%s", Rx, Ry); break; // and byte
+ case 0x6: util::stream_format(stream, "orb %s,%s", Rx, Ry); break; // or byte
+ case 0x7: util::stream_format(stream, "xor %s,%s", Rx, Ry); break; // xor byte
+ case 0x8: util::stream_format(stream, "add %s,%s", Rx, Ry); break; // add
+ case 0x9: util::stream_format(stream, "sub %s,%s", Rx, Ry); break; // subtract
+ case 0xa: util::stream_format(stream, "adds1 %s,%s", Rx, Ry); break; // add special #1
+ case 0xb: util::stream_format(stream, "adds2 %s,%s", Rx, Ry); break; // add special #2
+ case 0xc: util::stream_format(stream, "htl %s,%s", Rx, Ry); break; // high to low
+ case 0xd: util::stream_format(stream, "lth %s,%s", Rx, Ry); break; // low to high
+ case 0xe: util::stream_format(stream, "getr $%x,%s", DA, Ry); break; // get to register
+ case 0xf: util::stream_format(stream, "geta $%x,%s", DA, Ry); break; // get to register and add
+ }
+ break;
+ case 0x1: util::stream_format(stream, "ctl $%x,#$%x", DA, IMM); break; // control
+ case 0x2: util::stream_format(stream, "ldhd %s,$%x", Rx, IMM * 2); break; // load halfword direct
+ case 0x3: util::stream_format(stream, "sthd %s,$%x", Rx, IMM * 2); break; // store halfword direct
+ case 0x4:
+ // put byte
+ if (MOD < 8)
+ util::stream_format(stream, "putb $%x,%s,%s", DA, Ry, im[MOD]);
+ else
+ util::stream_format(stream, "putb $%x,%s", DA, Ry);
+ break;
+ case 0x5:
+ // store halfword indirect
+ if (MOD < 8)
+ util::stream_format(stream, "sthi %s,%s,%s", Rx, Ry, im[MOD]);
+ else
+ util::stream_format(stream, "sthi %s,%s", Rx, Ry);
+ break;
+ case 0x6:
+ // load byte indirect
+ if (MOD < 8)
+ util::stream_format(stream, "ldbi %s,%s,%s", Rx, Ry, im[MOD]);
+ else
+ util::stream_format(stream, "ldbi %s,%s", Rx, Ry);
+ break;
+ case 0x7:
+ // store byte indirect
+ if (MOD < 8)
+ util::stream_format(stream, "stbi %s,%s,%s", Rx, Ry, im[MOD]);
+ else
+ util::stream_format(stream, "stbi %s,%s", Rx, Ry);
+ break;
+ case 0x8: util::stream_format(stream, "emit %s,#$%x", Rx, IMM); break; // emit byte
+ case 0x9: util::stream_format(stream, "clri %s,#$%x", Rx, IMM); break; // clear immediate
+ case 0xa:
+ if (Rx)
+ // add immediate
+ util::stream_format(stream, "addi %s,#$%x", Rx, IMM + 1);
+ else
+ {
+ // synthetic jump relative (forward)
+ util::stream_format(stream, "jump $%x", pc + IMM + 1);
+ flags |= STEP_COND;
+ }
+ break;
+ case 0xb: util::stream_format(stream, "seti %s,#$%x", Rx, IMM); break; // set immediate
+ case 0xc:
+ switch (MOD)
+ {
+ case 0x3: case 0x4: case 0xb: case 0xc:
+ // one-operand jumps
+ util::stream_format(stream, "j%-4s %s", jm[MOD], Rx);
+ break;
+ case 0x0: case 0x1: case 0x2: case 0x5:
+ case 0x6: case 0x7: case 0x8: case 0x9:
+ case 0xa: case 0xd: case 0xe: case 0xf:
+ // two-operand jumps
+ util::stream_format(stream, "j%-4s %s,%s", jm[MOD], Rx, Ry);
+ break;
+ }
+ flags |= STEP_COND;
+ break;
+ case 0xd:
+ // load halfword indirect
+ if (MOD < 8)
+ util::stream_format(stream, "ldhi %s,%s,%s", Rx, Ry, im[MOD]);
+ else
+ util::stream_format(stream, "ldhi %s,%s", Rx, Ry);
+ break;
+ case 0xe:
+ if (DA == 0 && MOD >= 0xc)
+ {
+ switch (MOD)
+ {
+ case 0xc: util::stream_format(stream, "shftr %s", Ry); break; // shift right 1
+ case 0xd: util::stream_format(stream, "rotr %s", Ry); break; // shift right and rotate 1
+ case 0xe: util::stream_format(stream, "srr3 %s", Ry); break; // shift right and rotate 3
+ case 0xf: util::stream_format(stream, "srr4 %s", Ry); break; // shift right and rotate 4
+ }
+ }
+ else
+ {
+ if (MOD < 0x8)
+ // get byte
+ util::stream_format(stream, "getb $%x,%s,%s", DA, Ry, im[MOD]);
+ else if (MOD < 0xc)
+ // get byte
+ util::stream_format(stream, "getb $%x,%s", DA, Ry);
+ else
+ // get register byte
+ util::stream_format(stream, "getrb $%x,%s", DA, Ry);
+ }
+ break;
+ case 0xf:
+ if (Rx)
+ // subtract immediate
+ util::stream_format(stream, "subi %s,#$%x", Rx, IMM + 1);
+ else
+ {
+ // synthetic jump relative (backward)
+ util::stream_format(stream, "jump $%x", pc - IMM - 1);
+ flags |= STEP_COND;
+ }
+ break;
+ }
+
+ return 2 | flags | SUPPORTED;
+}
diff --git a/src/devices/cpu/palm/palmd.h b/src/devices/cpu/palm/palmd.h
new file mode 100644
index 00000000000..773fd9a5edc
--- /dev/null
+++ b/src/devices/cpu/palm/palmd.h
@@ -0,0 +1,19 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_CPU_PALM_PALMD_H
+#define MAME_CPU_PALM_PALMD_H
+
+#pragma once
+
+class palm_disassembler : public util::disasm_interface
+{
+public:
+ palm_disassembler() = default;
+ virtual ~palm_disassembler() = default;
+
+ virtual offs_t disassemble(std::ostream &stream, offs_t pc, data_buffer const &opcodes, data_buffer const &params) override;
+ virtual u32 opcode_alignment() const override { return 2; }
+};
+
+#endif // MAME_CPU_PALM_PALMD_H
diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp
index cd68c78adee..a8fd8a97649 100644
--- a/src/tools/unidasm.cpp
+++ b/src/tools/unidasm.cpp
@@ -135,6 +135,7 @@ using util::BIT;
#include "cpu/ns32000/ns32000d.h"
#include "cpu/nuon/nuondasm.h"
#include "cpu/pace/pacedasm.h"
+#include "cpu/palm/palmd.h"
#include "cpu/patinhofeio/patinho_feio_dasm.h"
#include "cpu/pdp1/pdp1dasm.h"
#include "cpu/pdp8/pdp8dasm.h"
@@ -566,6 +567,7 @@ static const dasm_table_entry dasm_table[] =
{ "p8xc552", le, 0, []() -> util::disasm_interface * { return new p8xc552_disassembler; } },
{ "p8xc562", le, 0, []() -> util::disasm_interface * { return new p8xc562_disassembler; } },
{ "pace", le, -1, []() -> util::disasm_interface * { return new pace_disassembler; } },
+ { "palm", be, 0, []() -> util::disasm_interface * { return new palm_disassembler; } },
{ "patinho_feio", le, 0, []() -> util::disasm_interface * { return new patinho_feio_disassembler; } },
{ "pdp1", be, -2, []() -> util::disasm_interface * { return new pdp1_disassembler; } },
{ "pdp8", be, -1, []() -> util::disasm_interface * { return new pdp8_disassembler; } },