initial commit
This commit is contained in:
parent
47a690bef7
commit
f4f7d659a1
871
src/devices/cpu/clipper/clipper.cpp
Normal file
871
src/devices/cpu/clipper/clipper.cpp
Normal file
@ -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);
|
||||
}
|
165
src/devices/cpu/clipper/clipper.h
Normal file
165
src/devices/cpu/clipper/clipper.h
Normal file
@ -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__ */
|
239
src/devices/cpu/clipper/clipperd.cpp
Normal file
239
src/devices/cpu/clipper/clipperd.cpp
Normal file
@ -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;
|
||||
}
|
462
src/mame/drivers/interpro.cpp
Normal file
462
src/mame/drivers/interpro.cpp
Normal file
@ -0,0 +1,462 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
#include "includes/interpro.h"
|
||||
#include "debugger.h"
|
||||
|
||||
#define VERBOSE 0
|
||||
#if VERBOSE
|
||||
#define LOG_EMERALD(...) logerror(__VA_ARGS__)
|
||||
#define LOG_MCGA(...) logerror(__VA_ARGS__)
|
||||
#define LOG_IDPROM(...) logerror(__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_EMERALD(...) {}
|
||||
#define LOG_MCGA(...) {}
|
||||
#define LOG_IDPROM(...) logerror(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
// machine start
|
||||
void interpro_state::machine_start()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* MCGA Control Register definitions.
|
||||
*/
|
||||
#define MCGA_CTRL_OPTMASK 0x00000003
|
||||
#define MCGA_CTRL_CBITFRCRD 0x00000004
|
||||
#define MCGA_CTRL_CBITFRCSUB 0x00000008
|
||||
#define MCGA_CTRL_ENREFRESH 0x00000010
|
||||
#define MCGA_CTRL_ENMSBE 0x00000100
|
||||
#define MCGA_CTRL_ENMMBE 0x00000200 // multi-master bus enable?
|
||||
#define MCGA_CTRL_ENECC 0x00000400
|
||||
#define MCGA_CTRL_WRPROT 0x00008000
|
||||
/*
|
||||
* MCGA Error Register definitions.
|
||||
*/
|
||||
#define MCGA_ERROR_SYNDMASK 0x000000ff
|
||||
#define MCGA_ERROR_SYNDSHIFT 0
|
||||
#define MCGA_ERROR_SYND(X) (((X) & MCGA_ERROR_SYNDMASK) >> \
|
||||
MCGA_ERROR_SYNDSHIFT)
|
||||
#define MCGA_ERROR_MMBE 0x00000100
|
||||
#define MCGA_ERROR_MSBE 0x00000200
|
||||
#define MCGA_ERROR_ADDRMASK 0x00001C00
|
||||
#define MCGA_ERROR_ADDRSHIFT 7
|
||||
#define MCGA_ERROR_ADDR(X) (((X) & MCGA_ERROR_ADDRMASK) >> \
|
||||
MCGA_ERROR_ADDRSHIFT)
|
||||
#define MCGA_ERROR_VALID 0x00008000
|
||||
|
||||
/*
|
||||
* MCGA Control Register definitions.
|
||||
*/
|
||||
#define MCGA_MEMSIZE_ADDRMASK 0x0000007F
|
||||
#define MCGA_MEMSIZE_ADDRSHIFT 24
|
||||
#define MCGA_MEMSIZE_ADDR(X) (((X) & MCGA_MEMSIZE_ADDRMASK) << \
|
||||
MCGA_MEMSIZE_ADDRSHIFT)
|
||||
|
||||
#define E_SREG_LED 0
|
||||
#define E_SREG_ERROR 0
|
||||
#define E_SREG_STATUS 1
|
||||
#define E_SREG_CTRL1 2
|
||||
#define E_SREG_CTRL2 3
|
||||
|
||||
/*
|
||||
* Error Register Bit Definitions
|
||||
* WARNING: Some definitions apply only to certain hardware
|
||||
* (ie: E_SERR_SRX* is only valid on 6600 class machines)
|
||||
*/
|
||||
#define E_SERR_BPID4 0x0001
|
||||
#define E_SERR_SRXMMBE 0x0002
|
||||
#define E_SERR_SRXHOG 0x0004
|
||||
#define E_SERR_SRXNEM 0x0008
|
||||
#define E_SERR_SRXVALID 0x0010
|
||||
#define E_SERR_CBUSNMI 0x0020
|
||||
#define E_SERR_CBGMASK 0x00c0
|
||||
#define E_SERR_CBGSHIFT 6
|
||||
#define E_SERR_BG_MASK 0x0070
|
||||
#define E_SERR_BG_SHIFT 4
|
||||
#define E_SERR_BUSHOG 0x0080
|
||||
#define E_SERR_BG(X) (((X) & E_SERR_BG_MASK) >> E_SERR_BG_SHIFT)
|
||||
#define CBUS_ID(X) (((X) & E_SERR_CBGMASK) >> E_SERR_CBGSHIFT)
|
||||
|
||||
/*
|
||||
* Status Register Bit Definitions
|
||||
*/
|
||||
#define E_STAT_YELLOW_ZONE 0x0001
|
||||
#define E_STAT_SRNMI 0x0002
|
||||
#define E_STAT_PWRLOSS 0x0004
|
||||
#define E_STAT_RED_ZONE 0x0008
|
||||
#define E_STAT_BP_MASK 0x00f0
|
||||
#define E_STAT_BP_SHIFT 4
|
||||
#define E_STAT_BP(X) (((X) & E_STAT_BP_MASK) >> E_STAT_BP_SHIFT)
|
||||
|
||||
/*
|
||||
* Control/Status Register 1 Bit Definitions
|
||||
*/
|
||||
#define E_CTRL1_FLOPLOW 0x0001
|
||||
#define E_CTRL1_FLOPRDY 0x0002
|
||||
#define E_CTRL1_LEDENA 0x0004
|
||||
#define E_CTRL1_LEDDP 0x0008
|
||||
#define E_CTRL1_ETHLOOP 0x0010
|
||||
#define E_CTRL1_ETHDTR 0x0020
|
||||
#define E_CTRL1_ETHRMOD 0x0040
|
||||
#define E_CTRL1_CLIPRESET 0x0040
|
||||
#define E_CTRL1_FIFOACTIVE 0x0080
|
||||
|
||||
/*
|
||||
* Control/Status Register 2 Bit Definitions
|
||||
*/
|
||||
#define E_CTRL2_PWRUP 0x0001
|
||||
#define E_CTRL2_PWRENA 0x0002
|
||||
#define E_CTRL2_HOLDOFF 0x0004
|
||||
#define E_CTRL2_EXTNMIENA 0x0008
|
||||
#define E_CTRL2_COLDSTART 0x0010
|
||||
#define E_CTRL2_RESET 0x0020
|
||||
#define E_CTRL2_BUSENA 0x0040
|
||||
#define E_CTRL2_FRCPARITY 0x0080
|
||||
#define E_CTRL2_FLASHEN 0x0080
|
||||
#define E_CTRL2_WMASK 0x000f
|
||||
#define E_SET_CTRL2(X) E_SREG_CTRL2 = (E_SREG_CTRL2 & \
|
||||
E_CTRL2_WMASK) | (X)
|
||||
#define E_CLR_CTRL2(X) E_SREG_CTRL2 &= E_CTRL2_WMASK & ~(X)
|
||||
|
||||
void interpro_state::machine_reset()
|
||||
{
|
||||
// flash rom requires the following values
|
||||
m_emerald_reg[E_SREG_ERROR] = 0x00;
|
||||
m_emerald_reg[E_SREG_STATUS] = 0x00;
|
||||
m_emerald_reg[E_SREG_CTRL1] = E_CTRL1_FLOPRDY;
|
||||
m_emerald_reg[E_SREG_CTRL2] = E_CTRL2_COLDSTART;
|
||||
|
||||
m_mcga[0] = 0x00ff; // 0x00
|
||||
m_mcga[2] = MCGA_CTRL_ENREFRESH | MCGA_CTRL_CBITFRCSUB | MCGA_CTRL_CBITFRCRD; // 0x08 ctrl
|
||||
//m_mcga[4] = 0x8000; // 0x10 error
|
||||
m_mcga[10] = 0x00ff; // 0x28
|
||||
m_mcga[14] = 0x0340; // 0x38 memsize
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(interpro_state::emerald_w)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case E_SREG_LED:
|
||||
LOG_EMERALD("led: value %d at pc 0x%08x\n", data, space.device().safe_pc());
|
||||
m_led->a_w(data);
|
||||
break;
|
||||
|
||||
case E_SREG_STATUS: // not sure if writable?
|
||||
case E_SREG_CTRL1:
|
||||
LOG_EMERALD("emerald write offset %d data 0x%x pc 0x%08x\n", offset, data, space.device().safe_pc());
|
||||
|
||||
if ((data ^ m_emerald_reg[offset]) & E_CTRL1_LEDDP)
|
||||
LOG_EMERALD("emerald led decimal point %s\n", data & E_CTRL1_LEDDP ? "on" : "off");
|
||||
|
||||
m_emerald_reg[offset] = data;
|
||||
break;
|
||||
|
||||
case E_SREG_CTRL2:
|
||||
LOG_EMERALD("emerald write offset %d data 0x%x pc 0x%08x\n", offset, data, space.device().safe_pc());
|
||||
if (data & 0x20)
|
||||
// reset
|
||||
m_maincpu->reset();
|
||||
else
|
||||
m_emerald_reg[offset] = data & 0x0f; // top four bits are not persistent
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER(interpro_state::emerald_r)
|
||||
{
|
||||
LOG_EMERALD("emerald read offset %d pc 0x%08x\n", offset, space.device().safe_pc());
|
||||
switch (offset)
|
||||
{
|
||||
case E_SREG_ERROR:
|
||||
case E_SREG_STATUS:
|
||||
case E_SREG_CTRL1:
|
||||
case E_SREG_CTRL2:
|
||||
default:
|
||||
return m_emerald_reg[offset];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WRITE16_MEMBER(interpro_state::mcga_w)
|
||||
{
|
||||
/*
|
||||
read MEMSIZE 0x38 mask 0xffff
|
||||
read 0x00 mask 0x0000
|
||||
write CBSUB 0x20 mask 0x00ff data 0
|
||||
write FRCRD 0x18 mask 0x00ff data 0
|
||||
read ERROR 0x10 mask 0xffff
|
||||
read 0x00 mask 0xffff
|
||||
|
||||
(0x38 >> 8) & 0xF == 3?
|
||||
|
||||
if (0x00 != 0xFF) -> register reset error
|
||||
|
||||
0x00 = 0x0055 (test value & 0xff)
|
||||
r7 = 0x00 & 0xff
|
||||
*/
|
||||
LOG_MCGA("mcga write offset = 0x%08x, mask = 0x%08x, data = 0x%08x, pc = 0x%08x\n", offset, mem_mask, data, space.device().safe_pc());
|
||||
switch (offset)
|
||||
{
|
||||
case 0x02: // MCGA_CTRL
|
||||
// HACK: set or clear error status depending on ENMMBE bit
|
||||
if (data & MCGA_CTRL_ENMMBE)
|
||||
m_mcga[4] |= MCGA_ERROR_VALID;
|
||||
// else
|
||||
// m_mcga[4] &= ~MCGA_ERROR_VALID;
|
||||
|
||||
default:
|
||||
m_mcga[offset] = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
READ16_MEMBER(interpro_state::mcga_r)
|
||||
{
|
||||
LOG_MCGA("mcga read offset = 0x%08x, mask = 0x%08x, pc = 0x%08x\n", offset, mem_mask, space.device().safe_pc());
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
default:
|
||||
return m_mcga[offset];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ID Prom Structure
|
||||
*/
|
||||
struct IDprom {
|
||||
char i_board[8]; /* string of board type */
|
||||
char i_eco[8]; /* ECO flags */
|
||||
char i_feature[8]; /* feature flags */
|
||||
char i_reserved[2]; /* reserved (all 1's) */
|
||||
short i_family; /* family code */
|
||||
char i_footprint[4]; /* footprint/checksum */
|
||||
};
|
||||
|
||||
|
||||
READ32_MEMBER(interpro_state::idprom_r)
|
||||
{
|
||||
LOG_IDPROM("idprom read offset 0x%x mask 0x%08x at 0x%08x\n", offset, mem_mask, space.device().safe_pc());
|
||||
|
||||
uint32_t speed = 70000000;
|
||||
|
||||
static uint8_t idprom[] = {
|
||||
#if 0
|
||||
// module type id
|
||||
'M', 'P', 'C', 'B',
|
||||
'*', '*', '*', '*',
|
||||
|
||||
// ECO bytes
|
||||
0x87, 0x65, 0x43, 0x21,
|
||||
0xbb, 0xcc, 0xdd, 0xee,
|
||||
|
||||
// the following 8 bytes are "feature bytes"
|
||||
// the feature bytes contain a 32 bit word which is divided by 40000
|
||||
// if they're empty, a default value of 50 000 000 is used
|
||||
// perhaps this is a system speed (50MHz)?
|
||||
0x12, 0x34, 0x56, 0x78,
|
||||
(speed >> 24) & 0xff, (speed >> 16) & 0xff, (speed >> 8) & 0xff, (speed >> 0) & 0xff,
|
||||
|
||||
// reserved bytes
|
||||
0xff, 0xff,
|
||||
|
||||
// family
|
||||
// boot rom tests for family == 0x41 or 0x42
|
||||
// if so, speed read from feature bytes 2 & 3
|
||||
// if not, read speed from feature bytes 4-7
|
||||
0x00, 0x40,
|
||||
#else
|
||||
// Carl Friend's 2020
|
||||
0x00, 0x00, 0x00, 0x00, '9', '6', '2', 'A', // board
|
||||
0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // eco
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // feature
|
||||
0xff, 0xff, // reserved
|
||||
0x24, 0x00, // family
|
||||
#endif
|
||||
// footprint and checksum
|
||||
0x55, 0xaa, 0x55, 0x00
|
||||
};
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
case 0x1f:
|
||||
{
|
||||
uint8_t sum = 0;
|
||||
|
||||
// compute the checksum (sum of all bytes must be == 0x00)
|
||||
for (int i = 0; i < 0x20; i++)
|
||||
sum += idprom[i];
|
||||
|
||||
return 0x100 - (sum & 0xff);
|
||||
}
|
||||
|
||||
default:
|
||||
return idprom[offset];
|
||||
}
|
||||
}
|
||||
|
||||
READ32_MEMBER(interpro_state::slot0_r)
|
||||
{
|
||||
//static struct IDprom slot0 = { "bordtyp", "ecoflgs", "featurs", { '\xff', '\xff' }, 0x7ead, "chk" };
|
||||
|
||||
// Carl Friend's Turqoise graphics board
|
||||
static uint8_t slot0[] = {
|
||||
0x00, 0x00, 0x00, 0x00, '9', '6', '3', 'A', // board
|
||||
0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // eco
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // features
|
||||
0xff, 0xff, // reserved
|
||||
0x22, 0x00, // family
|
||||
0x55, 0xaa, 0x55, 0x00
|
||||
};
|
||||
|
||||
return ((uint8_t *)&slot0)[offset];
|
||||
}
|
||||
|
||||
#if 1
|
||||
// data is 0x500 = offset 1
|
||||
// addr is 0x600 = offset 0
|
||||
// 5 0101 = 1
|
||||
// 6 0110 = 0
|
||||
|
||||
// mask 0x100
|
||||
WRITE8_MEMBER(interpro_state::interpro_rtc_w)
|
||||
{
|
||||
m_rtc->write(space, offset == 0 ? 1 : 0, data);
|
||||
}
|
||||
|
||||
READ8_MEMBER(interpro_state::interpro_rtc_r)
|
||||
{
|
||||
return m_rtc->read(space, offset == 0 ? 1 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
MCGA: 40000xxx - refer iopsysreg.h
|
||||
00: 0005
|
||||
08: CTRL 0010 // control register (hword)
|
||||
10: ERROR 0400 // error register (hword)
|
||||
18: 0000 // frcrd register (byte)
|
||||
20: 0000 // cbsub register (byte)
|
||||
28: 0088
|
||||
30: 001B
|
||||
38: MEMSIZE 0004
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
// driver init
|
||||
DRIVER_INIT_MEMBER(interpro_state, ip2800)
|
||||
{
|
||||
}
|
||||
|
||||
static ADDRESS_MAP_START(ip2800_map, AS_PROGRAM, 32, interpro_state)
|
||||
ADDRESS_MAP_UNMAP_LOW
|
||||
AM_RANGE(0x00000000, 0x00ffffff) AM_RAM // 16M RAM
|
||||
|
||||
AM_RANGE(0x08000000, 0x0800001f) AM_RAM // bogus
|
||||
|
||||
AM_RANGE(0x40000000, 0x4000003f) AM_READWRITE16(mcga_r, mcga_w, 0xffff)
|
||||
AM_RANGE(0x4f007e00, 0x4f007f7f) AM_RAM // treat SRX GA as ram for now
|
||||
|
||||
AM_RANGE(0x7f000100, 0x7f00011f) AM_DEVICE8(INTERPRO_FDC_TAG, n82077aa_device, map, 0xff)
|
||||
|
||||
AM_RANGE(0x7f000400, 0x7f00040f) AM_DEVREADWRITE8(INTERPRO_SCC1_TAG, scc85C30_device, ba_cd_inv_r, ba_cd_inv_w, 0xff)
|
||||
AM_RANGE(0x7f000410, 0x7f00041f) AM_DEVREADWRITE8(INTERPRO_SCC2_TAG, scc85230_device, ba_cd_inv_r, ba_cd_inv_w, 0xff)
|
||||
|
||||
AM_RANGE(0x7f000300, 0x7f00030f) AM_READWRITE8(emerald_r, emerald_w, 0xff)
|
||||
|
||||
AM_RANGE(0x7f000500, 0x7f0006ff) AM_READWRITE8(interpro_rtc_r, interpro_rtc_w, 0xff)
|
||||
//AM_RANGE(0x7F000500, 0x7F000500) AM_DEVREADWRITE8(INTERPRO_RTC_TAG, ds12885_device, read, write, 0xff) AM_MASK(0x100)
|
||||
//AM_RANGE(0x7F000600, 0x7F000600) AM_DEVREADWRITE8(INTERPRO_RTC_TAG, ds12885_device, read, write, 0xff) AM_MASK(0x100)
|
||||
|
||||
// 7f000768 -> 41 or 42
|
||||
// 7f00076c byte reg
|
||||
|
||||
AM_RANGE(0x7F000700, 0x7F00077f) AM_READ(idprom_r)
|
||||
|
||||
AM_RANGE(0x7F0FFF00, 0x7F0FFFFF) AM_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, map)
|
||||
|
||||
AM_RANGE(0x7F100000, 0x7F11FFFF) AM_ROM AM_REGION(INTERPRO_ROM_TAG, 0)
|
||||
AM_RANGE(0x7F180000, 0x7F1BFFFF) AM_ROM AM_REGION(INTERPRO_EEPROM_TAG, 0)
|
||||
|
||||
AM_RANGE(0x8f007f80, 0x8f007fff) AM_READ(slot0_r)
|
||||
|
||||
ADDRESS_MAP_END
|
||||
|
||||
FLOPPY_FORMATS_MEMBER(interpro_state::floppy_formats)
|
||||
FLOPPY_PC_FORMAT
|
||||
FLOPPY_FORMATS_END
|
||||
|
||||
static SLOT_INTERFACE_START(interpro_floppies)
|
||||
SLOT_INTERFACE("525dd", FLOPPY_525_DD)
|
||||
SLOT_INTERFACE("35hd", FLOPPY_35_HD)
|
||||
SLOT_INTERFACE_END
|
||||
|
||||
// input ports
|
||||
static INPUT_PORTS_START(ip2800)
|
||||
INPUT_PORTS_END
|
||||
|
||||
static MACHINE_CONFIG_START(ip2800, interpro_state)
|
||||
MCFG_CPU_ADD(INTERPRO_CPU_TAG, CLIPPER, 70000000)
|
||||
MCFG_CPU_PROGRAM_MAP(ip2800_map)
|
||||
MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, inta_cb)
|
||||
|
||||
MCFG_SCC85C30_ADD(INTERPRO_SCC1_TAG, XTAL_4_9152MHz, 0, 0, 0, 0)
|
||||
|
||||
MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE("rs232a", rs232_port_device, write_txd))
|
||||
MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE("rs232b", rs232_port_device, write_txd))
|
||||
MCFG_Z80SCC_OUT_INT_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir11_w))
|
||||
|
||||
MCFG_RS232_PORT_ADD("rs232a", default_rs232_devices, nullptr)
|
||||
MCFG_RS232_RXD_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, rxa_w))
|
||||
MCFG_RS232_DCD_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, dcda_w))
|
||||
MCFG_RS232_CTS_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, ctsa_w))
|
||||
|
||||
MCFG_RS232_PORT_ADD("rs232b", default_rs232_devices, "terminal")
|
||||
MCFG_RS232_RXD_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, rxb_w))
|
||||
MCFG_RS232_DCD_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, dcdb_w))
|
||||
MCFG_RS232_CTS_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, ctsb_w))
|
||||
|
||||
MCFG_SCC85230_ADD(INTERPRO_SCC2_TAG, XTAL_4_9152MHz, 0, 0, 0, 0)
|
||||
|
||||
MCFG_DS12885_ADD(INTERPRO_RTC_TAG)
|
||||
//MCFG_MC146818_IRQ_HANDLER(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir9_w)) // FIXME: boot rom doesn't like this
|
||||
|
||||
MCFG_DEVICE_ADD(INTERPRO_LED_TAG, DM9368, 0)
|
||||
|
||||
MCFG_N82077AA_ADD(INTERPRO_FDC_TAG, n82077aa_device::MODE_PS2)
|
||||
MCFG_UPD765_INTRQ_CALLBACK(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir1_w))
|
||||
MCFG_UPD765_DRQ_CALLBACK(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, drq))
|
||||
MCFG_FLOPPY_DRIVE_ADD("fdc:0", interpro_floppies, "525dd", interpro_state::floppy_formats)
|
||||
MCFG_FLOPPY_DRIVE_ADD("fdc:1", interpro_floppies, "35hd", interpro_state::floppy_formats)
|
||||
MCFG_FLOPPY_DRIVE_SOUND(false)
|
||||
|
||||
MCFG_DEVICE_ADD("scsiport", SCSI_PORT, 0)
|
||||
|
||||
MCFG_DEVICE_ADD(INTERPRO_SCSI_TAG, NCR539X, 12500000)
|
||||
MCFG_LEGACY_SCSI_PORT("scsiport")
|
||||
MCFG_NCR539X_OUT_IRQ_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir0_w))
|
||||
|
||||
MCFG_INTERPRO_IOGA_ADD(INTERPRO_IOGA_TAG, INPUTLINE(INTERPRO_CPU_TAG, 0))
|
||||
|
||||
// use callbacks to tell the ioga what the dma read and write methods of each device are
|
||||
// MCFG_INTERPRO_IOGA_DMA_CALLBACK(channel, n82077aa_device, dma_r, dma_w)
|
||||
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
ROM_START(ip2800)
|
||||
ROM_REGION(0x0020000, INTERPRO_ROM_TAG, 0)
|
||||
ROM_SYSTEM_BIOS(0, "IP2830", "IP2830")
|
||||
ROMX_LOAD("ip2830_rom.bin", 0x00000, 0x20000, CRC(467ce7bd) SHA1(53faee40d5df311f53b24c930e434cbf94a5c4aa), ROM_BIOS(1))
|
||||
|
||||
ROM_REGION(0x0040000, INTERPRO_EEPROM_TAG, 0)
|
||||
ROM_LOAD_OPTIONAL("ip2830_eeprom.bin", 0x00000, 0x40000, CRC(a0c0899f) SHA1(dda6fbca81f9885a1a76ca3c25e80463a83a0ef7))
|
||||
ROM_END
|
||||
|
||||
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
|
||||
COMP( 1990, ip2800, 0, 0, ip2800, ip2800, interpro_state, ip2800, "Intergraph", "InterPro 2800", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
|
90
src/mame/includes/interpro.h
Normal file
90
src/mame/includes/interpro.h
Normal file
@ -0,0 +1,90 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef INTERPRO_H_
|
||||
#define INTERPRO_H_
|
||||
|
||||
#include "emu.h"
|
||||
#include "cpu/clipper/clipper.h"
|
||||
|
||||
#include "machine/z80scc.h"
|
||||
#include "machine/ds128x.h"
|
||||
#include "bus/rs232/rs232.h"
|
||||
#include "video/dm9368.h"
|
||||
#include "machine/upd765.h"
|
||||
#include "machine/interpro_ioga.h"
|
||||
#include "machine/ncr539x.h"
|
||||
|
||||
#include "formats/pc_dsk.h"
|
||||
|
||||
#define INTERPRO_CPU_TAG "cpu"
|
||||
#define INTERPRO_RTC_TAG "rtc"
|
||||
#define INTERPRO_SCC1_TAG "scc1"
|
||||
#define INTERPRO_SCC2_TAG "scc2"
|
||||
#define INTERPRO_ROM_TAG "rom"
|
||||
#define INTERPRO_EEPROM_TAG "eeprom"
|
||||
#define INTERPRO_TERMINAL_TAG "terminal"
|
||||
#define INTERPRO_LED_TAG "led"
|
||||
#define INTERPRO_FDC_TAG "fdc"
|
||||
#define INTERPRO_SCSI_TAG "scsi"
|
||||
#define INTERPRO_IOGA_TAG "ioga"
|
||||
|
||||
// TODO: RTC is actually a DS12887, but the only difference is the 128 byte NVRAM, same as the DS12885
|
||||
// TODO: not sure what the LED is, but the DM9368 seems close enough
|
||||
|
||||
class interpro_state : public driver_device
|
||||
{
|
||||
public:
|
||||
interpro_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag),
|
||||
m_maincpu(*this, INTERPRO_CPU_TAG),
|
||||
m_scc1(*this, INTERPRO_SCC1_TAG),
|
||||
m_scc2(*this, INTERPRO_SCC2_TAG),
|
||||
m_rtc(*this, INTERPRO_RTC_TAG),
|
||||
m_led(*this, INTERPRO_LED_TAG),
|
||||
m_fdc(*this, INTERPRO_FDC_TAG),
|
||||
m_scsi(*this, INTERPRO_SCSI_TAG),
|
||||
m_ioga(*this, INTERPRO_IOGA_TAG)
|
||||
{ }
|
||||
|
||||
required_device<clipper_device> m_maincpu;
|
||||
|
||||
// FIXME: not sure which one is the escc
|
||||
required_device<z80scc_device> m_scc1;
|
||||
required_device<z80scc_device> m_scc2;
|
||||
|
||||
required_device<ds12885_device> m_rtc;
|
||||
required_device<dm9368_device> m_led;
|
||||
required_device<n82077aa_device> m_fdc;
|
||||
required_device<ncr539x_device> m_scsi;
|
||||
|
||||
required_device<interpro_ioga_device> m_ioga;
|
||||
|
||||
DECLARE_DRIVER_INIT(ip2800);
|
||||
|
||||
DECLARE_WRITE8_MEMBER(emerald_w);
|
||||
DECLARE_READ8_MEMBER(emerald_r);
|
||||
|
||||
DECLARE_WRITE16_MEMBER(mcga_w);
|
||||
DECLARE_READ16_MEMBER(mcga_r);
|
||||
|
||||
DECLARE_WRITE8_MEMBER(interpro_rtc_w);
|
||||
DECLARE_READ8_MEMBER(interpro_rtc_r);
|
||||
|
||||
DECLARE_READ32_MEMBER(idprom_r);
|
||||
DECLARE_READ32_MEMBER(slot0_r);
|
||||
|
||||
DECLARE_FLOPPY_FORMATS(floppy_formats);
|
||||
|
||||
protected:
|
||||
virtual void machine_start() override;
|
||||
virtual void machine_reset() override;
|
||||
|
||||
private:
|
||||
uint8_t m_emerald_reg[4];
|
||||
uint16_t m_mcga[32];
|
||||
};
|
||||
|
||||
#endif
|
300
src/mame/machine/interpro_ioga.cpp
Normal file
300
src/mame/machine/interpro_ioga.cpp
Normal file
@ -0,0 +1,300 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
#include "interpro_ioga.h"
|
||||
|
||||
#define VERBOSE 0
|
||||
#if VERBOSE
|
||||
#define LOG_TIMER(...) logerror(__VA_ARGS__)
|
||||
#define LOG_INTERRUPT(...) logerror(__VA_ARGS__)
|
||||
#define LOG_IOGA(...) logerror(__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_TIMER(...)
|
||||
#define LOG_INTERRUPT(...)
|
||||
#define LOG_IOGA(...)
|
||||
#endif
|
||||
|
||||
// InterPro IOGA
|
||||
const device_type INTERPRO_IOGA = &device_creator<interpro_ioga_device>;
|
||||
|
||||
interpro_ioga_device::interpro_ioga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, INTERPRO_IOGA, "InterPro IOGA", tag, owner, clock, "ioga", __FILE__),
|
||||
m_out_int_func(*this),
|
||||
m_irq_lines(0)
|
||||
{
|
||||
}
|
||||
|
||||
void interpro_ioga_device::device_start()
|
||||
{
|
||||
// resolve callbacks
|
||||
m_out_int_func.resolve();
|
||||
|
||||
m_cpu = machine().device<cpu_device>("cpu");
|
||||
m_fdc = machine().device<upd765_family_device>("fdc");
|
||||
|
||||
// allocate timer for DMA controller
|
||||
m_dma_timer = timer_alloc(IOGA_TIMER_DMA);
|
||||
m_dma_timer->adjust(attotime::never);
|
||||
}
|
||||
|
||||
void interpro_ioga_device::device_reset()
|
||||
{
|
||||
m_irq_lines = 0;
|
||||
m_interrupt = 0;
|
||||
m_state_drq = 0;
|
||||
}
|
||||
|
||||
void interpro_ioga_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
LOG_TIMER("interpro_ioga_device::device_timer(id = %d)\n", id);
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case IOGA_TIMER_0:
|
||||
m_timer[0] = 0x80000000;
|
||||
set_irq_line(14, 1);
|
||||
break;
|
||||
case IOGA_TIMER_1:
|
||||
m_timer[1] = 0x80000000;
|
||||
set_irq_line(15, 1);
|
||||
break;
|
||||
case IOGA_TIMER_3:
|
||||
m_timer[3] = 0x80000000;
|
||||
set_irq_line(1, 1);
|
||||
break;
|
||||
|
||||
case IOGA_TIMER_DMA:
|
||||
// transfer data from fdc to memory
|
||||
// TODO: vice-versa
|
||||
// TODO: get the dma transfer address and count
|
||||
// TODO: implement multiple dma channels
|
||||
{
|
||||
address_space &space = m_cpu->space(AS_PROGRAM);
|
||||
|
||||
space.write_byte(m_fdc_dma[0]++, m_fdc->dma_r());
|
||||
if (--m_fdc_dma[2])
|
||||
m_dma_timer->adjust(attotime::from_usec(10));
|
||||
else
|
||||
m_dma_timer->adjust(attotime::never);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEVICE_ADDRESS_MAP_START(map, 32, interpro_ioga_device)
|
||||
|
||||
AM_RANGE(0x30, 0x3f) AM_READWRITE(fdc_dma_r, fdc_dma_w)
|
||||
|
||||
AM_RANGE(0x5C, 0x81) AM_READWRITE16(icr_r, icr_w, 0xffffffff)
|
||||
|
||||
AM_RANGE(0x8C, 0x8F) AM_READWRITE(timer0_r, timer0_w)
|
||||
AM_RANGE(0x90, 0x93) AM_READWRITE(timer1_r, timer1_w)
|
||||
|
||||
AM_RANGE(0xA8, 0xAB) AM_READWRITE(timer3_r, timer3_w)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
|
||||
/*
|
||||
IOGA
|
||||
00: ethernet remap 003e0480 // ET_82586_BASE_ADDR or IOGA_ETH_REMAP
|
||||
04 : ethernet map page 00fff4b0 // ET_82586_CNTL_REG or IOGA_ETH_MAPPG
|
||||
08 : ethernet control 000004b2 // IOGA_ETH_CTL
|
||||
0C : plotter real address 00000fff
|
||||
10 : plotter virtual address fffffffc
|
||||
14 : plotter transfer count 003fffff
|
||||
18 : plotter control ec000001
|
||||
1C : plotter end - of - scanline counter ffffffff
|
||||
20 : SCSI real address 00000000
|
||||
24 : SCSI virtual address 007e96b8
|
||||
28 : SCSI transfer count
|
||||
2C : SCSI control
|
||||
30 : floppy real address
|
||||
34 : floppy virtual address
|
||||
38 : floppy transfer count
|
||||
3C : floppy control
|
||||
40 : serial address 0 (003ba298)
|
||||
44 : serial control 0 (01000000)
|
||||
48 : serial address 1 (ffffffff)
|
||||
4C : serial control 1 (01200000)
|
||||
50 : serial address 2 (ffffffff)
|
||||
54 : serial control 2 (01200000)
|
||||
|
||||
-- 16 bit
|
||||
5A : SIB control(00ff)
|
||||
5C : internal int 3 (timer 2) 00ff
|
||||
5E : internal int 4 (timer 3) 00ff
|
||||
|
||||
60 : external int 0 (SCSI)0a20
|
||||
62 : external int 1 (floppy)0621
|
||||
64 : external int 2 (plotter)1622
|
||||
66 : external int 3 (SRX / CBUS 0) 0a02
|
||||
68 : external int 4 (SRX / CBUS 1) 0e24
|
||||
6A : external int 5 (SRX / CBUS 2) 0e25
|
||||
6C : external int 6 (VB)0c26
|
||||
6E : external int 7 0cff
|
||||
70 : external int 8 (CBUS 3) 0cff
|
||||
72 : external int 9 (clock / calendar) 0e29
|
||||
74 : external int 10 (clock/SGA) 04fe
|
||||
|
||||
76 : internal int 0 (mouse)0010
|
||||
78 : internal int 1 (timer 0) 0011 - 60Hz
|
||||
7A : internal int 2 (timer 1) 0212
|
||||
7C : internal int 5 (serial DMA) 0e13
|
||||
7E : external int 11 (serial) 0a01
|
||||
80 : external int 12 (Ethernet)162c // IOGA_EXTINT12
|
||||
|
||||
-- 8 bit
|
||||
82 : soft int 00
|
||||
83 : NMI control 1b
|
||||
|
||||
-- 32 bit
|
||||
84 : mouse status 00070000
|
||||
88 : timer prescaler 05aa06da
|
||||
8C : timer 0 00000022
|
||||
90 : timer 1 00010005
|
||||
94 : error address 7f100000
|
||||
98 : error cycle type 00001911 // short?
|
||||
|
||||
-- 16 bit
|
||||
9C: arbiter control 000a // IOGA_ARBCTL
|
||||
#define ETHC_BR_ENA (1<<0)
|
||||
#define SCSI_BR_ENA (1<<1)
|
||||
#define PLT_BR_ENA (1<<2)
|
||||
#define FLP_BR_ENA (1<<3)
|
||||
#define SER0_BR_ENA (1<<4)
|
||||
#define SER1_BR_ENA (1<<5)
|
||||
#define SER2_BR_ENA (1<<6)
|
||||
#define ETHB_BR_ENA (1<<7)
|
||||
#define ETHA_BR_ENA (1<<8)
|
||||
|
||||
9E : I / O base address
|
||||
|
||||
-- 32 bit
|
||||
A0 : timer 2 count ccc748ec
|
||||
A4 : timer 2 value ffffffff
|
||||
A8 : timer 3 bfffffff // timer 3 count
|
||||
AC : bus timeout 445a445c
|
||||
|
||||
-- 16 bit
|
||||
B0 : soft int 8 00ff
|
||||
B2 : soft int 9 00ff
|
||||
B4 : soft int 10 00ff
|
||||
B6 : soft int 11 00ff
|
||||
B8 : soft int 12 00ff
|
||||
BA : soft int 13 00ff
|
||||
BC : soft int 14 00ff
|
||||
BE : soft int 15 00ff
|
||||
|
||||
-- 32 bit
|
||||
C0 : ethernet address A 403bc002 // IOGA_ETHADDR_A
|
||||
C4 : ethernet address B 403a68a0 // IOGA_ETHADDR_B
|
||||
C8 : ethernet address C 4039f088 // IOGA_ETHADDR_C
|
||||
|
||||
(62) = 0x0421 // set floppy interrupts?
|
||||
(3C) &= 0xfeff ffff // turn off and on again
|
||||
(3C) |= 0x0100 0000
|
||||
(9C) |= 0x0008
|
||||
(62) = 0x0621
|
||||
|
||||
during rom boot, all interrupt vectors point at 7f10249e
|
||||
|
||||
int 16 = prioritized interrupt 16, level 0, number 0, mouse interface
|
||||
17 timer 0
|
||||
*/
|
||||
|
||||
void interpro_ioga_device::set_irq_line(int irq, int state)
|
||||
{
|
||||
uint32_t mask = (1 << irq);
|
||||
#define E_INTRC_INTPEND 0x0100
|
||||
#define E_INTRC_EXT_IE 0x0200
|
||||
#define E_INTRC_EDGE 0x0400
|
||||
#define E_INTRC_NEGPOL 0x0800
|
||||
#define E_INTRC_INT_IE 0x1000
|
||||
|
||||
if (m_vectors[irq] & (E_INTRC_EXT_IE | E_INTRC_INT_IE))
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
LOG_INTERRUPT("interpro_ioga_device::set_irq_line(%d, %d)\n", irq, state);
|
||||
|
||||
m_irq_lines |= mask;
|
||||
m_interrupt = irq;
|
||||
m_out_int_func(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_irq_lines &= ~mask;
|
||||
m_out_int_func(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
LOG_INTERRUPT("ignoring irq %d vector 0x%04x\n", irq, m_vectors[irq]);
|
||||
}
|
||||
|
||||
IRQ_CALLBACK_MEMBER(interpro_ioga_device::inta_cb)
|
||||
{
|
||||
return m_vectors[m_interrupt];
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(interpro_ioga_device::drq)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
// TODO: check if dma is enabled
|
||||
m_dma_timer->adjust(attotime::from_usec(10));
|
||||
}
|
||||
|
||||
m_state_drq = state;
|
||||
}
|
||||
|
||||
|
||||
READ32_MEMBER(interpro_ioga_device::read)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
#if 0
|
||||
case 0x3C:
|
||||
// 3C: floppy control
|
||||
break;
|
||||
|
||||
case 0x9C:
|
||||
// 9C: arbiter control 000a
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
LOG_IOGA("ioga read from offset = %08x, mask = %08x, pc = %08x\n", offset, mem_mask, space.device().safe_pc());
|
||||
return 0xffffffff;
|
||||
}
|
||||
}
|
||||
|
||||
void interpro_ioga_device::set_timer(int timer, uint32_t value, device_timer_id id)
|
||||
{
|
||||
m_timer[timer] = value;
|
||||
if (value & 0x40000000)
|
||||
//timer_set(attotime::from_usec(value & 0x3fffff), id);
|
||||
timer_set(attotime::from_usec(500), id);
|
||||
|
||||
}
|
||||
|
||||
WRITE32_MEMBER(interpro_ioga_device::write)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
default:
|
||||
LOG_IOGA("ioga write to offset = 0x%08x, mask = 0x%08x) = 0x%08x, pc = %08x\n", offset, mem_mask, data, space.device().safe_pc());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
READ16_MEMBER(interpro_ioga_device::icr_r)
|
||||
{
|
||||
return m_vectors[offset];
|
||||
}
|
||||
|
||||
WRITE16_MEMBER(interpro_ioga_device::icr_w)
|
||||
{
|
||||
LOG_INTERRUPT("interrupt vector %d set to 0x%04x at pc 0x%08x\n", offset, data, space.device().safe_pc());
|
||||
|
||||
m_vectors[offset] = data;
|
||||
}
|
100
src/mame/machine/interpro_ioga.h
Normal file
100
src/mame/machine/interpro_ioga.h
Normal file
@ -0,0 +1,100 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef INTERPRO_IOGA_H_
|
||||
#define INTERPRO_IOGA_H_
|
||||
|
||||
#include "emu.h"
|
||||
#include "machine/upd765.h"
|
||||
|
||||
#define MCFG_INTERPRO_IOGA_ADD(_tag, _out_int) \
|
||||
MCFG_DEVICE_ADD(_tag, INTERPRO_IOGA, 0) \
|
||||
devcb = &interpro_ioga_device::static_set_out_int_callback( *device, DEVCB_##_out_int );
|
||||
|
||||
class interpro_ioga_device : public device_t
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
interpro_ioga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
template<class _Object> static devcb_base &static_set_out_int_callback(device_t &device, _Object object) { return downcast<interpro_ioga_device &>(device).m_out_int_func.set_callback(object); }
|
||||
|
||||
virtual DECLARE_ADDRESS_MAP(map, 8);
|
||||
|
||||
// external interrupt lines
|
||||
DECLARE_WRITE_LINE_MEMBER(ir0_w) { set_irq_line(2, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(ir1_w) { set_irq_line(3, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(ir2_w) { set_irq_line(4, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(ir3_w) { set_irq_line(5, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(ir4_w) { set_irq_line(6, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(ir5_w) { set_irq_line(7, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(ir6_w) { set_irq_line(8, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(ir7_w) { set_irq_line(9, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(ir8_w) { set_irq_line(10, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(ir9_w) { set_irq_line(11, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(ir10_w) { set_irq_line(12, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(ir11_w) { set_irq_line(17, state); }
|
||||
DECLARE_WRITE_LINE_MEMBER(ir12_w) { set_irq_line(18, state); }
|
||||
|
||||
IRQ_CALLBACK_MEMBER(inta_cb);
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(drq);
|
||||
|
||||
DECLARE_READ32_MEMBER(read);
|
||||
DECLARE_WRITE32_MEMBER(write);
|
||||
|
||||
DECLARE_READ32_MEMBER(timer0_r) { return m_timer[0]; };
|
||||
DECLARE_READ32_MEMBER(timer1_r) { return m_timer[1]; };
|
||||
DECLARE_READ32_MEMBER(timer3_r) { return m_timer[3]; };
|
||||
|
||||
DECLARE_WRITE32_MEMBER(timer0_w) { set_timer(0, data, IOGA_TIMER_0); }
|
||||
DECLARE_WRITE32_MEMBER(timer1_w) { set_timer(1, data, IOGA_TIMER_1); }
|
||||
DECLARE_WRITE32_MEMBER(timer3_w) { set_timer(3, data, IOGA_TIMER_3); }
|
||||
|
||||
DECLARE_READ16_MEMBER(icr_r);
|
||||
DECLARE_WRITE16_MEMBER(icr_w);
|
||||
|
||||
DECLARE_READ32_MEMBER(fdc_dma_r) { return m_fdc_dma[offset]; };
|
||||
DECLARE_WRITE32_MEMBER(fdc_dma_w) { m_fdc_dma[offset] = data; };
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
cpu_device *m_cpu;
|
||||
|
||||
private:
|
||||
static const device_timer_id IOGA_TIMER_0 = 0;
|
||||
static const device_timer_id IOGA_TIMER_1 = 1;
|
||||
static const device_timer_id IOGA_TIMER_2 = 2;
|
||||
static const device_timer_id IOGA_TIMER_3 = 3;
|
||||
|
||||
static const device_timer_id IOGA_TIMER_DMA = 4;
|
||||
|
||||
void set_irq_line(int irq, int state);
|
||||
void set_timer(int timer, uint32_t value, device_timer_id id);
|
||||
|
||||
devcb_write_line m_out_int_func;
|
||||
|
||||
// a hack to get hold of the dma devices
|
||||
upd765_family_device *m_fdc;
|
||||
|
||||
uint32_t m_irq_lines;
|
||||
uint8_t m_interrupt;
|
||||
uint16_t m_vectors[19];
|
||||
|
||||
uint32_t m_timer[4];
|
||||
|
||||
emu_timer *m_dma_timer;
|
||||
uint32_t m_state_drq;
|
||||
uint32_t m_fdc_dma[4];
|
||||
};
|
||||
|
||||
// device type definition
|
||||
extern const device_type INTERPRO_IOGA;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user