1182 lines
31 KiB
C++
1182 lines
31 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:Patrick Mackinlay
|
|
|
|
#include "emu.h"
|
|
#include "debugger.h"
|
|
#include "clipper.h"
|
|
|
|
#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(STATE_GENSP, "GENSP", m_r[m_ssw.bits.u][15]).noshow();
|
|
state_add(STATE_GENFLAGS, "GENFLAGS", m_psw.d).mask(0xf).formatstr("%4s").noshow();
|
|
|
|
state_add(CLIPPER_PC, "pc", m_pc);
|
|
state_add(CLIPPER_PSW, "psw", m_psw.d);
|
|
state_add(CLIPPER_SSW, "ssw", m_ssw.d);
|
|
|
|
state_add(CLIPPER_R0, "r0", m_r[m_ssw.bits.u][0]);
|
|
state_add(CLIPPER_R1, "r1", m_r[m_ssw.bits.u][1]);
|
|
state_add(CLIPPER_R2, "r2", m_r[m_ssw.bits.u][2]);
|
|
state_add(CLIPPER_R3, "r3", m_r[m_ssw.bits.u][3]);
|
|
state_add(CLIPPER_R4, "r4", m_r[m_ssw.bits.u][4]);
|
|
state_add(CLIPPER_R5, "r5", m_r[m_ssw.bits.u][5]);
|
|
state_add(CLIPPER_R6, "r6", m_r[m_ssw.bits.u][6]);
|
|
state_add(CLIPPER_R7, "r7", m_r[m_ssw.bits.u][7]);
|
|
state_add(CLIPPER_R8, "r8", m_r[m_ssw.bits.u][8]);
|
|
state_add(CLIPPER_R9, "r9", m_r[m_ssw.bits.u][9]);
|
|
state_add(CLIPPER_R10, "r10", m_r[m_ssw.bits.u][10]);
|
|
state_add(CLIPPER_R11, "r11", m_r[m_ssw.bits.u][11]);
|
|
state_add(CLIPPER_R12, "r12", m_r[m_ssw.bits.u][12]);
|
|
state_add(CLIPPER_R13, "r13", m_r[m_ssw.bits.u][13]);
|
|
state_add(CLIPPER_R14, "r14", m_r[m_ssw.bits.u][14]);
|
|
state_add(CLIPPER_R15, "r15", m_r[m_ssw.bits.u][15]);
|
|
|
|
state_add(CLIPPER_F0, "f0", m_f[0]);
|
|
state_add(CLIPPER_F1, "f1", m_f[1]);
|
|
state_add(CLIPPER_F2, "f2", m_f[2]);
|
|
state_add(CLIPPER_F3, "f3", m_f[3]);
|
|
state_add(CLIPPER_F4, "f4", m_f[4]);
|
|
state_add(CLIPPER_F5, "f5", m_f[5]);
|
|
state_add(CLIPPER_F6, "f6", m_f[6]);
|
|
state_add(CLIPPER_F7, "f7", m_f[7]);
|
|
state_add(CLIPPER_F8, "f8", m_f[8]);
|
|
state_add(CLIPPER_F9, "f9", m_f[9]);
|
|
state_add(CLIPPER_F10, "f10", m_f[10]);
|
|
state_add(CLIPPER_F11, "f11", m_f[11]);
|
|
state_add(CLIPPER_F12, "f12", m_f[12]);
|
|
state_add(CLIPPER_F13, "f13", m_f[13]);
|
|
state_add(CLIPPER_F14, "f14", m_f[14]);
|
|
state_add(CLIPPER_F15, "f15", m_f[15]);
|
|
}
|
|
|
|
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())
|
|
{
|
|
case STATE_GENFLAGS:
|
|
str = string_format("%c%c%c%c",
|
|
m_psw.bits.c ? 'C' : ' ',
|
|
m_psw.bits.v ? 'V' : ' ',
|
|
m_psw.bits.z ? 'Z' : ' ',
|
|
m_psw.bits.n ? 'N' : ' ');
|
|
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)
|
|
{
|
|
// this variable is used to return the next execution location to the caller
|
|
uint32_t next_pc = 0;
|
|
|
|
// this union holds operands used by instructions with immediate
|
|
// values, complex addressing modes or macro instructions
|
|
union {
|
|
int32_t imm;
|
|
uint32_t r2;
|
|
uint16_t macro;
|
|
} op;
|
|
op.imm = op.r2 = op.macro = 0;
|
|
|
|
// holds the effective address for instructions with complex addressing modes
|
|
uint32_t address = 0;
|
|
|
|
// decode complex instruction formats
|
|
if ((insn & 0xf800) == 0x3800 || (insn & 0xd300) == 0x8300)
|
|
{
|
|
// instruction has an immediate operand: decode 16 and 32 bit cases
|
|
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)
|
|
{
|
|
// instruction has a complex addressing mode (b*, bf*, call, load*, stor*)
|
|
// decode the operands and compute the effective address
|
|
uint16_t temp;
|
|
|
|
switch (insn & 0x00f0)
|
|
{
|
|
case ADDR_MODE_PC32:
|
|
op.r2 = R2;
|
|
address = m_pc + (int32_t)m_direct->read_dword(m_pc + 2);
|
|
next_pc = m_pc + 6;
|
|
break;
|
|
|
|
case ADDR_MODE_ABS32:
|
|
op.r2 = R2;
|
|
address = 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;
|
|
address = 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;
|
|
address = 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;
|
|
address = m_r[m_ssw.bits.u][R2] + ((int16_t)temp >> 4);
|
|
next_pc = m_pc + 4;
|
|
break;
|
|
|
|
case ADDR_MODE_ABS16:
|
|
op.r2 = R2;
|
|
address = (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;
|
|
address = 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;
|
|
address = 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
|
|
// all other instruction formats are 16 bits
|
|
next_pc = m_pc + 2;
|
|
|
|
switch (insn >> 8)
|
|
{
|
|
case 0x00: // noop
|
|
break;
|
|
|
|
case 0x10:
|
|
// movwp: move word to processor register
|
|
// 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: move processor register to word
|
|
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: call supervisor
|
|
next_pc = intrap(0x400 + (insn & 0x7f) * 8, next_pc);
|
|
break;
|
|
case 0x13:
|
|
// ret: return from subroutine
|
|
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: push word
|
|
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: pop word
|
|
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:
|
|
// subs: subtract single floating
|
|
*((float *)&m_f[R2]) -= *((float *)&m_f[R1]);
|
|
break;
|
|
case 0x21:
|
|
// adds: add single floating
|
|
*((float *)&m_f[R2]) += *((float *)&m_f[R1]);
|
|
break;
|
|
case 0x22:
|
|
// addd: add double floating
|
|
m_f[R2] += m_f[R1];
|
|
break;
|
|
case 0x23:
|
|
// subd: subtract double floating
|
|
m_f[R2] -= m_f[R1];
|
|
break;
|
|
case 0x24:
|
|
// movs: move single floating
|
|
*((float *)&m_f[R2]) = *((float *)&m_f[R1]);
|
|
break;
|
|
case 0x25:
|
|
// cmps: compare single floating
|
|
evaluate_cc2f(*((float *)&m_f[R2]), *((float *)&m_f[R1]));
|
|
break;
|
|
case 0x26:
|
|
// movd: move double floating
|
|
m_f[R2] = m_f[R1];
|
|
break;
|
|
case 0x27:
|
|
// cmpd: compare double floating
|
|
evaluate_cc2f(m_f[R2], m_f[R1]);
|
|
break;
|
|
case 0x2a:
|
|
// muld: multiple double floating
|
|
m_f[R2] *= m_f[R1];
|
|
break;
|
|
case 0x2b:
|
|
// divd: divide double floating
|
|
m_f[R2] /= m_f[R1];
|
|
break;
|
|
case 0x2c:
|
|
// movsw: move single floating to word
|
|
m_r[m_ssw.bits.u][R2] = *((int32_t *)&m_f[R1]);
|
|
break;
|
|
case 0x2d:
|
|
// movws: move word to single floating
|
|
*((int32_t *)&m_f[R2]) = m_r[m_ssw.bits.u][R1];
|
|
break;
|
|
case 0x2e:
|
|
// movdl: move double floating to longword
|
|
((double *)m_r[m_ssw.bits.u])[R2 >> 1] = m_f[R1];
|
|
break;
|
|
case 0x2f:
|
|
// movld: move longword to double floating
|
|
m_f[R2] = ((double *)m_r[m_ssw.bits.u])[R1 >> 1];
|
|
break;
|
|
|
|
case 0x30:
|
|
// shaw: shift arithmetic word
|
|
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: shift arithmetic longword
|
|
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: shift logical word
|
|
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: shift logical longword
|
|
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: rotate word
|
|
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: rotate longword
|
|
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: shift arithmetic immediate
|
|
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: shift arithmetic longword immediate
|
|
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: shift logical immediate
|
|
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: shift logical longword immediate
|
|
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: rotate immediate
|
|
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: rotate longword immediate
|
|
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: call subroutine (relative)
|
|
m_r[m_ssw.bits.u][R2] -= 4;
|
|
m_program->write_dword(m_r[m_ssw.bits.u][R2], next_pc);
|
|
next_pc = m_r[m_ssw.bits.u][R1];
|
|
break;
|
|
case 0x45:
|
|
// call: call subroutine (other modes)
|
|
m_r[m_ssw.bits.u][op.r2] -= 4;
|
|
m_program->write_dword(m_r[m_ssw.bits.u][op.r2], next_pc);
|
|
next_pc = address;
|
|
break;
|
|
#ifdef UNIMPLEMENTED
|
|
case 0x46:
|
|
// loadd2:
|
|
break;
|
|
case 0x47:
|
|
// loadd2:
|
|
break;
|
|
#endif
|
|
case 0x48:
|
|
// b*: branch on condition (relative)
|
|
if (evaluate_branch(R2))
|
|
next_pc = m_r[m_ssw.bits.u][R1];
|
|
break;
|
|
case 0x49:
|
|
// b*: branch on condition (other modes)
|
|
if (evaluate_branch(op.r2))
|
|
next_pc = address;
|
|
break;
|
|
#ifdef UNIMPLEMENTED
|
|
case 0x4a:
|
|
// cdb:
|
|
break;
|
|
case 0x4b:
|
|
// cdb:
|
|
break;
|
|
case 0x4c:
|
|
// bf*/cdbeq:
|
|
break;
|
|
case 0x4d:
|
|
// bf*/cdbeq:
|
|
break;
|
|
case 0x4e:
|
|
// cdbne:
|
|
break;
|
|
case 0x4f:
|
|
// cdbne:
|
|
break;
|
|
|
|
case 0x50:
|
|
// db*:
|
|
break;
|
|
case 0x51:
|
|
// db*:
|
|
break;
|
|
#endif
|
|
|
|
case 0x60:
|
|
// loadw: load word (relative)
|
|
m_r[m_ssw.bits.u][R2] = m_program->read_dword(m_r[m_ssw.bits.u][R1]);
|
|
break;
|
|
case 0x61:
|
|
// loadw: load word (other modes)
|
|
m_r[m_ssw.bits.u][op.r2] = m_program->read_dword(address);
|
|
break;
|
|
case 0x62:
|
|
// loada: load address (relative)
|
|
m_r[m_ssw.bits.u][R2] = m_r[m_ssw.bits.u][R1];
|
|
break;
|
|
case 0x63:
|
|
// loada: load address (other modes)
|
|
m_r[m_ssw.bits.u][op.r2] = address;
|
|
break;
|
|
case 0x64:
|
|
// loads: load single floating (relative)
|
|
((uint64_t *)&m_f)[R2] = m_program->read_dword(m_r[m_ssw.bits.u][R1]);
|
|
break;
|
|
case 0x65:
|
|
// loads: load single floating (other modes)
|
|
((uint64_t *)&m_f)[op.r2] = m_program->read_dword(address);
|
|
break;
|
|
case 0x66:
|
|
// loadd: load double floating (relative)
|
|
((uint64_t *)&m_f)[R2] = m_program->read_qword(m_r[m_ssw.bits.u][R1]);
|
|
break;
|
|
case 0x67:
|
|
// loadd: load double floating (other modes)
|
|
((uint64_t *)&m_f)[op.r2] = m_program->read_qword(address);
|
|
break;
|
|
case 0x68:
|
|
// loadb: load byte (relative)
|
|
m_r[m_ssw.bits.u][R2] = (int8_t)m_program->read_byte(m_r[m_ssw.bits.u][R1]);
|
|
break;
|
|
case 0x69:
|
|
// loadb: load byte (other modes)
|
|
m_r[m_ssw.bits.u][op.r2] = (int8_t)m_program->read_byte(address);
|
|
break;
|
|
case 0x6a:
|
|
// loadbu: load byte unsigned (relative)
|
|
m_r[m_ssw.bits.u][R2] = (uint8_t)m_program->read_byte(m_r[m_ssw.bits.u][R1]);
|
|
break;
|
|
case 0x6b:
|
|
// loadbu: load byte unsigned (other modes)
|
|
m_r[m_ssw.bits.u][op.r2] = m_program->read_byte(address);
|
|
break;
|
|
case 0x6c:
|
|
// loadh: load halfword (relative)
|
|
m_r[m_ssw.bits.u][R2] = (int16_t)m_program->read_word(m_r[m_ssw.bits.u][R1]);
|
|
break;
|
|
case 0x6d:
|
|
// loadh: load halfword (other modes)
|
|
m_r[m_ssw.bits.u][op.r2] = (int16_t)m_program->read_word(address);
|
|
break;
|
|
case 0x6e:
|
|
// loadhu: load halfword unsigned (relative)
|
|
m_r[m_ssw.bits.u][R2] = (uint16_t)m_program->read_word(m_r[m_ssw.bits.u][R1]);
|
|
break;
|
|
case 0x6f:
|
|
// loadhu: load halfword unsigned (other modes)
|
|
m_r[m_ssw.bits.u][op.r2] = m_program->read_word(address);
|
|
break;
|
|
case 0x70:
|
|
// storw: store word (relative)
|
|
m_program->write_dword(m_r[m_ssw.bits.u][R1], m_r[m_ssw.bits.u][R2]);
|
|
break;
|
|
case 0x71:
|
|
// storw: store word (other modes)
|
|
m_program->write_dword(address, m_r[m_ssw.bits.u][op.r2]);
|
|
break;
|
|
case 0x72:
|
|
// tsts: test and set (relative)
|
|
m_r[m_ssw.bits.u][R2] = m_program->read_dword(m_r[m_ssw.bits.u][R1]);
|
|
m_program->write_dword(m_r[m_ssw.bits.u][R1], m_r[m_ssw.bits.u][R2] | 0x80000000);
|
|
break;
|
|
case 0x73:
|
|
// tsts: test and set (other modes)
|
|
m_r[m_ssw.bits.u][R2] = m_program->read_dword(address);
|
|
m_program->write_dword(address, m_r[m_ssw.bits.u][R2] | 0x80000000);
|
|
break;
|
|
case 0x74:
|
|
// stors: store single floating (relative)
|
|
m_program->write_dword(m_r[m_ssw.bits.u][R1], *((uint32_t *)&m_f[R2]));
|
|
break;
|
|
case 0x75:
|
|
// stors: store single floating (other modes)
|
|
m_program->write_dword(address, *((uint32_t *)&m_f[op.r2]));
|
|
break;
|
|
case 0x76:
|
|
// stord: store double floating (relative)
|
|
m_program->write_qword(m_r[m_ssw.bits.u][R1], *((uint64_t *)&m_f[R2]));
|
|
break;
|
|
case 0x77:
|
|
// stord: store double floating (other modes)
|
|
m_program->write_qword(address, *((uint64_t *)&m_f[op.r2]));
|
|
break;
|
|
case 0x78:
|
|
// storb: store byte (relative)
|
|
m_program->write_byte(m_r[m_ssw.bits.u][R1], (uint8_t)m_r[m_ssw.bits.u][R2]);
|
|
break;
|
|
case 0x79:
|
|
// storb: store byte (other modes)
|
|
m_program->write_byte(address, (uint8_t)m_r[m_ssw.bits.u][op.r2]);
|
|
break;
|
|
|
|
case 0x7c:
|
|
// storh: store halfword (relative)
|
|
m_program->write_word(m_r[m_ssw.bits.u][R1], (uint16_t)m_r[m_ssw.bits.u][R2]);
|
|
break;
|
|
case 0x7d:
|
|
// storh: store halfword (other modes)
|
|
m_program->write_word(address, (uint16_t)m_r[m_ssw.bits.u][op.r2]);
|
|
break;
|
|
|
|
case 0x80:
|
|
// addw: add word
|
|
m_r[m_ssw.bits.u][R2] += m_r[m_ssw.bits.u][R1];
|
|
break;
|
|
|
|
case 0x82:
|
|
// addq: add quick
|
|
m_r[m_ssw.bits.u][R2] += R1;
|
|
break;
|
|
case 0x83:
|
|
// addi: add immediate
|
|
m_r[m_ssw.bits.u][R2] += op.imm;
|
|
break;
|
|
case 0x84:
|
|
// movw: move word
|
|
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: load quick
|
|
m_r[m_ssw.bits.u][R2] = R1;
|
|
break;
|
|
case 0x87:
|
|
// loadi: load immediate
|
|
m_r[m_ssw.bits.u][R2] = op.imm;
|
|
break;
|
|
case 0x88:
|
|
// andw: and word
|
|
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: and immediate
|
|
m_r[m_ssw.bits.u][R2] &= op.imm;
|
|
evaluate_cc1(m_r[m_ssw.bits.u][R2]);
|
|
break;
|
|
case 0x8c:
|
|
// orw: or word
|
|
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: or immediate
|
|
m_r[m_ssw.bits.u][R2] |= op.imm;
|
|
evaluate_cc1(m_r[m_ssw.bits.u][R2]);
|
|
break;
|
|
#ifdef UNIMPLEMENTED
|
|
case 0x90:
|
|
// addwc: add word with carry
|
|
m_r[m_ssw.bits.u][r2] += m_r[m_ssw.bits.u][r1] + psw.b.c;
|
|
break;
|
|
case 0x91:
|
|
// subwc: subtract word with carry
|
|
m_r[m_ssw.bits.u][r2] -= m_r[m_ssw.bits.u][r1] + psw.b.c;
|
|
break;
|
|
#endif
|
|
|
|
case 0x93:
|
|
// negw: negate word
|
|
m_r[m_ssw.bits.u][R2] = -(int32_t)m_r[m_ssw.bits.u][R1];
|
|
break;
|
|
|
|
case 0x98:
|
|
// mulw: multiply word
|
|
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;
|
|
#ifdef UNIMPLEMENTED
|
|
case 0x99:
|
|
// mulwx: multiply word extended
|
|
break;
|
|
#endif
|
|
case 0x9a:
|
|
// mulwu: multiply word unsigned
|
|
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;
|
|
#ifdef UNIMPLEMENTED
|
|
case 0x9b:
|
|
// mulwux: multiply word unsigned extended
|
|
break;
|
|
#endif
|
|
case 0x9c:
|
|
// divw: divide word
|
|
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: modulus word
|
|
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: divide word unsigned
|
|
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: modulus word unsigned
|
|
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: subtract word
|
|
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: subtract quick
|
|
evaluate_cc2(m_r[m_ssw.bits.u][R2], R1);
|
|
m_r[m_ssw.bits.u][R2] -= R1;
|
|
break;
|
|
case 0xa3:
|
|
// subi: subtract immediate
|
|
evaluate_cc2(m_r[m_ssw.bits.u][R2], op.imm);
|
|
m_r[m_ssw.bits.u][R2] -= op.imm;
|
|
break;
|
|
case 0xa4:
|
|
// cmpw: compare word
|
|
evaluate_cc2(m_r[m_ssw.bits.u][R2], m_r[m_ssw.bits.u][R1]);
|
|
break;
|
|
|
|
case 0xa6:
|
|
// cmpq: compare quick
|
|
evaluate_cc2(m_r[m_ssw.bits.u][R2], R1);
|
|
break;
|
|
case 0xa7:
|
|
// cmpi: compare immediate
|
|
evaluate_cc2(m_r[m_ssw.bits.u][R2], op.imm);
|
|
break;
|
|
case 0xa8:
|
|
// xorw: exclusive or word
|
|
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: exclusive or immediate
|
|
m_r[m_ssw.bits.u][R2] ^= op.imm;
|
|
evaluate_cc1(m_r[m_ssw.bits.u][R2]);
|
|
break;
|
|
case 0xac:
|
|
// notw: not word
|
|
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: not quick
|
|
m_r[m_ssw.bits.u][R2] = ~R1;
|
|
evaluate_cc1(m_r[m_ssw.bits.u][R2]);
|
|
break;
|
|
|
|
#ifdef UNIMPLEMENTED
|
|
case 0xb0:
|
|
// abss: absolute value single floating?
|
|
break;
|
|
|
|
case 0xb2:
|
|
// absd: absolute value double floating?
|
|
break;
|
|
#endif
|
|
|
|
case 0xb4:
|
|
// unprivileged macro instructions
|
|
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 rN:r14
|
|
|
|
// store ri at sp - 4 * (15 - i)
|
|
for (int i = R2; i < 15; i++)
|
|
m_program->write_dword(m_r[m_ssw.bits.u][15] - 4 * (15 - i), m_r[m_ssw.bits.u][i]);
|
|
|
|
// decrement sp after push to allow restart on exceptions
|
|
m_r[m_ssw.bits.u][15] -= 4 * (15 - R2);
|
|
break;
|
|
|
|
// NOTE: the movc, initc and cmpc macro instructions are implemented in a very basic way because
|
|
// at some point they will need to be improved to deal with possible exceptions (e.g. page faults)
|
|
// that may occur during execution. The implementation here is intended to allow the instructions
|
|
// to be "continued" after such exceptions.
|
|
case 0x0d:
|
|
// movc: copy r0 bytes from r1 to r2
|
|
|
|
while (m_r[m_ssw.bits.u][0])
|
|
{
|
|
m_program->write_byte(m_r[m_ssw.bits.u][2], m_program->read_byte(m_r[m_ssw.bits.u][1]));
|
|
|
|
m_r[m_ssw.bits.u][0]--;
|
|
m_r[m_ssw.bits.u][1]++;
|
|
m_r[m_ssw.bits.u][2]++;
|
|
}
|
|
break;
|
|
|
|
case 0x0e:
|
|
// initc: initialise r0 bytes at r1 with value in r2
|
|
while (m_r[m_ssw.bits.u][0])
|
|
{
|
|
m_program->write_byte(m_r[m_ssw.bits.u][1], m_r[m_ssw.bits.u][2] & 0xff);
|
|
|
|
m_r[m_ssw.bits.u][0]--;
|
|
m_r[m_ssw.bits.u][1]++;
|
|
m_r[m_ssw.bits.u][2] = _rotr(m_r[m_ssw.bits.u][2], 8);
|
|
}
|
|
break;
|
|
|
|
case 0x0f:
|
|
// cmpc: compare r0 bytes at r1 with r2
|
|
|
|
// set condition codes assuming strings match
|
|
m_psw.bits.n = 0;
|
|
m_psw.bits.z = 1;
|
|
m_psw.bits.v = 0;
|
|
m_psw.bits.c = 0;
|
|
|
|
while (m_r[m_ssw.bits.u][0])
|
|
{
|
|
// set condition codes and abort the loop if the current byte does not match
|
|
uint8_t byte1 = m_program->read_byte(m_r[m_ssw.bits.u][1]);
|
|
uint8_t byte2 = m_program->read_byte(m_r[m_ssw.bits.u][2]);
|
|
if (byte1 != byte2)
|
|
{
|
|
evaluate_cc2(byte1, byte2);
|
|
break;
|
|
}
|
|
|
|
m_r[m_ssw.bits.u][0]--;
|
|
m_r[m_ssw.bits.u][1]++;
|
|
m_r[m_ssw.bits.u][2]++;
|
|
}
|
|
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 rN:r14
|
|
|
|
// load ri from sp + 4 * (i - N)
|
|
for (int i = R2; i < 15; i++)
|
|
m_r[m_ssw.bits.u][i] = m_program->read_dword(m_r[m_ssw.bits.u][15] + 4 * (i - R2));
|
|
|
|
// increment sp after pop to allow restart on exceptions
|
|
m_r[m_ssw.bits.u][15] += 4 * (15 - R2);
|
|
break;
|
|
|
|
case 0x20: case 0x21: case 0x22: case 0x23:
|
|
case 0x24: case 0x25: case 0x26: case 0x27:
|
|
// saved0..saved7: push registers fN:f7
|
|
|
|
// store fi at sp - 8 * (8 - i)
|
|
for (int i = R2; i < 8; i++)
|
|
m_program->write_qword(m_r[m_ssw.bits.u][15] - 8 * (8 - i), m_f[i]);
|
|
|
|
// decrement sp after push to allow restart on exceptions
|
|
m_r[m_ssw.bits.u][15] -= 8 * (8 - R2);
|
|
break;
|
|
|
|
case 0x28: case 0x29: case 0x2a: case 0x2b:
|
|
case 0x2c: case 0x2d: case 0x2e: case 0x2f:
|
|
// restd0..restd7: pop registers fN:f7
|
|
|
|
// load fi from sp + 8 * (i - N)
|
|
for (int i = R2; i < 8; i++)
|
|
m_f[i] = m_program->read_qword(m_r[m_ssw.bits.u][15] + 8 * (i - R2));
|
|
|
|
// increment sp after pop to allow restart on exceptions
|
|
m_r[m_ssw.bits.u][15] += 8 * (8 - R2);
|
|
break;
|
|
#ifdef UNIMPLEMENTED
|
|
case 0x30:
|
|
// cnvsw
|
|
case 0x31:
|
|
// cnvrsw
|
|
case 0x32:
|
|
// cnvtsw
|
|
case 0x33:
|
|
// cnvws
|
|
case 0x34:
|
|
// cnvdw
|
|
case 0x35:
|
|
// cnvrdw
|
|
break;
|
|
#endif
|
|
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;
|
|
#ifdef UNIMPLEMENTED
|
|
case 0x38:
|
|
// cnvsd
|
|
case 0x39:
|
|
// cnvds
|
|
case 0x3a:
|
|
// negs
|
|
case 0x3b:
|
|
// negds
|
|
case 0x3c:
|
|
// scalbs
|
|
case 0x3d:
|
|
// scalbd
|
|
case 0x3e:
|
|
// trapfn
|
|
case 0x3f:
|
|
// loadfs
|
|
break;
|
|
#endif
|
|
default:
|
|
logerror("illegal macro opcode at 0x%08x\n", m_pc);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case 0xb6:
|
|
// privileged macro instructions
|
|
if (m_ssw.bits.u == 0)
|
|
{
|
|
switch (insn & 0xff)
|
|
{
|
|
case 0x00:
|
|
// movus: move user to supervisor
|
|
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: move supervisor to user
|
|
m_r[1][op.macro & 0xf] = m_r[0][(op.macro >> 4) & 0xf];
|
|
// setcc1(m_r[!m_ssw.bits.u][r2]);
|
|
break;
|
|
|
|
case 0x02:
|
|
// saveur: save user registers
|
|
for (int i = 0; i < 16; i++)
|
|
m_program->write_dword(m_r[0][(op.macro >> 4) & 0xf] - 4 * (i + 1), m_r[1][15 - i]);
|
|
|
|
m_r[0][(op.macro >> 4) & 0xf] -= 64;
|
|
break;
|
|
|
|
case 0x03:
|
|
// restur: restore user registers
|
|
for (int i = 0; i < 16; i++)
|
|
m_r[1][i] = m_program->read_dword(m_r[0][(op.macro >> 4) & 0xf] + 4 * i);
|
|
|
|
m_r[0][(op.macro >> 4) & 0xf] += 64;
|
|
break;
|
|
|
|
case 0x04:
|
|
// reti: restore psw, ssw and pc from supervisor stack
|
|
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;
|
|
|
|
case 0x05:
|
|
// wait: wait for interrupt
|
|
next_pc = m_pc;
|
|
break;
|
|
|
|
default:
|
|
// illegal operation
|
|
// TODO: set psw.b.cts
|
|
logerror("illegal opcode at 0x%08x\n", m_pc);
|
|
next_pc = intrap(0x300, next_pc);
|
|
machine().debug_break();
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
// TODO: set psw.b.cts
|
|
next_pc = intrap(0x308, next_pc); // illegal operation, privileged instruction
|
|
break;
|
|
|
|
#ifdef UNIMPLEMENTED
|
|
case 0xbc:
|
|
// waitd:
|
|
break;
|
|
|
|
case 0xc0:
|
|
// sregc:
|
|
break;
|
|
#endif
|
|
|
|
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
|
|
|
|
// NOTE: while not explicitly stated anywhere, it seems the InterPro boot code has been
|
|
// developed with the assumption that the SSP is decremented by 24 bytes during an exception,
|
|
// rather than the 12 bytes that might otherwise be expected. This means the exception handler
|
|
// code must explicitly increment the SSP by 12 prior to executing the RETI instruction,
|
|
// as otherwise the SSP will not be pointing at a valid return frame. It's possible this
|
|
// behaviour might vary with some other version of the CPU, but this is all we know for now.
|
|
m_r[0][15] -= 24;
|
|
|
|
// 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);
|
|
|
|
// 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
|
|
|
|
THEORY:
|
|
for compare, call evaluate_cc2(r1, r2)
|
|
for move/logical, call evaluate_cc2(r2, 0)
|
|
these instructions should only set N or Z
|
|
*/
|
|
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);
|
|
}
|