summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/clipper
diff options
context:
space:
mode:
author Patrick Mackinlay <pmackinlay@hotmail.com>2016-12-27 11:24:33 +0700
committer Patrick Mackinlay <pmackinlay@hotmail.com>2016-12-27 11:24:33 +0700
commitf4f7d659a1e7461ec1ef33534a61df8fe1dc1ee3 (patch)
treeb634eeb368c79c8c6b73944a67ea0d07cc93b3fb /src/devices/cpu/clipper
parent47a690bef71e27f72d5b0f86c6308d8a16539a21 (diff)
initial commit
Diffstat (limited to 'src/devices/cpu/clipper')
-rw-r--r--src/devices/cpu/clipper/clipper.cpp871
-rw-r--r--src/devices/cpu/clipper/clipper.h165
-rw-r--r--src/devices/cpu/clipper/clipperd.cpp239
3 files changed, 1275 insertions, 0 deletions
diff --git a/src/devices/cpu/clipper/clipper.cpp b/src/devices/cpu/clipper/clipper.cpp
new file mode 100644
index 00000000000..be80487c041
--- /dev/null
+++ b/src/devices/cpu/clipper/clipper.cpp
@@ -0,0 +1,871 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#include "emu.h"
+#include "debugger.h"
+#include "clipper.h"
+
+#define SSP_HACK 0
+
+#define VERBOSE 0
+#if VERBOSE
+#define LOG_INTERRUPT(...) logerror(__VA_ARGS__)
+#else
+#define LOG_INTERRUPT(...)
+#endif
+
+
+const device_type CLIPPER = &device_creator<clipper_device>;
+
+clipper_device::clipper_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : cpu_device(mconfig, CLIPPER, "c400", tag, owner, clock, "c400", __FILE__),
+ m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0),
+ m_program(nullptr),
+ m_direct(nullptr),
+ m_pc(0),
+ m_icount(0),
+ m_interrupt_cycles(0)
+{
+}
+
+void clipper_device::device_start()
+{
+ // get our address spaces
+ m_program = &space(AS_PROGRAM);
+ m_direct = &m_program->direct();
+
+ // set our instruction counter
+ m_icountptr = &m_icount;
+
+ //save_item(NAME(m_pc));
+
+ state_add(STATE_GENPC, "GENPC", m_pc).noshow();
+ state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow();
+
+ state_add(CLIPPER_PC, "pc", m_pc).formatstr("%08X");
+ state_add(CLIPPER_PSW, "psw", m_psw.d).formatstr("%08X");
+ state_add(CLIPPER_SSW, "ssw", m_ssw.d).formatstr("%08X");
+
+ state_add(CLIPPER_R0, "r0", m_r[m_ssw.bits.u][0]).formatstr("%08X");
+ state_add(CLIPPER_R1, "r1", m_r[m_ssw.bits.u][1]).formatstr("%08X");
+ state_add(CLIPPER_R2, "r2", m_r[m_ssw.bits.u][2]).formatstr("%08X");
+ state_add(CLIPPER_R3, "r3", m_r[m_ssw.bits.u][3]).formatstr("%08X");
+ state_add(CLIPPER_R4, "r4", m_r[m_ssw.bits.u][4]).formatstr("%08X");
+ state_add(CLIPPER_R5, "r5", m_r[m_ssw.bits.u][5]).formatstr("%08X");
+ state_add(CLIPPER_R6, "r6", m_r[m_ssw.bits.u][6]).formatstr("%08X");
+ state_add(CLIPPER_R7, "r7", m_r[m_ssw.bits.u][7]).formatstr("%08X");
+ state_add(CLIPPER_R8, "r8", m_r[m_ssw.bits.u][8]).formatstr("%08X");
+ state_add(CLIPPER_R9, "r9", m_r[m_ssw.bits.u][9]).formatstr("%08X");
+ state_add(CLIPPER_R10, "r10", m_r[m_ssw.bits.u][10]).formatstr("%08X");
+ state_add(CLIPPER_R11, "r11", m_r[m_ssw.bits.u][11]).formatstr("%08X");
+ state_add(CLIPPER_R12, "r12", m_r[m_ssw.bits.u][12]).formatstr("%08X");
+ state_add(CLIPPER_R13, "r13", m_r[m_ssw.bits.u][13]).formatstr("%08X");
+ state_add(CLIPPER_R14, "r14", m_r[m_ssw.bits.u][14]).formatstr("%08X");
+ state_add(CLIPPER_R15, "r15", m_r[m_ssw.bits.u][15]).formatstr("%08X");
+
+ state_add(CLIPPER_F0, "f0", m_f[0]).formatstr("%016X");
+ state_add(CLIPPER_F1, "f1", m_f[1]).formatstr("%016X");
+ state_add(CLIPPER_F2, "f2", m_f[2]).formatstr("%016X");
+ state_add(CLIPPER_F3, "f3", m_f[3]).formatstr("%016X");
+ state_add(CLIPPER_F4, "f4", m_f[4]).formatstr("%016X");
+ state_add(CLIPPER_F5, "f5", m_f[5]).formatstr("%016X");
+ state_add(CLIPPER_F6, "f6", m_f[6]).formatstr("%016X");
+ state_add(CLIPPER_F7, "f7", m_f[7]).formatstr("%016X");
+ state_add(CLIPPER_F8, "f8", m_f[8]).formatstr("%016X");
+ state_add(CLIPPER_F9, "f9", m_f[9]).formatstr("%016X");
+ state_add(CLIPPER_F10, "f10", m_f[10]).formatstr("%016X");
+ state_add(CLIPPER_F11, "f11", m_f[11]).formatstr("%016X");
+ state_add(CLIPPER_F12, "f12", m_f[12]).formatstr("%016X");
+ state_add(CLIPPER_F13, "f13", m_f[13]).formatstr("%016X");
+ state_add(CLIPPER_F14, "f14", m_f[14]).formatstr("%016X");
+ state_add(CLIPPER_F15, "f15", m_f[15]).formatstr("%016X");
+}
+
+void clipper_device::device_reset()
+{
+ m_ssw.bits.m = 0; // FIXME: turn off mapping
+ m_ssw.bits.u = 0;
+
+ m_pc = 0x7F100000; // FIXME: start executing boot rom
+ m_immediate_irq = 0;
+}
+
+void clipper_device::state_string_export(const device_state_entry &entry, std::string &str) const
+{
+ switch (entry.index())
+ {
+ default:
+ break;
+ }
+}
+
+void clipper_device::execute_run()
+{
+ uint16_t insn;
+
+ if (m_immediate_irq)
+ {
+ LOG_INTERRUPT("taking interrupt - current pc = %08x\n", m_pc);
+
+ m_pc = intrap(0x800 + m_immediate_vector * 8, m_pc);
+ m_immediate_irq = 0;
+ }
+
+ while (m_icount > 0) {
+
+ debugger_instruction_hook(this, m_pc);
+
+ // fetch instruction word
+ insn = m_direct->read_word(m_pc + 0);
+
+ // decode and execute instruction, return next pc
+ m_pc = execute_instruction(insn);
+
+ m_icount--;
+ }
+}
+
+void clipper_device::execute_set_input(int inputnum, int state)
+{
+ if (state)
+ {
+ // clock is vector 0e29 0000 1110
+ // floppy is vector 0621 0000 0110
+
+ uint16_t vector = standard_irq_callback(inputnum);
+
+ uint8_t ivec = vector & 0xff;
+ uint8_t il = ivec >> 4;
+ uint8_t in = ivec & 0xf;
+
+ LOG_INTERRUPT("received interrupt with vector %04x\n", vector);
+
+ // allow NMI or equal/higher priority interrupts
+ if (ivec == 0 || (m_ssw.bits.ei && (il <= m_ssw.bits.il)))
+ {
+ m_immediate_irq = 1;
+ m_immediate_vector = ivec;
+
+ LOG_INTERRUPT("accepting interrupt %x\n", m_immediate_vector);
+ }
+ }
+}
+
+const address_space_config * clipper_device::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_PROGRAM) ? &m_program_config : nullptr;
+}
+
+#define R1 ((insn & 0x00F0) >> 4)
+#define R2 (insn & 0x000F)
+int clipper_device::execute_instruction(uint16_t insn)
+{
+ uint32_t next_pc = 0;
+ union {
+ int32_t imm; // used by instructions with immediate operand values
+ uint32_t r2; // used by instructions with complex addressing modes
+ uint16_t macro; // used by macro instructions
+ } op;
+ op.imm = op.r2 = op.macro = 0;
+ uint32_t addr_ea = 0; // used by instructions with complex addressing modes
+
+ // test for immediate, address or macro instructions and decode additional operands
+ if ((insn & 0xF800) == 0x3800 || (insn & 0xD300) == 0x8300)
+ {
+ // immediate instructions
+ if (insn & 0x0080)
+ {
+ // fetch 16 bit immediate and sign extend
+ op.imm = (int16_t)m_direct->read_word(m_pc + 2);
+ next_pc = m_pc + 4;
+ }
+ else
+ {
+ // fetch 32 bit immediate and sign extend
+ op.imm = (int32_t)m_direct->read_dword(m_pc + 2);
+ next_pc = m_pc + 6;
+ }
+ }
+ else if ((insn & 0xF100) == 0x4100 || (insn & 0xE100) == 0x6100)
+ {
+ // instructions with complex addressing modes (b*, bf*, call, load*, stor*)
+ uint16_t temp;
+
+ switch (insn & 0x00F0)
+ {
+ case ADDR_MODE_PC32:
+ op.r2 = R2;
+ addr_ea = m_pc + (int32_t)m_direct->read_dword(m_pc + 2);
+ next_pc = m_pc + 6;
+ break;
+
+ case ADDR_MODE_ABS32:
+ op.r2 = R2;
+ addr_ea = m_direct->read_dword(m_pc + 2);
+ next_pc = m_pc + 6;
+ break;
+
+ case ADDR_MODE_REL32:
+ op.r2 = m_direct->read_word(m_pc + 2) & 0xf;
+ addr_ea = m_r[m_ssw.bits.u][R2] + (int32_t)m_direct->read_dword(m_pc + 4);
+ next_pc = m_pc + 8;
+ break;
+
+ case ADDR_MODE_PC16:
+ op.r2 = R2;
+ addr_ea = m_pc + (int16_t)m_direct->read_word(m_pc + 2);
+ next_pc = m_pc + 4;
+ break;
+
+ case ADDR_MODE_REL12:
+ temp = m_direct->read_word(m_pc + 2);
+
+ op.r2 = temp & 0xf;
+ addr_ea = m_r[m_ssw.bits.u][R2] + ((int16_t)temp >> 4);
+ next_pc = m_pc + 4;
+ break;
+
+ case ADDR_MODE_ABS16:
+ op.r2 = R2;
+ addr_ea = (int16_t)m_direct->read_word(m_pc + 2);
+ next_pc = m_pc + 4;
+ break;
+
+ case ADDR_MODE_PCX:
+ temp = m_direct->read_word(m_pc + 2);
+
+ op.r2 = temp & 0xf;
+ addr_ea = m_pc + m_r[m_ssw.bits.u][(temp >> 4) & 0xf];
+ next_pc = m_pc + 4;
+ break;
+
+ case ADDR_MODE_RELX:
+ temp = m_direct->read_word(m_pc + 2);
+
+ op.r2 = temp & 0xf;
+ addr_ea = m_r[m_ssw.bits.u][R2] + m_r[m_ssw.bits.u][(temp >> 4) & 0xf];
+ next_pc = m_pc + 4;
+ break;
+
+ default:
+ logerror("illegal addressing mode pc = 0x%08x\n", m_pc);
+ machine().debug_break();
+ break;
+ }
+ }
+ else if ((insn & 0xFD00) == 0xB400)
+ {
+ // macro instructions
+ op.macro = m_direct->read_word(m_pc + 2);
+ next_pc = m_pc + 4;
+ }
+ else
+ next_pc = m_pc + 2;
+
+ switch (insn >> 8)
+ {
+ case 0x00: // noop
+ break;
+
+ case 0x10:
+ // movwp (treated as a noop if target ssw in user mode)
+ // R1 == 3 means "fast" mode - avoids pipeline flush
+ if (R1 == 0)
+ m_psw.d = m_r[m_ssw.bits.u][R2];
+ else if (m_ssw.bits.u == 0 && (R1 == 1 || R1 == 3))
+ m_ssw.d = m_r[m_ssw.bits.u][R2];
+ break;
+
+ case 0x11: // movpw
+ switch (R1)
+ {
+ case 0: m_r[m_ssw.bits.u][R2] = m_psw.d; break;
+ case 1: m_r[m_ssw.bits.u][R2] = m_ssw.d; break;
+ }
+ break;
+
+ case 0x12: // calls
+ next_pc = intrap(0x400 + (insn & 0x7F) * 8, next_pc);
+ break;
+
+ case 0x13: // ret
+ next_pc = m_program->read_dword(m_r[m_ssw.bits.u][R2]);
+ m_r[m_ssw.bits.u][R2] += 4;
+ break;
+
+ case 0x14: // pushw
+ m_r[m_ssw.bits.u][R1] -= 4;
+ m_program->write_dword(m_r[m_ssw.bits.u][R1], m_r[m_ssw.bits.u][R2]);
+ break;
+
+ case 0x16: // popw
+ m_r[m_ssw.bits.u][R2] = m_program->read_dword(m_r[m_ssw.bits.u][R1]);
+ m_r[m_ssw.bits.u][R1] += 4;
+ break;
+
+ case 0x20: *((float *)&m_f[R2]) -= *((float *)&m_f[R1]); break; // subs
+ case 0x21: *((float *)&m_f[R2]) += *((float *)&m_f[R1]); break; // adds
+ case 0x22: m_f[R2] += m_f[R1]; break; // addd
+ case 0x23: m_f[R2] -= m_f[R1]; break; // subd
+ case 0x24: *((float *)&m_f[R2]) = *((float *)&m_f[R1]); break; // movs
+ case 0x25: evaluate_cc2f(*((float *)&m_f[R2]), *((float *)&m_f[R1])); break; // cmps
+ case 0x26: m_f[R2] = m_f[R1]; break; // movd
+ case 0x27: evaluate_cc2f(m_f[R2], m_f[R1]); break; // cmpd
+ case 0x2A: m_f[R2] *= m_f[R1]; break; // muld
+ case 0x2B: m_f[R2] /= m_f[R1]; break; // divd
+ case 0x2C: m_r[m_ssw.bits.u][R2] = *((int32_t *)&m_f[R1]); break; // movsw
+ case 0x2D: *((int32_t *)&m_f[R2]) = m_r[m_ssw.bits.u][R1]; break; // movws
+ case 0x2E: ((double *)m_r[m_ssw.bits.u])[R2 >> 1] = m_f[R1]; break; // movdl
+ case 0x2F: m_f[R2] = ((double *)m_r[m_ssw.bits.u])[R1 >> 1]; break; // movld
+
+ case 0x30: // shaw
+ if ((int32_t)m_r[m_ssw.bits.u][R1] > 0)
+ m_r[m_ssw.bits.u][R2] = (int32_t)m_r[m_ssw.bits.u][R2] << m_r[m_ssw.bits.u][R1];
+ else
+ m_r[m_ssw.bits.u][R2] = (int32_t)m_r[m_ssw.bits.u][R2] >> -(int32_t)m_r[m_ssw.bits.u][R1];
+ break;
+ case 0x31: // shal
+ if ((int32_t)m_r[m_ssw.bits.u][R1] > 0)
+ ((int64_t *)m_r[m_ssw.bits.u])[R2 >> 1] <<= m_r[m_ssw.bits.u][R1];
+ else
+ ((int64_t *)m_r[m_ssw.bits.u])[R2 >> 1] >>= -(int32_t)m_r[m_ssw.bits.u][R1];
+ break;
+ case 0x32: // shlw
+ if ((int32_t)m_r[m_ssw.bits.u][R1] > 0)
+ m_r[m_ssw.bits.u][R2] <<= m_r[m_ssw.bits.u][R1];
+ else
+ m_r[m_ssw.bits.u][R2] >>= -(int32_t)m_r[m_ssw.bits.u][R1];
+ break;
+ case 0x33: // shll
+ if ((int32_t)m_r[m_ssw.bits.u][R1] > 0)
+ ((uint64_t *)m_r[m_ssw.bits.u])[R2 >> 1] <<= m_r[m_ssw.bits.u][R1];
+ else
+ ((uint64_t *)m_r[m_ssw.bits.u])[R2 >> 1] >>= -(int32_t)m_r[m_ssw.bits.u][R1];
+ break;
+ case 0x34: // rotw
+ if ((int32_t)m_r[m_ssw.bits.u][R1] > 0)
+ m_r[m_ssw.bits.u][R2] = _rotl(m_r[m_ssw.bits.u][R2], m_r[m_ssw.bits.u][R1]);
+ else
+ m_r[m_ssw.bits.u][R2] = _rotr(m_r[m_ssw.bits.u][R2], -(int32_t)m_r[m_ssw.bits.u][R1]);
+ break;
+ case 0x35: // rotl
+ if ((int32_t)m_r[m_ssw.bits.u][R1] > 0)
+ ((uint64_t *)m_r[m_ssw.bits.u])[R2 >> 1] = _rotl64(((uint64_t *)m_r[m_ssw.bits.u])[R2 >> 1], m_r[m_ssw.bits.u][R1]);
+ else
+ ((uint64_t *)m_r[m_ssw.bits.u])[R2 >> 1] = _rotr64(((uint64_t *)m_r[m_ssw.bits.u])[R2 >> 1], -(int32_t)m_r[m_ssw.bits.u][R1]);
+ break;
+ case 0x38: // shai
+ if (op.imm > 0)
+ m_r[m_ssw.bits.u][R2] = (int32_t)m_r[m_ssw.bits.u][R2] << op.imm;
+ else
+ m_r[m_ssw.bits.u][R2] = (int32_t)m_r[m_ssw.bits.u][R2] >> -op.imm;
+ break;
+ case 0x39: // shali
+ if (op.imm > 0)
+ ((int64_t *)m_r[m_ssw.bits.u])[R2 >> 1] <<= op.imm;
+ else
+ ((int64_t *)m_r[m_ssw.bits.u])[R2 >> 1] >>= -op.imm;
+ break;
+ case 0x3A: // shli
+ if (op.imm > 0)
+ m_r[m_ssw.bits.u][R2] <<= op.imm;
+ else
+ m_r[m_ssw.bits.u][R2] >>= -op.imm;
+ break;
+ case 0x3B: // shlli
+ if (op.imm > 0)
+ ((uint64_t *)m_r[m_ssw.bits.u])[R2 >> 1] <<= op.imm;
+ else
+ ((uint64_t *)m_r[m_ssw.bits.u])[R2 >> 1] >>= -op.imm;
+ break;
+ case 0x3C: // roti
+ if (op.imm > 0)
+ m_r[m_ssw.bits.u][R2] = _rotl(m_r[m_ssw.bits.u][R2], op.imm);
+ else
+ m_r[m_ssw.bits.u][R2] = _rotr(m_r[m_ssw.bits.u][R2], -op.imm);
+ break;
+ case 0x3D: // rotli
+ if (op.imm > 0)
+ ((uint64_t *)m_r[m_ssw.bits.u])[R2 >> 1] = _rotl64(((uint64_t *)m_r[m_ssw.bits.u])[R2 >> 1], op.imm);
+ else
+ ((uint64_t *)m_r[m_ssw.bits.u])[R2 >> 1] = _rotr64(((uint64_t *)m_r[m_ssw.bits.u])[R2 >> 1], -op.imm);
+ break;
+
+ case 0x44: // call
+ m_r[m_ssw.bits.u][R2] -= 4; // decrement sp
+ m_program->write_dword(m_r[m_ssw.bits.u][R2], next_pc); // push return address
+ next_pc = m_r[m_ssw.bits.u][R1];
+ break;
+ case 0x45: // call
+ m_r[m_ssw.bits.u][op.r2] -= 4; // decrement sp
+ m_program->write_dword(m_r[m_ssw.bits.u][op.r2], next_pc); // push return address
+ next_pc = addr_ea;
+ break;
+
+ case 0x48: // b*
+ if (evaluate_branch(R2))
+ next_pc = m_r[m_ssw.bits.u][R1];
+ break;
+ case 0x49: // b*
+ if (evaluate_branch(op.r2))
+ next_pc = addr_ea;
+ break;
+
+ case 0x60: // loadw
+ m_r[m_ssw.bits.u][R2] = m_program->read_dword(m_r[m_ssw.bits.u][R1]);
+ break;
+ case 0x61: // loadw
+ m_r[m_ssw.bits.u][op.r2] = m_program->read_dword(addr_ea);
+ break;
+
+ case 0x62: // loada
+ m_r[m_ssw.bits.u][R2] = m_r[m_ssw.bits.u][R1];
+ break;
+ case 0x63:
+ m_r[m_ssw.bits.u][op.r2] = addr_ea;
+ break;
+
+ case 0x64: // loads
+ ((uint64_t *)&m_f)[R2] = m_program->read_dword(m_r[m_ssw.bits.u][R1]);
+ break;
+ case 0x65: // loads
+ ((uint64_t *)&m_f)[op.r2] = m_program->read_dword(addr_ea);
+ break;
+
+ case 0x66: // loadd
+ ((uint64_t *)&m_f)[R2] = m_program->read_qword(m_r[m_ssw.bits.u][R1]);
+ break;
+ case 0x67: // loadd
+ ((uint64_t *)&m_f)[op.r2] = m_program->read_qword(addr_ea);
+ break;
+
+ case 0x68: // loadb
+ m_r[m_ssw.bits.u][R2] = (int8_t)m_program->read_byte(m_r[m_ssw.bits.u][R1]);
+ break;
+ case 0x69: // loadb
+ m_r[m_ssw.bits.u][op.r2] = (int8_t)m_program->read_byte(addr_ea);
+ break;
+
+ case 0x6A: // loadbu
+ m_r[m_ssw.bits.u][R2] = (uint8_t)m_program->read_byte(m_r[m_ssw.bits.u][R1]);
+ break;
+ case 0x6B:
+ m_r[m_ssw.bits.u][op.r2] = m_program->read_byte(addr_ea);
+ break;
+
+ case 0x6C: // loadh
+ m_r[m_ssw.bits.u][R2] = (int16_t)m_program->read_word(m_r[m_ssw.bits.u][R1]);
+ break;
+ case 0x6D:
+ m_r[m_ssw.bits.u][op.r2] = (int16_t)m_program->read_word(addr_ea);
+ break;
+
+ case 0x6E: // loadhu
+ m_r[m_ssw.bits.u][R2] = (uint16_t)m_program->read_word(m_r[m_ssw.bits.u][R1]);
+ break;
+ case 0x6F: // loadhu
+ m_r[m_ssw.bits.u][op.r2] = m_program->read_word(addr_ea);
+ break;
+
+ case 0x70: // storw
+ m_program->write_dword(m_r[m_ssw.bits.u][R1], m_r[m_ssw.bits.u][R2]);
+ break;
+ case 0x71:
+ m_program->write_dword(addr_ea, m_r[m_ssw.bits.u][op.r2]);
+ break;
+
+ case 0x74: // stors
+ m_program->write_dword(m_r[m_ssw.bits.u][R1], *((uint32_t *)&m_f[R2]));
+ break;
+ case 0x75: // stors
+ m_program->write_dword(addr_ea, *((uint32_t *)&m_f[op.r2]));
+ break;
+
+ case 0x76: // stord
+ m_program->write_qword(m_r[m_ssw.bits.u][R1], *((uint64_t *)&m_f[R2]));
+ break;
+ case 0x77: // stord
+ m_program->write_qword(addr_ea, *((uint64_t *)&m_f[op.r2]));
+ break;
+
+ case 0x78: // storb
+ m_program->write_byte(m_r[m_ssw.bits.u][R1], (uint8_t)m_r[m_ssw.bits.u][R2]);
+ break;
+ case 0x79:
+ m_program->write_byte(addr_ea, (uint8_t)m_r[m_ssw.bits.u][op.r2]);
+ break;
+
+ case 0x7C: // storh
+ m_program->write_word(m_r[m_ssw.bits.u][R1], (uint16_t)m_r[m_ssw.bits.u][R2]);
+ break;
+ case 0x7D:
+ m_program->write_word(addr_ea, (uint16_t)m_r[m_ssw.bits.u][op.r2]);
+ break;
+
+ case 0x80: // addw
+ m_r[m_ssw.bits.u][R2] += m_r[m_ssw.bits.u][R1];
+ break;
+
+ case 0x82: // addq
+ m_r[m_ssw.bits.u][R2] += R1;
+ break;
+ case 0x83: // addi
+ m_r[m_ssw.bits.u][R2] += op.imm;
+ break;
+ case 0x84: // movw
+ m_r[m_ssw.bits.u][R2] = m_r[m_ssw.bits.u][R1];
+ evaluate_cc1(m_r[m_ssw.bits.u][R2]);
+ break;
+
+ case 0x86: // loadq
+ m_r[m_ssw.bits.u][R2] = R1;
+ break;
+ case 0x87: // loadi
+ m_r[m_ssw.bits.u][R2] = op.imm;
+ break;
+ case 0x88: // andw
+ m_r[m_ssw.bits.u][R2] &= m_r[m_ssw.bits.u][R1];
+ evaluate_cc1(m_r[m_ssw.bits.u][R2]);
+ break;
+
+ case 0x8B: // andi
+ m_r[m_ssw.bits.u][R2] &= op.imm;
+ evaluate_cc1(m_r[m_ssw.bits.u][R2]);
+ break;
+ case 0x8C: // orw
+ m_r[m_ssw.bits.u][R2] |= m_r[m_ssw.bits.u][R1];
+ evaluate_cc1(m_r[m_ssw.bits.u][R2]);
+ break;
+
+ case 0x8F: // ori
+ m_r[m_ssw.bits.u][R2] |= op.imm;
+ evaluate_cc1(m_r[m_ssw.bits.u][R2]);
+ break;
+
+#if 0
+ case 0x90: // addwc
+ m_r[m_ssw.bits.u][r2] += m_r[m_ssw.bits.u][r1] + psw.b.c;
+ break;
+
+ case 0x91: // subwc
+ m_r[m_ssw.bits.u][r2] -= m_r[m_ssw.bits.u][r1] + psw.b.c;
+ break;
+#endif
+
+ case 0x93: // negw
+ m_r[m_ssw.bits.u][R2] = -(int32_t)m_r[m_ssw.bits.u][R1];
+ break;
+
+ case 0x98: // mulw
+ m_r[m_ssw.bits.u][R2] = (int32_t)m_r[m_ssw.bits.u][R2] * (int32_t)m_r[m_ssw.bits.u][R1];
+ break;
+ // TODO: mulwx
+ case 0x9A: // mulwu
+ m_r[m_ssw.bits.u][R2] = (uint32_t)m_r[m_ssw.bits.u][R2] * (uint32_t)m_r[m_ssw.bits.u][R1];
+ break;
+ // TODO: mulwux
+ case 0x9C: // divw
+ m_r[m_ssw.bits.u][R2] = (int32_t)m_r[m_ssw.bits.u][R2] / (int32_t)m_r[m_ssw.bits.u][R1];
+ break;
+ case 0x9D: // modw
+ m_r[m_ssw.bits.u][R2] = (int32_t)m_r[m_ssw.bits.u][R2] % (int32_t)m_r[m_ssw.bits.u][R1];
+ break;
+ case 0x9E: // divwu
+ m_r[m_ssw.bits.u][R2] = (uint32_t)m_r[m_ssw.bits.u][R2] / (uint32_t)m_r[m_ssw.bits.u][R1];
+ break;
+ case 0x9F: // modwu
+ m_r[m_ssw.bits.u][R2] = (uint32_t)m_r[m_ssw.bits.u][R2] % (uint32_t)m_r[m_ssw.bits.u][R1];
+ break;
+
+ case 0xA0: // subw
+ evaluate_cc2(m_r[m_ssw.bits.u][R2], m_r[m_ssw.bits.u][R1]);
+ m_r[m_ssw.bits.u][R2] -= m_r[m_ssw.bits.u][R1];
+ break;
+
+ case 0xA2: // subq
+ evaluate_cc2(m_r[m_ssw.bits.u][R2], R1);
+ m_r[m_ssw.bits.u][R2] -= R1;
+ break;
+ case 0xA3: // subi
+ evaluate_cc2(m_r[m_ssw.bits.u][R2], op.imm);
+ m_r[m_ssw.bits.u][R2] -= op.imm;
+ break;
+ case 0xA4: // cmpw
+ evaluate_cc2(m_r[m_ssw.bits.u][R2], m_r[m_ssw.bits.u][R1]);
+ break;
+
+ case 0xA6: // cmpq
+ evaluate_cc2(m_r[m_ssw.bits.u][R2], R1);
+ break;
+ case 0xA7: // cmpi
+ evaluate_cc2(m_r[m_ssw.bits.u][R2], op.imm);
+ break;
+ case 0xA8: // xorw
+ m_r[m_ssw.bits.u][R2] ^= m_r[m_ssw.bits.u][R1];
+ evaluate_cc1(m_r[m_ssw.bits.u][R2]);
+ break;
+
+ case 0xAB: // xori
+ m_r[m_ssw.bits.u][R2] ^= op.imm;
+ evaluate_cc1(m_r[m_ssw.bits.u][R2]);
+ break;
+ case 0xAC: // notw
+ m_r[m_ssw.bits.u][R2] = ~m_r[m_ssw.bits.u][R1];
+ evaluate_cc1(m_r[m_ssw.bits.u][R2]);
+ break;
+
+ case 0xAE: // notq
+ m_r[m_ssw.bits.u][R2] = ~R1;
+ evaluate_cc1(m_r[m_ssw.bits.u][R2]);
+ break;
+
+ case 0xB4:
+ switch (insn & 0xFF)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ case 0x08: case 0x09: case 0x0A: case 0x0B:
+ case 0x0C:
+ // savew0..savew12: push registers from rN through r14
+
+ // store ri at sp - 4 * (15 - i)
+ for (int reg = R2; reg < 15; reg++)
+ m_program->write_dword(m_r[m_ssw.bits.u][15] - 4 * (15 - reg), m_r[m_ssw.bits.u][reg]);
+
+ // decrement sp after push to allow restart on exceptions
+ m_r[m_ssw.bits.u][15] -= 4 * (15 - R2);
+ break;
+
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1A: case 0x1B:
+ case 0x1C:
+ // restwN..restw12: pop registers from rN:r14
+
+ // load ri from sp + 4 * (i - N)
+ for (int reg = R2; reg < 15; reg++)
+ m_r[m_ssw.bits.u][reg] = m_program->read_dword(m_r[m_ssw.bits.u][15] + 4 * (reg - R2));
+
+ // increment sp after pop to allow restart on exceptions
+ m_r[m_ssw.bits.u][15] += 4 * (15 - R2);
+ break;
+
+ case 0x36: // cnvtdw
+ m_r[m_ssw.bits.u][op.macro & 0xf] = (int32_t)m_f[(op.macro >> 4) & 0xf];
+ break;
+
+ case 0x37: // cnvwd
+ m_f[op.macro & 0xf] = (double)m_r[m_ssw.bits.u][(op.macro >> 4) & 0xf];
+ break;
+
+ default:
+ logerror("illegal macro opcode at 0x%08x\n", m_pc);
+ break;
+ }
+
+ break;
+
+ case 0xB6:
+ if (m_ssw.bits.u == 0)
+ {
+ switch (insn & 0xFF)
+ {
+ case 0x00: // movus
+ m_r[0][op.macro & 0xf] = m_r[1][(op.macro >> 4) & 0xf];
+ // setcc1(m_r[m_ssw.bits.u][r2]);
+ break;
+
+ case 0x01: // movsu
+ m_r[1][op.macro & 0xf] = m_r[0][(op.macro >> 4) & 0xf];
+ // setcc1(m_r[!m_ssw.bits.u][r2]);
+ break;
+
+ case 0x04:
+ // reti: restore psw, ssw and pc from supervisor stack
+#if SSP_HACK
+ // some user code increments sp before reti
+ // HACK: if previous instruction is addq $12,sp then correct sp
+ // FIXME: figure out the real cause of this stack adjustment
+ if (m_program->read_word(m_pc - 2) == 0x82cf)
+ {
+ LOG_INTERRUPT("correcting ssp for reti at 0x%08x\n", m_pc);
+
+ m_r[0][(op.macro >> 4) & 0xf] -= 12;
+ }
+#endif
+ LOG_INTERRUPT("reti r%d, ssp = %08x, pc = %08x, next_pc = %08x\n",
+ (op.macro >> 4) & 0xf, m_r[0][(op.macro >> 4) & 0xf], m_pc, m_program->read_dword(m_r[0][(op.macro >> 4) & 0xf] + 8));
+ m_psw.d = m_program->read_dword(m_r[0][(op.macro >> 4) & 0xf] + 0);
+ m_ssw.d = m_program->read_dword(m_r[0][(op.macro >> 4) & 0xf] + 4);
+ next_pc = m_program->read_dword(m_r[0][(op.macro >> 4) & 0xf] + 8);
+
+ m_r[0][(op.macro >> 4) & 0xf] += 12;
+ break;
+
+ default:
+ // TODO: set psw.b.cts
+ logerror("illegal opcode at 0x%08x\n", m_pc);
+ next_pc = intrap(0x300, next_pc); // illegal operation, illegal operation
+ machine().debug_break();
+ break;
+ }
+ }
+ else
+ // TODO: set psw.b.cts
+ next_pc = intrap(0x308, next_pc); // illegal operation, privileged instruction
+ break;
+
+ default:
+ logerror("illegal opcode at 0x%08x\n", m_pc);
+ next_pc = intrap(0x300, next_pc); // illegal operation, illegal operation
+ machine().debug_break();
+ break;
+
+ }
+
+ return next_pc;
+}
+
+/*
+* Sets up the PC, SSW and PSW to handle an exception.
+*/
+uint32_t clipper_device::intrap(uint32_t vector, uint32_t pc)
+{
+ uint32_t next_pc, pmode;
+
+ LOG_INTERRUPT("intrap - vector %x, pc = 0x%08x, next_pc = 0x%08x, ssp = 0x%08x\n", vector, pc, m_program->read_dword(vector + 4), m_r[0][15]);
+
+ // push pc, psw and ssw onto supervisor stack
+ m_program->write_dword(m_r[0][15] - 4, pc);
+ m_program->write_dword(m_r[0][15] - 12, m_psw.d); // TODO: set mts or cts bits in saved psw
+ m_program->write_dword(m_r[0][15] - 8, m_ssw.d);
+
+ // decrement supervisor stack pointer
+#if SSP_HACK
+ m_r[0][15] -= 12;
+#else
+ m_r[0][15] -= 24;
+#endif
+
+ // load SSW from trap vector and set previous mode flag
+ pmode = m_ssw.bits.u;
+ m_ssw.d = m_program->read_dword(vector + 0);
+ m_ssw.bits.p = pmode;
+
+ // clear psw
+ m_psw.d = 0;
+
+ // fetch target pc
+ next_pc = m_program->read_dword(vector + 4);
+
+#if SSP_HACK
+ // some code immediately increments sp by 12 on entry into isr (causing overwrite of exception frame)
+ // HACK: if target instruction is addq $12,sp then adjust sp
+ // FIXME: figure out the real cause of this stack adjustment
+ if (m_program->read_word(next_pc) == 0x82cf)
+ {
+ LOG_INTERRUPT("correcting ssp for trap handler at 0x%08x\n", next_pc);
+
+ m_r[0][15] -= 12;
+ }
+#endif
+
+ // return new pc from trap vector
+ return next_pc;
+}
+
+void clipper_device::evaluate_cc1(int32_t v0)
+{
+ m_psw.bits.n = v0 < 0;
+ m_psw.bits.z = v0 == 0;
+}
+
+/*
+evaluation of overflow:
+both +: v0 - v1 > v0
+v0- v1+: v0 - v1 > v0 = 0
+
+both -: v0 - v1 < v0
+v0+ v1-: v0 - v1 < v0 = 0
+
+overflow (addition): inputs have same sign and output has opposite
+s1 == s2 && != s3
+*/
+void clipper_device::evaluate_cc2(int32_t v0, int32_t v1)
+{
+ m_psw.bits.n = (v0 - v1) >> 31;
+ m_psw.bits.z = v0 == v1;
+ m_psw.bits.v = ((v1 < 0) ? (v0 - v1 < v0) : (v0 - v1 > v0));
+ m_psw.bits.c = ((uint32_t)v0 < (uint32_t)v1);
+}
+
+void clipper_device::evaluate_cc3(int32_t v0, int32_t v1, int32_t v2)
+{
+ m_psw.bits.n = v2 >> 31;
+ m_psw.bits.z = v2 == 0;
+ m_psw.bits.v = ((v0 > 0 && v1 > 0 && v2 < 0) || (v0 < 0 && v1 < 0 && v2 > 0));
+ m_psw.bits.v = ((v1 < 0) ? (v0 - v1 < v0) : (v0 - v1 > v0));
+ m_psw.bits.c = ((uint32_t)v0 < (uint32_t)v1);
+}
+
+void clipper_device::evaluate_cc2f(double v0, double v1)
+{
+ m_psw.bits.n = v0 < v1;
+ m_psw.bits.z = v0 == v1;
+ // psw.b.v = ((v1 < 0) ? (v0 - v1 < v0) : (v0 - v1 > v0));
+ // psw.b.c = (fabs(v0) < fabs(v1));
+ m_psw.bits.v = 0;
+ m_psw.bits.c = 0;
+}
+
+bool clipper_device::evaluate_branch(uint32_t r2)
+{
+ switch (r2)
+ {
+ case BRANCH_T:
+ return true;
+
+ case BRANCH_GT:
+ return !((m_psw.bits.n ^ m_psw.bits.v) | m_psw.bits.z);
+ case BRANCH_GE:
+ return !(m_psw.bits.n ^ m_psw.bits.v);
+ case BRANCH_EQ:
+ return m_psw.bits.z;
+
+ case BRANCH_LT:
+ return m_psw.bits.n ^ m_psw.bits.v;
+ case BRANCH_LE:
+ return (m_psw.bits.n ^ m_psw.bits.v) | m_psw.bits.z;
+ case BRANCH_NE:
+ return !m_psw.bits.z;
+
+ case BRANCH_GTU:
+ return !(m_psw.bits.c | m_psw.bits.z);
+ case BRANCH_GEU:
+ return !m_psw.bits.c;
+ case BRANCH_LTU:
+ return m_psw.bits.c;
+ case BRANCH_LEU:
+ return m_psw.bits.c | m_psw.bits.z;
+
+ case BRANCH_V:
+ return m_psw.bits.v;
+ case BRANCH_NV:
+ return !m_psw.bits.v;
+ case BRANCH_N:
+ return m_psw.bits.n;
+ case BRANCH_NN:
+ return !m_psw.bits.n;
+
+ case BRANCH_FV:
+ return false;
+ }
+
+ return false;
+}
+
+offs_t clipper_device::disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options)
+{
+ extern CPU_DISASSEMBLE(clipper);
+ return CPU_DISASSEMBLE_NAME(clipper)(this, stream, pc, oprom, opram, options);
+}
diff --git a/src/devices/cpu/clipper/clipper.h b/src/devices/cpu/clipper/clipper.h
new file mode 100644
index 00000000000..ad8c28421a1
--- /dev/null
+++ b/src/devices/cpu/clipper/clipper.h
@@ -0,0 +1,165 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+#pragma once
+
+#ifndef __CLIPPER_H__
+#define __CLIPPER_H__
+
+// enumerate registers (why?)
+enum
+{
+ CLIPPER_R0, CLIPPER_R1, CLIPPER_R2, CLIPPER_R3, CLIPPER_R4, CLIPPER_R5, CLIPPER_R6, CLIPPER_R7,
+ CLIPPER_R8, CLIPPER_R9, CLIPPER_R10, CLIPPER_R11, CLIPPER_R12, CLIPPER_R13, CLIPPER_R14, CLIPPER_R15,
+
+ CLIPPER_F0, CLIPPER_F1, CLIPPER_F2, CLIPPER_F3, CLIPPER_F4, CLIPPER_F5, CLIPPER_F6, CLIPPER_F7,
+ CLIPPER_F8, CLIPPER_F9, CLIPPER_F10, CLIPPER_F11, CLIPPER_F12, CLIPPER_F13, CLIPPER_F14, CLIPPER_F15,
+
+ CLIPPER_PSW, CLIPPER_SSW,
+ CLIPPER_PC
+};
+
+enum
+{
+ ADDR_MODE_NONE = 0x00,
+ ADDR_MODE_PC32 = 0x10,
+ ADDR_MODE_ABS32 = 0x30,
+ ADDR_MODE_REL32 = 0x60,
+ ADDR_MODE_PC16 = 0x90,
+ ADDR_MODE_REL12 = 0xA0,
+ ADDR_MODE_ABS16 = 0xB0,
+ ADDR_MODE_PCX = 0xD0,
+ ADDR_MODE_RELX = 0xE0,
+ ADDR_MODE_REL = 0xFF
+};
+
+// branch conditions
+enum
+{
+ BRANCH_T = 0x0,
+ BRANCH_GT = 0x1,
+ BRANCH_GE = 0x2,
+ BRANCH_EQ = 0x3,
+ BRANCH_LT = 0x4,
+ BRANCH_LE = 0x5,
+ BRANCH_NE = 0x6,
+ BRANCH_GTU = 0x7,
+ BRANCH_GEU = 0x8,
+ BRANCH_LTU = 0x9,
+ BRANCH_LEU = 0xA,
+ BRANCH_V = 0xB,
+ BRANCH_NV = 0xC,
+ BRANCH_N = 0xD,
+ BRANCH_NN = 0xE,
+ BRANCH_FV = 0xF
+};
+
+class clipper_device : public cpu_device
+{
+public:
+ clipper_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // device_execute_interface overrides
+ virtual uint32_t execute_min_cycles() const override { return 1; };
+ virtual uint32_t execute_max_cycles() const override { return 1; }; // FIXME: don't know, especially macro instructions
+ virtual uint32_t execute_input_lines() const override { return 16; }; // FIXME: number of input/interrupt lines
+ virtual void execute_run() override;
+ virtual void execute_set_input(int inputnum, int state) override;
+
+ // device_memory_interface overrides
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const override;
+
+ // device_state_interface overrides
+#if 0
+ virtual void state_import(const device_state_entry &entry) override;
+ virtual void state_export(const device_state_entry &entry) override;
+#endif
+ virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
+
+ // device_disasm_interface overrides
+ virtual uint32_t disasm_min_opcode_bytes() const override { return 2; } // smallest instruction
+ virtual uint32_t disasm_max_opcode_bytes() const override { return 8; } // largest instruction
+ virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override;
+
+ // core registers
+ uint32_t m_pc;
+ union {
+ struct {
+ uint32_t n : 1; // negative
+ uint32_t z : 1; // zero
+ uint32_t v : 1; // overflow
+ uint32_t c : 1; // carry out or borrow in
+ uint32_t fx : 1; // floating inexact
+ uint32_t fu : 1; // floating underflow
+ uint32_t fd : 1; // floating divide by zero
+ uint32_t fv : 1; // floating overflow
+ uint32_t fi : 1; // floating invalid operation
+ uint32_t efx : 1; // enable floating inexact trap
+ uint32_t efu : 1; // enable floating underflow trap
+ uint32_t efd : 1; // enable floating divide by zero trap
+ uint32_t efv : 1; // enable floating overflow trap
+ uint32_t efi : 1; // enable floating invalid operation trap
+ uint32_t eft : 1; // enable floating trap
+ uint32_t fr : 2; // floating rounding mode
+ uint32_t : 3;
+ uint32_t dsp : 2; // c400 - delay slot pointer
+ uint32_t big : 1; // c400 - big endian (hardware)
+ uint32_t t : 1; // trace trap
+ uint32_t cts : 4; // cpu trap status
+ uint32_t mts : 4; // memory trap status
+ } bits;
+ uint32_t d;
+ } m_psw;
+ union {
+ struct {
+ uint32_t in : 4; // interrupt number
+ uint32_t il : 4; // interrupt level
+ uint32_t ei : 1; // enable interrupts
+ uint32_t id : 8; // cpu rev # and type
+ uint32_t : 5;
+ uint32_t frd : 1; // floating registers dirty
+ uint32_t tp : 1; // trace trap pending
+ uint32_t ecm : 1; // enable corrected memory error
+ uint32_t df : 1; // fpu disabled
+ uint32_t m : 1; // mapped mode
+ uint32_t ku : 1; // user protect key
+ uint32_t uu : 1; // user data mode
+ uint32_t k : 1; // protect key
+ uint32_t u : 1; // user mode
+ uint32_t p : 1; // previous mode
+ } bits;
+ uint32_t d;
+ } m_ssw;
+ int32_t m_r[2][16];
+ double m_f[16];
+
+private:
+ address_space_config m_program_config;
+
+ address_space *m_program;
+ direct_read_data *m_direct;
+
+ int m_icount;
+ int m_interrupt_cycles;
+
+ int m_immediate_irq;
+ int m_immediate_vector;
+
+ int clipper_device::execute_instruction(uint16_t insn);
+
+ // condition code evaluations
+ void clipper_device::evaluate_cc1(int32_t v0);
+ void clipper_device::evaluate_cc2(int32_t v0, int32_t v1);
+ void clipper_device::evaluate_cc3(int32_t v0, int32_t v1, int32_t v2);
+ void clipper_device::evaluate_cc2f(double v0, double v1);
+ bool clipper_device::evaluate_branch(uint32_t r2);
+
+ uint32_t clipper_device::intrap(uint32_t vector, uint32_t pc);
+};
+
+extern const device_type CLIPPER;
+#endif /* __CLIPPER_H__ */
diff --git a/src/devices/cpu/clipper/clipperd.cpp b/src/devices/cpu/clipper/clipperd.cpp
new file mode 100644
index 00000000000..414817e3a8f
--- /dev/null
+++ b/src/devices/cpu/clipper/clipperd.cpp
@@ -0,0 +1,239 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#include "emu.h"
+
+enum
+{
+ ADDR_MODE_PC32 = 0x10,
+ ADDR_MODE_ABS32 = 0x30,
+ ADDR_MODE_REL32 = 0x60,
+ ADDR_MODE_PC16 = 0x90,
+ ADDR_MODE_REL12 = 0xA0,
+ ADDR_MODE_ABS16 = 0xB0,
+ ADDR_MODE_PCX = 0xD0,
+ ADDR_MODE_RELX = 0xE0,
+};
+
+#define R1 ((insn[0] & 0x00F0) >> 4)
+#define R2 (insn[0] & 0x000F)
+
+#define I16 ((int16_t)insn[1])
+#define I32 (*(int32_t *)&insn[1])
+#define IMM_VALUE (insn[0] & 0x0080 ? I16 : I32)
+#define IMM_SIZE (insn[0] & 0x0080 ? 2 : 4)
+
+#define ADDR_MODE (insn[0] & 0x00F0)
+#define ADDR_R2 ((insn[0] & 0x0050) == 0x0010 ? (insn[0] & 0x000F) : (insn[1] & 0x000F))
+#define ADDR_SIZE (ADDR_MODE > ADDR_MODE_REL32 ? 2 : ADDR_MODE == ADDR_MODE_REL32 ? 6 : 4)
+#define ADDR_RX ((insn[1] & 0xF0) >> 4)
+#define ADDR_I12 (((int16_t)insn[1]) >> 4)
+
+char *address (offs_t pc, uint16_t *insn)
+{
+ static char buffer[32];
+
+ switch (ADDR_MODE)
+ {
+ case ADDR_MODE_PC32: sprintf(buffer, "0x%X", pc + I32); break;
+ case ADDR_MODE_ABS32: sprintf(buffer, "0x%X", I32); break;
+ case ADDR_MODE_REL32: sprintf(buffer, "%d(r%d)", *(int32_t *)&insn[2], R2); break;
+ case ADDR_MODE_PC16: sprintf(buffer, "0x%X", pc + I16); break;
+ case ADDR_MODE_REL12: sprintf(buffer, "%d(r%d)", ADDR_I12, R2); break;
+ case ADDR_MODE_ABS16: sprintf(buffer, "0x%X", I16); break;
+ case ADDR_MODE_PCX: sprintf(buffer, "[r%d](pc)", ADDR_RX); break;
+ case ADDR_MODE_RELX: sprintf(buffer, "[r%d](r%d)", ADDR_RX, R2); break;
+ default: sprintf(buffer, "ERROR"); break;
+ }
+
+ return buffer;
+}
+
+CPU_DISASSEMBLE(clipper)
+{
+ uint16_t *insn = (uint16_t *)oprom;
+ offs_t bytes;
+
+ // TODO: substitute for 'fp' and 'sp' register names?
+ // TODO: branch conditions
+
+ switch (insn[0] >> 8)
+ {
+ case 0x00:
+ if (oprom[0] == 0)
+ util::stream_format(stream, "noop");
+ else
+ util::stream_format(stream, "noop $%d", oprom[0]);
+ bytes = 2;
+ break;
+
+ case 0x10: util::stream_format(stream, "movwp r%d,%s", R2, R1 == 0 ? "psw" : R1 == 1 ? "ssw" : "sswf"); bytes = 2; break;
+ case 0x11: util::stream_format(stream, "movpw %s,r%d", R1 == 0 ? "psw" : "ssw", R2); bytes = 2; break;
+ case 0x12: util::stream_format(stream, "calls $%d", insn[0] & 0x7F); bytes = 2; break;
+ case 0x13: util::stream_format(stream, "ret r%d", R2); bytes = 2; break;
+ case 0x14: util::stream_format(stream, "pushw r%d,r%d", R2, R1); bytes = 2; break;
+
+ case 0x16: util::stream_format(stream, "popw r%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0x20: util::stream_format(stream, "adds f%d,f%d", R1, R2); bytes = 2; break;
+ case 0x21: util::stream_format(stream, "subs f%d,f%d", R1, R2); bytes = 2; break;
+ case 0x22: util::stream_format(stream, "addd f%d,f%d", R1, R2); bytes = 2; break;
+ case 0x23: util::stream_format(stream, "subd f%d,f%d", R1, R2); bytes = 2; break;
+ case 0x24: util::stream_format(stream, "movs f%d,f%d", R1, R2); bytes = 2; break;
+ case 0x25: util::stream_format(stream, "cmps f%d,f%d", R1, R2); bytes = 2; break;
+ case 0x26: util::stream_format(stream, "movd f%d,f%d", R1, R2); bytes = 2; break;
+ case 0x27: util::stream_format(stream, "cmpd f%d,f%d", R1, R2); bytes = 2; break;
+ case 0x28: util::stream_format(stream, "muls f%d,f%d", R1, R2); bytes = 2; break;
+ case 0x29: util::stream_format(stream, "divs f%d,f%d", R1, R2); bytes = 2; break;
+ case 0x2A: util::stream_format(stream, "muld f%d,f%d", R1, R2); bytes = 2; break;
+ case 0x2B: util::stream_format(stream, "divd f%d,f%d", R1, R2); bytes = 2; break;
+ case 0x2C: util::stream_format(stream, "movsw f%d,r%d", R1, R2); bytes = 2; break;
+ case 0x2D: util::stream_format(stream, "movws r%d,f%d", R1, R2); bytes = 2; break;
+ case 0x2E: util::stream_format(stream, "movdl f%d,r%d:%d", R1, R2 + 0, R2 + 1); bytes = 2; break;
+ case 0x2F: util::stream_format(stream, "movld r%d:r%d,f%d", R1 + 0, R1 + 1, R2); bytes = 2; break;
+
+ case 0x30: util::stream_format(stream, "shaw r%d,r%d", R1, R2); bytes = 2; break;
+ case 0x31: util::stream_format(stream, "shal r%d,r%d:r%d", R1, R2 + 0, R2 + 1); bytes = 2; break;
+ case 0x32: util::stream_format(stream, "shlw r%d,r%d", R1, R2); bytes = 2; break;
+ case 0x33: util::stream_format(stream, "shll r%d,r%d:r%d", R1, R2 + 0, R2 + 1); bytes = 2; break;
+ case 0x34: util::stream_format(stream, "rotw r%d,r%d", R1, R2); bytes = 2; break;
+ case 0x35: util::stream_format(stream, "rotl r%d,r%d:r%d", R1, R2 + 0, R2 + 1); bytes = 2; break;
+
+ case 0x38: util::stream_format(stream, "shai $%d,r%d", I16, R2); bytes = 4; break;
+ case 0x39: util::stream_format(stream, "shali $%d,r%d:r%d", I16, R2 + 0, R2 + 1); bytes = 4; break;
+ case 0x3A: util::stream_format(stream, "shli $%d,r%d", I16, R2); bytes = 4; break;
+ case 0x3B: util::stream_format(stream, "shlli $%d,r%d:r%d", I16, R2 + 0, R2 + 1); bytes = 4; break;
+ case 0x3C: util::stream_format(stream, "roti $%d,r%d", I16, R2); bytes = 4; break;
+ case 0x3D: util::stream_format(stream, "rotli $%d,r%d:r%d", I16, R2 + 0, R2 + 1); bytes = 4; break;
+
+ case 0x44: util::stream_format(stream, "call r%d,(r%d)", R2, R1); bytes = 2; break;
+ case 0x45: util::stream_format(stream, "call r%d,%s", ADDR_R2, address(pc, insn)); bytes = 2 + ADDR_SIZE; break;
+
+ case 0x48: util::stream_format(stream, "b* (r%d)", R1); bytes = 2; break;
+ case 0x49: util::stream_format(stream, "b* %s", address(pc, insn)); bytes = 2 + ADDR_SIZE; break;
+
+ case 0x4C: util::stream_format(stream, "bf* (r%d)", R1); bytes = 2; break;
+ case 0x4D: util::stream_format(stream, "bf* %s", address(pc, insn)); bytes = 2 + ADDR_SIZE; break;
+
+ case 0x60: util::stream_format(stream, "loadw (r%d),r%d", R1, R2); bytes = 2; break;
+ case 0x61: util::stream_format(stream, "loadw %s,r%d", address(pc, insn), ADDR_R2); bytes = 2 + ADDR_SIZE; break;
+ case 0x62: util::stream_format(stream, "loada (r%d),r%d", R1, R2); bytes = 2; break;
+ case 0x63: util::stream_format(stream, "loada %s,r%d", address(pc, insn), ADDR_R2); bytes = 2 + ADDR_SIZE; break;
+ case 0x64: util::stream_format(stream, "loads (r%d),f%d", R1, R2); bytes = 2; break;
+ case 0x65: util::stream_format(stream, "loads %s,f%d", address(pc, insn), ADDR_R2); bytes = 2 + ADDR_SIZE; break;
+ case 0x66: util::stream_format(stream, "loadd (r%d),f%d", R1, R2); bytes = 2; break;
+ case 0x67: util::stream_format(stream, "loadd %s,f%d", address(pc, insn), ADDR_R2); bytes = 2 + ADDR_SIZE; break;
+ case 0x68: util::stream_format(stream, "loadb (r%d),r%d", R1, R2); bytes = 2; break;
+ case 0x69: util::stream_format(stream, "loadb %s,r%d", address(pc, insn), ADDR_R2); bytes = 2 + ADDR_SIZE; break;
+ case 0x6A: util::stream_format(stream, "loadbu (r%d),r%d", R1, R2); bytes = 2; break;
+ case 0x6B: util::stream_format(stream, "loadbu %s,r%d", address(pc, insn), ADDR_R2); bytes = 2 + ADDR_SIZE; break;
+ case 0x6C: util::stream_format(stream, "loadh (r%d),r%d", R1, R2); bytes = 2; break;
+ case 0x6D: util::stream_format(stream, "loadh %s,r%d", address(pc, insn), ADDR_R2); bytes = 2 + ADDR_SIZE; break;
+ case 0x6E: util::stream_format(stream, "loadhu (r%d),r%d", R1, R2); bytes = 2; break;
+ case 0x6F: util::stream_format(stream, "loadhu %s,r%d", address(pc, insn), ADDR_R2); bytes = 2 + ADDR_SIZE; break;
+
+ case 0x70: util::stream_format(stream, "storw r%d,(r%d)", R2, R1); bytes = 2; break;
+ case 0x71: util::stream_format(stream, "storw r%d,%s", ADDR_R2, address(pc, insn)); bytes = 2 + ADDR_SIZE; break;
+ case 0x72: util::stream_format(stream, "tsts (r%d),r%d", R1, R2); bytes = 2; break;
+ case 0x73: // tsts
+ case 0x74: util::stream_format(stream, "stors f%d,(r%d)", R2, R1); bytes = 2; break;
+ case 0x75: util::stream_format(stream, "stors f%d,%s", ADDR_R2, address(pc, insn)); bytes = 2 + ADDR_SIZE; break;
+ case 0x76: util::stream_format(stream, "stord f%d,(r%d)", R2, R1); bytes = 2; break;
+ case 0x77: util::stream_format(stream, "stord f%d,%s", ADDR_R2, address(pc, insn)); bytes = 2 + ADDR_SIZE; break;
+ case 0x78: util::stream_format(stream, "storb r%d,(r%d)", R2, R1); bytes = 2; break;
+ case 0x79: util::stream_format(stream, "storb r%d,%s", ADDR_R2, address(pc, insn)); bytes = 2 + ADDR_SIZE; break;
+
+ case 0x7C: util::stream_format(stream, "storh r%d,(r%d)", R2, R1); bytes = 2; break;
+ case 0x7D: util::stream_format(stream, "storh r%d,%s", ADDR_R2, address(pc, insn)); bytes = 2 + ADDR_SIZE; break;
+
+ case 0x80: util::stream_format(stream, "addw r%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0x82: util::stream_format(stream, "addq $%d,r%d", R1, R2); bytes = 2; break;
+ case 0x83: util::stream_format(stream, "addi $%d,r%d", IMM_VALUE, R2); bytes = 2 + IMM_SIZE; break;
+ case 0x84: util::stream_format(stream, "movw r%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0x86: util::stream_format(stream, "loadq $%d,r%d", R1, R2); bytes = 2; break;
+ case 0x87: util::stream_format(stream, "loadi $%d,r%d", IMM_VALUE, R2); bytes = 2 + IMM_SIZE; break;
+ case 0x88: util::stream_format(stream, "andw r%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0x8B: util::stream_format(stream, "andi $%d,r%d", IMM_VALUE, R2); bytes = 2 + IMM_SIZE; break;
+ case 0x8C: util::stream_format(stream, "orw r%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0x8F: util::stream_format(stream, "ori $%d,r%d", IMM_VALUE, R2); bytes = 2 + IMM_SIZE; break;
+
+ case 0x90: util::stream_format(stream, "addwc r%d,r%d", R1, R2); bytes = 2; break;
+ case 0x91: util::stream_format(stream, "subwc r%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0x93: util::stream_format(stream, "negw r%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0x98: util::stream_format(stream, "mulw r%d,r%d", R1, R2); bytes = 2; break;
+ case 0x99: util::stream_format(stream, "mulwx r%d,r%d:r%d", R1, R2 + 0, R2 + 1); bytes = 2; break;
+ case 0x9A: util::stream_format(stream, "mulwu r%d,r%d", R1, R2); bytes = 2; break;
+ case 0x9B: util::stream_format(stream, "mulwux r%d,r%d:r%d", R1, R2 + 0, R2 + 1); bytes = 2; break;
+ case 0x9C: util::stream_format(stream, "divw r%d,r%d", R1, R2); bytes = 2; break;
+ case 0x9D: util::stream_format(stream, "modw r%d,r%d", R1, R2); bytes = 2; break;
+ case 0x9E: util::stream_format(stream, "divwu r%d,r%d", R1, R2); bytes = 2; break;
+ case 0x9F: util::stream_format(stream, "modwu r%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0xA0: util::stream_format(stream, "subw r%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0xA2: util::stream_format(stream, "subq $%d,r%d", R1, R2); bytes = 2; break;
+ case 0xA3: util::stream_format(stream, "subi $%d,r%d", IMM_VALUE, R2); bytes = 2 + IMM_SIZE; break;
+ case 0xA4: util::stream_format(stream, "cmpw r%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0xA6: util::stream_format(stream, "cmpq $%d,r%d", R1, R2); bytes = 2; break;
+ case 0xA7: util::stream_format(stream, "cmpi $%d,r%d", IMM_VALUE, R2); bytes = 2 + IMM_SIZE; break;
+ case 0xA8: util::stream_format(stream, "xorw r%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0xAB: util::stream_format(stream, "xori $%d,r%d", IMM_VALUE, R2); bytes = 2 + IMM_SIZE; break;
+ case 0xAC: util::stream_format(stream, "notw r%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0xAE: util::stream_format(stream, "notq $%d,r%d", R1, R2); bytes = 2; break;
+
+ case 0xB4: // macro
+ case 0xB5: // macro
+ switch (insn[0] & 0xff)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ case 0x08: case 0x09: case 0x0A: case 0x0B:
+ case 0x0C:
+ util::stream_format(stream, "savew%d", R2);
+ break;
+
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1A: case 0x1B:
+ case 0x1C:
+ util::stream_format(stream, "restw%d", R2);
+ break;
+
+ default:
+ util::stream_format(stream, "macro 0x%04X %04X", insn[0], insn[1]);
+ break;
+ }
+ bytes = 4;
+ break;
+ case 0xB6: // macro
+ case 0xB7: // macro
+ switch (insn[0] & 0xff)
+ {
+ case 0x00: util::stream_format(stream, "movus r%d,r%d", (insn[1] & 0xf0) >> 4, insn[1] & 0xf); break;
+ case 0x01: util::stream_format(stream, "movsu r%d,r%d", (insn[1] & 0xf0) >> 4, insn[1] & 0xf); break;
+ case 0x04: util::stream_format(stream, "reti r%d", (insn[1] & 0xf0) >> 4); break;
+
+ default:
+ util::stream_format(stream, "macro 0x%04X %04X", insn[0], insn[1]);
+ break;
+ }
+ bytes = 4;
+ break;
+
+ default:
+ util::stream_format(stream, ".word 0x%04X ; invalid", insn[0]);
+ bytes = 2;
+ break;
+ }
+
+ return bytes;
+} \ No newline at end of file