diff options
author | 2016-12-27 11:24:33 +0700 | |
---|---|---|
committer | 2016-12-27 11:24:33 +0700 | |
commit | f4f7d659a1e7461ec1ef33534a61df8fe1dc1ee3 (patch) | |
tree | b634eeb368c79c8c6b73944a67ea0d07cc93b3fb /src/devices/cpu/clipper | |
parent | 47a690bef71e27f72d5b0f86c6308d8a16539a21 (diff) |
initial commit
Diffstat (limited to 'src/devices/cpu/clipper')
-rw-r--r-- | src/devices/cpu/clipper/clipper.cpp | 871 | ||||
-rw-r--r-- | src/devices/cpu/clipper/clipper.h | 165 | ||||
-rw-r--r-- | src/devices/cpu/clipper/clipperd.cpp | 239 |
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 |