summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/cpu/ssp1601/ssp1601.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/cpu/ssp1601/ssp1601.c')
-rw-r--r--trunk/src/emu/cpu/ssp1601/ssp1601.c916
1 files changed, 916 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/ssp1601/ssp1601.c b/trunk/src/emu/cpu/ssp1601/ssp1601.c
new file mode 100644
index 00000000000..57ccefa36b7
--- /dev/null
+++ b/trunk/src/emu/cpu/ssp1601/ssp1601.c
@@ -0,0 +1,916 @@
+/*
+ * Samsung SSP1601 DSP emulator
+ *
+ * Copyright 2008, Grazvydas Ignotas
+ *
+ * This code is released under the MAME license.
+ *
+ *
+ * notes:
+ * not everything is implemented, but it is accurate enough to
+ * properly emulate Virtua Racing for Genesis/MegaDrive:
+ *
+ * only Z and N status flags are emulated (others unused by VR)
+ * so all condition checks except N and Z are ignored (not used by VR)
+ * modifiers for 'OP a, ri' and ((ri)) are ignored (not used by VR)
+ * loop repeat mode when destination is (ri) is ignored
+ * ops not used by VR are not implemented
+ */
+
+#include "emu.h"
+#include "debugger.h"
+#include "ssp1601.h"
+
+CPU_DISASSEMBLE( ssp1601 );
+
+/* detect ops with unimplemented/invalid fields.
+ * Useful for homebrew or if a new VR revision pops up. */
+//#define DO_CHECKS
+
+
+
+typedef struct _ssp1601_state_t ssp1601_state_t;
+struct _ssp1601_state_t
+{
+ PAIR gr[8]; /* general regs, some are 16bit, some 32bit */
+ union {
+ unsigned char r[8]; /* pointer registers, 4 for earch bank */
+ struct {
+ unsigned char r0[4];
+ unsigned char r1[4];
+ };
+ };
+ union {
+ unsigned short RAM[256*2]; /* 2 256-word internal RAM banks */
+ struct {
+ unsigned short RAM0[256];
+ unsigned short RAM1[256];
+ };
+ };
+ UINT16 stack[6]; /* 6-level hardware stack */
+ PAIR ppc;
+
+ int g_cycles;
+
+ legacy_cpu_device *device;
+ address_space *program;
+ direct_read_data *direct;
+ address_space *io;
+};
+
+INLINE ssp1601_state_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == SSP1601);
+ return (ssp1601_state_t *)downcast<legacy_cpu_device *>(device)->token();
+}
+
+
+
+// 0
+#define rX ssp1601_state->gr[SSP_X].w.h
+#define rY ssp1601_state->gr[SSP_Y].w.h
+#define rA ssp1601_state->gr[SSP_A].w.h
+#define rST ssp1601_state->gr[SSP_ST].w.h // 4
+#define rSTACK ssp1601_state->gr[SSP_STACK].w.h
+#define rPC ssp1601_state->gr[SSP_PC].w.h
+#define rP ssp1601_state->gr[SSP_P]
+
+#define rAL ssp1601_state->gr[SSP_A].w.l
+#define rA32 ssp1601_state->gr[SSP_A].d
+#define rIJ ssp1601_state->r
+
+#define IJind (((op>>6)&4)|(op&3))
+
+#define PPC ssp1601_state->ppc.w.h
+
+#define FETCH() ssp1601_state->direct->read_decrypted_word(rPC++ << 1)
+#define PROGRAM_WORD(a) ssp1601_state->program->read_word((a) << 1)
+#define GET_PPC_OFFS() PPC
+
+#define REG_READ(ssp1601_state,r) (((r) <= 4) ? ssp1601_state->gr[r].w.h : reg_read_handlers[r](ssp1601_state, r))
+#define REG_WRITE(ssp1601_state,r,d) { \
+ int r1 = r; \
+ if (r1 >= 4) reg_write_handlers[r1](ssp1601_state, r1,d); \
+ else if (r1 > 0) ssp1601_state->gr[r1].w.h = d; \
+}
+
+// flags
+#define SSP_FLAG_L (1<<0xc)
+#define SSP_FLAG_Z (1<<0xd)
+#define SSP_FLAG_V (1<<0xe)
+#define SSP_FLAG_N (1<<0xf)
+
+// update ZN according to 32bit ACC.
+#define UPD_ACC_ZN \
+ rST &= ~(SSP_FLAG_Z|SSP_FLAG_N); \
+ if (!rA32) rST |= SSP_FLAG_Z; \
+ else rST |= (rA32>>16)&SSP_FLAG_N;
+
+// it seems SVP code never checks for L and OV, so we leave them out.
+#define UPD_LZVN \
+ rST &= ~(SSP_FLAG_L|SSP_FLAG_Z|SSP_FLAG_V|SSP_FLAG_N); \
+ if (!rA32) rST |= SSP_FLAG_Z; \
+ else rST |= (rA32>>16)&SSP_FLAG_N;
+
+// standard cond processing.
+// again, only Z and N is checked, as VR doesn't seem to use any other conds.
+#define COND_CHECK \
+ switch (op&0xf0) { \
+ case 0x00: cond = 1; break; /* always true */ \
+ case 0x50: cond = !((rST ^ (op<<5)) & SSP_FLAG_Z); break; /* Z matches f(?) bit */ \
+ case 0x70: cond = !((rST ^ (op<<7)) & SSP_FLAG_N); break; /* N matches f(?) bit */ \
+ default:logerror(__FILE__ " FIXME: unimplemented cond @ %04x\n", GET_PPC_OFFS()); break; \
+ }
+
+// ops with accumulator.
+// note that 'ld A' doesn't affect flags
+#define OP_LDA(x) \
+ rA = x
+
+#define OP_LDA32(x) \
+ rA32 = x
+
+#define OP_SUBA(x) { \
+ rA32 -= (x) << 16; \
+ UPD_LZVN \
+}
+
+#define OP_SUBA32(x) { \
+ rA32 -= (x); \
+ UPD_LZVN \
+}
+
+#define OP_CMPA(x) { \
+ UINT32 t = rA32 - ((x) << 16); \
+ rST &= ~(SSP_FLAG_L|SSP_FLAG_Z|SSP_FLAG_V|SSP_FLAG_N); \
+ if (!t) rST |= SSP_FLAG_Z; \
+ else rST |= (t>>16)&SSP_FLAG_N; \
+}
+
+#define OP_CMPA32(x) { \
+ UINT32 t = rA32 - (x); \
+ rST &= ~(SSP_FLAG_L|SSP_FLAG_Z|SSP_FLAG_V|SSP_FLAG_N); \
+ if (!t) rST |= SSP_FLAG_Z; \
+ else rST |= (t>>16)&SSP_FLAG_N; \
+}
+
+#define OP_ADDA(x) { \
+ rA32 += (x) << 16; \
+ UPD_LZVN \
+}
+
+#define OP_ADDA32(x) { \
+ rA32 += (x); \
+ UPD_LZVN \
+}
+
+#define OP_ANDA(x) \
+ rA32 &= (x) << 16; \
+ UPD_ACC_ZN
+
+#define OP_ANDA32(x) \
+ rA32 &= (x); \
+ UPD_ACC_ZN
+
+#define OP_ORA(x) \
+ rA32 |= (x) << 16; \
+ UPD_ACC_ZN
+
+#define OP_ORA32(x) \
+ rA32 |= (x); \
+ UPD_ACC_ZN
+
+#define OP_EORA(x) \
+ rA32 ^= (x) << 16; \
+ UPD_ACC_ZN
+
+#define OP_EORA32(x) \
+ rA32 ^= (x); \
+ UPD_ACC_ZN
+
+
+#define OP_CHECK32(OP) { \
+ if ((op & 0x0f) == SSP_P) { /* A <- P */ \
+ update_P(ssp1601_state); \
+ OP(rP.d); \
+ break; \
+ } \
+ if ((op & 0x0f) == SSP_A) { /* A <- A */ \
+ OP(rA32); \
+ break; \
+ } \
+}
+
+
+#ifdef DO_CHECKS
+#define CHECK_IMM16() if (op&0x1ff) logerror(__FILE__ " imm bits! %04x @ %04x\n", op, GET_PPC_OFFS())
+#define CHECK_B_SET() if (op&0x100) logerror(__FILE__ " b set! %04x @ %04x\n", op, GET_PPC_OFFS())
+#define CHECK_B_CLEAR() if (!(op&0x100)) logerror(__FILE__ " b clear! %04x @ %04x\n", op, GET_PPC_OFFS())
+#define CHECK_MOD() if (op&0x00c) logerror(__FILE__ " mod bits! %04x @ %04x\n", op, GET_PPC_OFFS())
+#define CHECK_10f() if (op&0x10f) logerror(__FILE__ " bits 10f! %04x @ %04x\n", op, GET_PPC_OFFS())
+#define CHECK_008() if (op&0x008) logerror(__FILE__ " bits 008! %04x @ %04x\n", op, GET_PPC_OFFS())
+#define CHECK_00f() if (op&0x00f) logerror(__FILE__ " bits 00f! %04x @ %04x\n", op, GET_PPC_OFFS())
+#define CHECK_0f0() if (op&0x0f0) logerror(__FILE__ " bits 0f0! %04x @ %04x\n", op, GET_PPC_OFFS())
+#define CHECK_1f0() if (op&0x1f0) logerror(__FILE__ " bits 1f0! %04x @ %04x\n", op, GET_PPC_OFFS())
+#define CHECK_RPL() if (rST&7) logerror(__FILE__ " unhandled RPL! %04x @ %04x\n", op, GET_PPC_OFFS())
+#define CHECK_ST(d) if((rST^d)&0xf98)logerror(__FILE__ " ssp FIXME ST %04x -> %04x @ %04x\n", rST, d, GET_PPC_OFFS())
+#else
+#define CHECK_IMM16()
+#define CHECK_B_SET()
+#define CHECK_B_CLEAR()
+#define CHECK_MOD()
+#define CHECK_10f()
+#define CHECK_008()
+#define CHECK_00f()
+#define CHECK_0f0()
+#define CHECK_1f0()
+#define CHECK_RPL()
+#define CHECK_ST(d)
+#endif
+
+#define CHIP_NAME "SSP1601"
+
+// -----------------------------------------------------
+// register i/o handlers
+
+static void update_P(ssp1601_state_t *ssp1601_state)
+{
+ int m1 = (signed short)rX;
+ int m2 = (signed short)rY;
+ rP.d = (m1 * m2 * 2);
+}
+
+static UINT32 read_unknown(ssp1601_state_t *ssp1601_state, int reg)
+{
+ logerror("%s:%i FIXME\n", __FILE__, __LINE__);
+ return 0;
+}
+
+static void write_unknown(ssp1601_state_t *ssp1601_state, int reg, UINT32 d)
+{
+ logerror("%s:%i FIXME\n", __FILE__, __LINE__);
+}
+
+/* map EXT regs to virtual I/O range of 0x00-0x0f */
+static UINT32 read_ext(ssp1601_state_t *ssp1601_state, int reg)
+{
+ reg &= 7;
+ return ssp1601_state->io->read_word((reg << 1));
+}
+
+static void write_ext(ssp1601_state_t *ssp1601_state, int reg, UINT32 d)
+{
+ reg &= 7;
+ ssp1601_state->io->write_word((reg << 1), d);
+}
+
+// 4
+static void write_ST(ssp1601_state_t *ssp1601_state, int reg, UINT32 d)
+{
+ CHECK_ST(d);
+ rST = d;
+}
+
+// 5
+static UINT32 read_STACK(ssp1601_state_t *ssp1601_state, int reg)
+{
+ --rSTACK;
+ if ((signed short)rSTACK < 0) {
+ rSTACK = 5;
+ logerror(__FILE__ " FIXME: stack underflow! (%i) @ %04x\n", rSTACK, GET_PPC_OFFS());
+ }
+ return ssp1601_state->stack[rSTACK];
+}
+
+static void write_STACK(ssp1601_state_t *ssp1601_state, int reg, UINT32 d)
+{
+ if (rSTACK >= 6) {
+ logerror(__FILE__ " FIXME: stack overflow! (%i) @ %04x\n", rSTACK, GET_PPC_OFFS());
+ rSTACK = 0;
+ }
+ ssp1601_state->stack[rSTACK++] = d;
+}
+
+// 6
+static UINT32 read_PC(ssp1601_state_t *ssp1601_state, int reg)
+{
+ return rPC;
+}
+
+static void write_PC(ssp1601_state_t *ssp1601_state, int reg, UINT32 d)
+{
+ rPC = d;
+ ssp1601_state->g_cycles--;
+}
+
+// 7
+static UINT32 read_P(ssp1601_state_t *ssp1601_state, int reg)
+{
+ update_P(ssp1601_state);
+ return rP.w.h;
+}
+
+// 15
+static UINT32 read_AL(ssp1601_state_t *ssp1601_state, int reg)
+{
+ /* apparently reading AL causes some effect on EXT bus, VR depends on that.. */
+ read_ext(ssp1601_state, reg);
+ return rAL;
+}
+
+static void write_AL(ssp1601_state_t *ssp1601_state, int reg, UINT32 d)
+{
+ write_ext(ssp1601_state, reg, d);
+ rAL = d;
+}
+
+
+typedef UINT32 (*read_func_t)(ssp1601_state_t *ssp1601_state, int reg);
+typedef void (*write_func_t)(ssp1601_state_t *ssp1601_state, int reg, UINT32 d);
+
+static const read_func_t reg_read_handlers[16] =
+{
+ read_unknown, read_unknown, read_unknown, read_unknown, // -, X, Y, A
+ read_unknown, // 4 ST
+ read_STACK,
+ read_PC,
+ read_P,
+ read_ext, // 8
+ read_ext,
+ read_ext,
+ read_ext,
+ read_ext, // 12
+ read_ext,
+ read_ext,
+ read_AL
+};
+
+static const write_func_t reg_write_handlers[16] =
+{
+ write_unknown, write_unknown, write_unknown, write_unknown, // -, X, Y, A
+ write_ST,
+ write_STACK,
+ write_PC,
+ write_unknown, // 7 P (not writable)
+ write_ext, // 8
+ write_ext,
+ write_ext,
+ write_ext,
+ write_ext, // 12
+ write_ext,
+ write_ext,
+ write_AL
+};
+
+// -----------------------------------------------------
+// pointer register handlers
+
+//
+#define ptr1_read(ssp1601_state, op) ptr1_read_(ssp1601_state, op&3,(op>>6)&4,(op<<1)&0x18)
+
+static UINT32 ptr1_read_(ssp1601_state_t *ssp1601_state, int ri, int isj2, int modi3)
+{
+ //int t = (op&3) | ((op>>6)&4) | ((op<<1)&0x18);
+ UINT32 mask, add = 0, t = ri | isj2 | modi3;
+ unsigned char *rp = NULL;
+ switch (t)
+ {
+ // mod=0 (00)
+ case 0x00:
+ case 0x01:
+ case 0x02: return ssp1601_state->RAM0[ssp1601_state->r0[t&3]];
+ case 0x03: return ssp1601_state->RAM0[0];
+ case 0x04:
+ case 0x05:
+ case 0x06: return ssp1601_state->RAM1[ssp1601_state->r1[t&3]];
+ case 0x07: return ssp1601_state->RAM1[0];
+ // mod=1 (01), "+!"
+ case 0x08:
+ case 0x09:
+ case 0x0a: return ssp1601_state->RAM0[ssp1601_state->r0[t&3]++];
+ case 0x0b: return ssp1601_state->RAM0[1];
+ case 0x0c:
+ case 0x0d:
+ case 0x0e: return ssp1601_state->RAM1[ssp1601_state->r1[t&3]++];
+ case 0x0f: return ssp1601_state->RAM1[1];
+ // mod=2 (10), "-"
+ case 0x10:
+ case 0x11:
+ case 0x12: rp = &ssp1601_state->r0[t&3]; t = ssp1601_state->RAM0[*rp];
+ if (!(rST&7)) { (*rp)--; return t; }
+ add = -1; goto modulo;
+ case 0x13: return ssp1601_state->RAM0[2];
+ case 0x14:
+ case 0x15:
+ case 0x16: rp = &ssp1601_state->r1[t&3]; t = ssp1601_state->RAM1[*rp];
+ if (!(rST&7)) { (*rp)--; return t; }
+ add = -1; goto modulo;
+ case 0x17: return ssp1601_state->RAM1[2];
+ // mod=3 (11), "+"
+ case 0x18:
+ case 0x19:
+ case 0x1a: rp = &ssp1601_state->r0[t&3]; t = ssp1601_state->RAM0[*rp];
+ if (!(rST&7)) { (*rp)++; return t; }
+ add = 1; goto modulo;
+ case 0x1b: return ssp1601_state->RAM0[3];
+ case 0x1c:
+ case 0x1d:
+ case 0x1e: rp = &ssp1601_state->r1[t&3]; t = ssp1601_state->RAM1[*rp];
+ if (!(rST&7)) { (*rp)++; return t; }
+ add = 1; goto modulo;
+ case 0x1f: return ssp1601_state->RAM1[3];
+ }
+
+ return 0;
+
+modulo:
+ mask = (1 << (rST&7)) - 1;
+ *rp = (*rp & ~mask) | ((*rp + add) & mask);
+ return t;
+}
+
+static void ptr1_write(ssp1601_state_t *ssp1601_state, int op, UINT32 d)
+{
+ int t = (op&3) | ((op>>6)&4) | ((op<<1)&0x18);
+ switch (t)
+ {
+ // mod=0 (00)
+ case 0x00:
+ case 0x01:
+ case 0x02: ssp1601_state->RAM0[ssp1601_state->r0[t&3]] = d; return;
+ case 0x03: ssp1601_state->RAM0[0] = d; return;
+ case 0x04:
+ case 0x05:
+ case 0x06: ssp1601_state->RAM1[ssp1601_state->r1[t&3]] = d; return;
+ case 0x07: ssp1601_state->RAM1[0] = d; return;
+ // mod=1 (01), "+!"
+ // mod=3, "+"
+ case 0x08:
+ case 0x09:
+ case 0x0a: ssp1601_state->RAM0[ssp1601_state->r0[t&3]++] = d; return;
+ case 0x0b: ssp1601_state->RAM0[1] = d; return;
+ case 0x0c:
+ case 0x0d:
+ case 0x0e: ssp1601_state->RAM1[ssp1601_state->r1[t&3]++] = d; return;
+ case 0x0f: ssp1601_state->RAM1[1] = d; return;
+ // mod=2 (10), "-"
+ case 0x10:
+ case 0x11:
+ case 0x12: ssp1601_state->RAM0[ssp1601_state->r0[t&3]--] = d; CHECK_RPL(); return;
+ case 0x13: ssp1601_state->RAM0[2] = d; return;
+ case 0x14:
+ case 0x15:
+ case 0x16: ssp1601_state->RAM1[ssp1601_state->r1[t&3]--] = d; CHECK_RPL(); return;
+ case 0x17: ssp1601_state->RAM1[2] = d; return;
+ // mod=3 (11), "+"
+ case 0x18:
+ case 0x19:
+ case 0x1a: ssp1601_state->RAM0[ssp1601_state->r0[t&3]++] = d; CHECK_RPL(); return;
+ case 0x1b: ssp1601_state->RAM0[3] = d; return;
+ case 0x1c:
+ case 0x1d:
+ case 0x1e: ssp1601_state->RAM1[ssp1601_state->r1[t&3]++] = d; CHECK_RPL(); return;
+ case 0x1f: ssp1601_state->RAM1[3] = d; return;
+ }
+}
+
+static UINT32 ptr2_read(ssp1601_state_t *ssp1601_state, int op)
+{
+ int mv = 0, t = (op&3) | ((op>>6)&4) | ((op<<1)&0x18);
+ switch (t)
+ {
+ // mod=0 (00)
+ case 0x00:
+ case 0x01:
+ case 0x02: mv = ssp1601_state->RAM0[ssp1601_state->r0[t&3]]++; break;
+ case 0x03: mv = ssp1601_state->RAM0[0]++; break;
+ case 0x04:
+ case 0x05:
+ case 0x06: mv = ssp1601_state->RAM1[ssp1601_state->r1[t&3]]++; break;
+ case 0x07: mv = ssp1601_state->RAM1[0]++; break;
+ // mod=1 (01)
+ case 0x0b: mv = ssp1601_state->RAM0[1]++; break;
+ case 0x0f: mv = ssp1601_state->RAM1[1]++; break;
+ // mod=2 (10)
+ case 0x13: mv = ssp1601_state->RAM0[2]++; break;
+ case 0x17: mv = ssp1601_state->RAM1[2]++; break;
+ // mod=3 (11)
+ case 0x1b: mv = ssp1601_state->RAM0[3]++; break;
+ case 0x1f: mv = ssp1601_state->RAM1[3]++; break;
+ default: logerror(__FILE__ " FIXME: unimplemented mod in ((rX)) @ %04x\n", GET_PPC_OFFS());
+ return 0;
+ }
+
+ return PROGRAM_WORD(mv);
+}
+
+
+// -----------------------------------------------------
+
+
+static CPU_INIT( ssp1601 )
+{
+ ssp1601_state_t *ssp1601_state = get_safe_token(device);
+
+ device->save_item(NAME(rX));
+ device->save_item(NAME(rY));
+ device->save_item(NAME(rA32));
+ device->save_item(NAME(rST));
+ device->save_item(NAME(rSTACK));
+ device->save_item(NAME(rPC));
+ device->save_item(NAME(rP.d));
+ device->save_item(NAME(PPC));
+ device->save_item(NAME(ssp1601_state->stack));
+ device->save_item(NAME(ssp1601_state->r));
+ device->save_item(NAME(ssp1601_state->RAM));
+
+ /* clear the state */
+ memset(ssp1601_state, 0, sizeof(ssp1601_state_t));
+ ssp1601_state->gr[0].w.h = 0xffff; // constant reg
+ ssp1601_state->device = device;
+ ssp1601_state->program = device->space(AS_PROGRAM);
+ ssp1601_state->direct = &ssp1601_state->program->direct();
+ ssp1601_state->io = device->space(AS_IO);
+
+}
+
+static CPU_EXIT( ssp1601 )
+{
+ /* nothing to do */
+}
+
+static CPU_RESET( ssp1601 )
+{
+ ssp1601_state_t *ssp1601_state = get_safe_token(device);
+
+ rPC = 0x400;
+ rSTACK = 0; // ? using ascending stack
+ rST = 0;
+}
+
+
+static CPU_EXECUTE( ssp1601 )
+{
+ ssp1601_state_t *ssp1601_state = get_safe_token(device);
+
+ while (ssp1601_state->g_cycles > 0)
+ {
+ int op;
+ UINT32 tmpv;
+
+ PPC = rPC;
+
+ debugger_instruction_hook(device, rPC);
+
+ op = FETCH();
+
+ switch (op >> 9)
+ {
+ // ld d, s
+ case 0x00:
+ CHECK_B_SET();
+ if (op == 0) break; // nop
+ if (op == ((SSP_A<<4)|SSP_P)) { // A <- P
+ update_P(ssp1601_state);
+ rA32 = rP.d;
+ }
+ else
+ {
+ tmpv = REG_READ(ssp1601_state,op & 0x0f);
+ REG_WRITE(ssp1601_state,(op & 0xf0) >> 4, tmpv);
+ }
+ break;
+
+ // ld d, (ri)
+ case 0x01: tmpv = ptr1_read(ssp1601_state, op); REG_WRITE(ssp1601_state, (op & 0xf0) >> 4, tmpv); break;
+
+ // ld (ri), s
+ case 0x02: tmpv = REG_READ(ssp1601_state,(op & 0xf0) >> 4); ptr1_write(ssp1601_state, op, tmpv); break;
+
+ // ldi d, imm
+ case 0x04: CHECK_10f(); tmpv = FETCH(); REG_WRITE(ssp1601_state, (op & 0xf0) >> 4, tmpv);ssp1601_state->g_cycles--; break;
+
+ // ld d, ((ri))
+ case 0x05: CHECK_MOD(); tmpv = ptr2_read(ssp1601_state, op); REG_WRITE(ssp1601_state, (op & 0xf0) >> 4, tmpv); ssp1601_state->g_cycles -= 2; break;
+
+ // ldi (ri), imm
+ case 0x06: tmpv = FETCH(); ptr1_write(ssp1601_state, op, tmpv); ssp1601_state->g_cycles--; break;
+
+ // ld adr, a
+ case 0x07: ssp1601_state->RAM[op & 0x1ff] = rA; break;
+
+ // ld d, ri
+ case 0x09: CHECK_MOD(); tmpv = rIJ[(op&3)|((op>>6)&4)]; REG_WRITE(ssp1601_state,(op & 0xf0) >> 4, tmpv); break;
+
+ // ld ri, s
+ case 0x0a: CHECK_MOD(); rIJ[(op&3)|((op>>6)&4)] = REG_READ(ssp1601_state,(op & 0xf0) >> 4); break;
+
+ // ldi ri, simm
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f: rIJ[(op>>8)&7] = op; break;
+
+ // call cond, addr
+ case 0x24: {
+ int cond = 0;
+ CHECK_00f();
+ COND_CHECK
+ if (cond) { int new_PC = FETCH(); write_STACK(ssp1601_state, SSP_STACK, rPC); rPC = new_PC; }
+ else rPC++;
+ ssp1601_state->g_cycles--; // always 2 cycles
+ break;
+ }
+
+ // ld d, (a)
+ case 0x25:
+ CHECK_10f();
+ tmpv = PROGRAM_WORD(rA);
+ REG_WRITE(ssp1601_state,(op & 0xf0) >> 4, tmpv);
+ ssp1601_state->g_cycles -= 2; // 3 cycles total
+ break;
+
+ // bra cond, addr
+ case 0x26: {
+ int cond = 0;
+ CHECK_00f();
+ COND_CHECK
+ if (cond) { rPC = FETCH(); }
+ else rPC++;
+ ssp1601_state->g_cycles--;
+ break;
+ }
+
+ // mod cond, op
+ case 0x48: {
+ int cond = 0;
+ CHECK_008();
+ COND_CHECK
+ if (cond) {
+ switch (op & 7) {
+ case 2: rA32 = (signed int)rA32 >> 1; break; // shr (arithmetic)
+ case 3: rA32 <<= 1; break; // shl
+ case 6: rA32 = -(signed int)rA32; break; // neg
+ case 7: if ((int)rA32 < 0) rA32 = -(signed int)rA32; break; // abs
+ default: logerror(__FILE__ " FIXME: unhandled mod %i @ %04x\n",
+ op&7, GET_PPC_OFFS());
+ }
+ UPD_ACC_ZN
+ }
+ break;
+ }
+
+ // mpys?
+ case 0x1b:
+ CHECK_B_CLEAR();
+ update_P(ssp1601_state);
+ rA32 -= rP.d;
+ UPD_ACC_ZN
+ rX = ptr1_read_(ssp1601_state, op&3, 0, (op<<1)&0x18);
+ rY = ptr1_read_(ssp1601_state, (op>>4)&3, 4, (op>>3)&0x18);
+ break;
+
+ // mpya (rj), (ri), b
+ case 0x4b:
+ CHECK_B_CLEAR();
+ update_P(ssp1601_state);
+ rA32 += rP.d;
+ UPD_ACC_ZN
+ rX = ptr1_read_(ssp1601_state, op&3, 0, (op<<1)&0x18);
+ rY = ptr1_read_(ssp1601_state, (op>>4)&3, 4, (op>>3)&0x18);
+ break;
+
+ // mld (rj), (ri), b
+ case 0x5b:
+ CHECK_B_CLEAR();
+ rA32 = 0;
+ rST &= 0x0fff;
+ rST |= SSP_FLAG_Z;
+ rX = ptr1_read_(ssp1601_state, op&3, 0, (op<<1)&0x18);
+ rY = ptr1_read_(ssp1601_state, (op>>4)&3, 4, (op>>3)&0x18);
+ break;
+
+ // OP a, s
+ case 0x10: CHECK_1f0(); OP_CHECK32(OP_SUBA32); tmpv = REG_READ(ssp1601_state,op & 0x0f); OP_SUBA(tmpv); break;
+ case 0x30: CHECK_1f0(); OP_CHECK32(OP_CMPA32); tmpv = REG_READ(ssp1601_state,op & 0x0f); OP_CMPA(tmpv); break;
+ case 0x40: CHECK_1f0(); OP_CHECK32(OP_ADDA32); tmpv = REG_READ(ssp1601_state,op & 0x0f); OP_ADDA(tmpv); break;
+ case 0x50: CHECK_1f0(); OP_CHECK32(OP_ANDA32); tmpv = REG_READ(ssp1601_state,op & 0x0f); OP_ANDA(tmpv); break;
+ case 0x60: CHECK_1f0(); OP_CHECK32(OP_ORA32 ); tmpv = REG_READ(ssp1601_state,op & 0x0f); OP_ORA (tmpv); break;
+ case 0x70: CHECK_1f0(); OP_CHECK32(OP_EORA32); tmpv = REG_READ(ssp1601_state,op & 0x0f); OP_EORA(tmpv); break;
+
+ // OP a, (ri)
+ case 0x11: CHECK_0f0(); tmpv = ptr1_read(ssp1601_state, op); OP_SUBA(tmpv); break;
+ case 0x31: CHECK_0f0(); tmpv = ptr1_read(ssp1601_state, op); OP_CMPA(tmpv); break;
+ case 0x41: CHECK_0f0(); tmpv = ptr1_read(ssp1601_state, op); OP_ADDA(tmpv); break;
+ case 0x51: CHECK_0f0(); tmpv = ptr1_read(ssp1601_state, op); OP_ANDA(tmpv); break;
+ case 0x61: CHECK_0f0(); tmpv = ptr1_read(ssp1601_state, op); OP_ORA (tmpv); break;
+ case 0x71: CHECK_0f0(); tmpv = ptr1_read(ssp1601_state, op); OP_EORA(tmpv); break;
+
+ // OP a, adr
+ case 0x03: tmpv = ssp1601_state->RAM[op & 0x1ff]; OP_LDA (tmpv); break;
+ case 0x13: tmpv = ssp1601_state->RAM[op & 0x1ff]; OP_SUBA(tmpv); break;
+ case 0x33: tmpv = ssp1601_state->RAM[op & 0x1ff]; OP_CMPA(tmpv); break;
+ case 0x43: tmpv = ssp1601_state->RAM[op & 0x1ff]; OP_ADDA(tmpv); break;
+ case 0x53: tmpv = ssp1601_state->RAM[op & 0x1ff]; OP_ANDA(tmpv); break;
+ case 0x63: tmpv = ssp1601_state->RAM[op & 0x1ff]; OP_ORA (tmpv); break;
+ case 0x73: tmpv = ssp1601_state->RAM[op & 0x1ff]; OP_EORA(tmpv); break;
+
+ // OP a, imm
+ case 0x14: CHECK_IMM16(); tmpv = FETCH(); OP_SUBA(tmpv); ssp1601_state->g_cycles--; break;
+ case 0x34: CHECK_IMM16(); tmpv = FETCH(); OP_CMPA(tmpv); ssp1601_state->g_cycles--; break;
+ case 0x44: CHECK_IMM16(); tmpv = FETCH(); OP_ADDA(tmpv); ssp1601_state->g_cycles--; break;
+ case 0x54: CHECK_IMM16(); tmpv = FETCH(); OP_ANDA(tmpv); ssp1601_state->g_cycles--; break;
+ case 0x64: CHECK_IMM16(); tmpv = FETCH(); OP_ORA (tmpv); ssp1601_state->g_cycles--; break;
+ case 0x74: CHECK_IMM16(); tmpv = FETCH(); OP_EORA(tmpv); ssp1601_state->g_cycles--; break;
+
+ // OP a, ((ri))
+ case 0x15: CHECK_MOD(); tmpv = ptr2_read(ssp1601_state, op); OP_SUBA(tmpv); ssp1601_state->g_cycles -= 2; break;
+ case 0x35: CHECK_MOD(); tmpv = ptr2_read(ssp1601_state, op); OP_CMPA(tmpv); ssp1601_state->g_cycles -= 2; break;
+ case 0x45: CHECK_MOD(); tmpv = ptr2_read(ssp1601_state, op); OP_ADDA(tmpv); ssp1601_state->g_cycles -= 2; break;
+ case 0x55: CHECK_MOD(); tmpv = ptr2_read(ssp1601_state, op); OP_ANDA(tmpv); ssp1601_state->g_cycles -= 2; break;
+ case 0x65: CHECK_MOD(); tmpv = ptr2_read(ssp1601_state, op); OP_ORA (tmpv); ssp1601_state->g_cycles -= 2; break;
+ case 0x75: CHECK_MOD(); tmpv = ptr2_read(ssp1601_state, op); OP_EORA(tmpv); ssp1601_state->g_cycles -= 2; break;
+
+ // OP a, ri
+ case 0x19: CHECK_MOD(); tmpv = rIJ[IJind]; OP_SUBA(tmpv); break;
+ case 0x39: CHECK_MOD(); tmpv = rIJ[IJind]; OP_CMPA(tmpv); break;
+ case 0x49: CHECK_MOD(); tmpv = rIJ[IJind]; OP_ADDA(tmpv); break;
+ case 0x59: CHECK_MOD(); tmpv = rIJ[IJind]; OP_ANDA(tmpv); break;
+ case 0x69: CHECK_MOD(); tmpv = rIJ[IJind]; OP_ORA (tmpv); break;
+ case 0x79: CHECK_MOD(); tmpv = rIJ[IJind]; OP_EORA(tmpv); break;
+
+ // OP simm
+ case 0x1c: CHECK_B_SET(); OP_SUBA(op & 0xff); break;
+ case 0x3c: CHECK_B_SET(); OP_CMPA(op & 0xff); break;
+ case 0x4c: CHECK_B_SET(); OP_ADDA(op & 0xff); break;
+ case 0x5c: CHECK_B_SET(); OP_ANDA(op & 0xff); break;
+ case 0x6c: CHECK_B_SET(); OP_ORA (op & 0xff); break;
+ case 0x7c: CHECK_B_SET(); OP_EORA(op & 0xff); break;
+
+ default:
+ logerror(__FILE__ " FIXME unhandled op %04x @ %04x\n", op, GET_PPC_OFFS());
+ break;
+ }
+ ssp1601_state->g_cycles--;
+ }
+
+ update_P(ssp1601_state);
+}
+
+
+/**************************************************************************
+ * MAME interface
+ **************************************************************************/
+
+static CPU_SET_INFO( ssp1601 )
+{
+ ssp1601_state_t *ssp1601_state = get_safe_token(device);
+
+ switch (state)
+ {
+ /* --- the following bits of info are set as 64-bit signed integers --- */
+
+ case CPUINFO_INT_REGISTER + SSP_X: rX = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_Y: rY = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_A: rA32 = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_ST: rST = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK: rSTACK = info->i; break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SSP_PC: rPC = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_P: rP.d = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK0: ssp1601_state->stack[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK1: ssp1601_state->stack[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK2: ssp1601_state->stack[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK3: ssp1601_state->stack[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK4: ssp1601_state->stack[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK5: ssp1601_state->stack[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_PR0: ssp1601_state->r[0] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_PR1: ssp1601_state->r[1] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_PR2: ssp1601_state->r[2] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_PR3: ssp1601_state->r[3] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_PR4: ssp1601_state->r[4] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_PR5: ssp1601_state->r[5] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_PR6: ssp1601_state->r[6] = info->i; break;
+ case CPUINFO_INT_REGISTER + SSP_PR7: ssp1601_state->r[7] = info->i; break;
+
+// case CPUINFO_INT_INPUT_STATE + 0: set_irq_line(0, info->i); break;
+// case CPUINFO_INT_INPUT_STATE + 1: set_irq_line(1, info->i); break;
+// case CPUINFO_INT_INPUT_STATE + 2: set_irq_line(2, info->i); break;
+ }
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+CPU_GET_INFO( ssp1601 )
+{
+ ssp1601_state_t *ssp1601_state = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL;
+
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ssp1601_state_t); break;
+ case CPUINFO_INT_INPUT_LINES: info->i = 3; break;
+ case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
+ case DEVINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break;
+ case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break;
+ case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
+ case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 2; break;
+ case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
+ case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
+ case CPUINFO_INT_MAX_CYCLES: info->i = 4; break;
+
+ case DEVINFO_INT_DATABUS_WIDTH + AS_PROGRAM: info->i = 16; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 16; break;
+ case DEVINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = -1; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_DATA: info->i = 0; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_DATA: info->i = 0; break;
+ case DEVINFO_INT_ADDRBUS_SHIFT + AS_DATA: info->i = 0; break;
+ case DEVINFO_INT_DATABUS_WIDTH + AS_IO: info->i = 16; break;
+ case DEVINFO_INT_ADDRBUS_WIDTH + AS_IO: info->i = 4; break;
+ case DEVINFO_INT_ADDRBUS_SHIFT + AS_IO: info->i = 0; break;
+
+ case CPUINFO_INT_INPUT_STATE + 0: /* not implemented */ break;
+
+ case CPUINFO_INT_PREVIOUSPC: info->i = PPC; break;
+
+ case CPUINFO_INT_REGISTER + SSP_R0: info->i = ssp1601_state->gr[0].w.h; break;
+ case CPUINFO_INT_REGISTER + SSP_X: info->i = rX; break;
+ case CPUINFO_INT_REGISTER + SSP_Y: info->i = rY; break;
+ case CPUINFO_INT_REGISTER + SSP_A: info->i = rA32; break;
+ case CPUINFO_INT_REGISTER + SSP_ST: info->i = rST; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK: info->i = rSTACK; break;
+ case CPUINFO_INT_PC:
+ case CPUINFO_INT_REGISTER + SSP_PC: info->i = rPC; break;
+ case CPUINFO_INT_REGISTER + SSP_P: info->i = rP.d; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK0: info->i = ssp1601_state->stack[0]; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK1: info->i = ssp1601_state->stack[1]; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK2: info->i = ssp1601_state->stack[2]; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK3: info->i = ssp1601_state->stack[3]; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK4: info->i = ssp1601_state->stack[4]; break;
+ case CPUINFO_INT_REGISTER + SSP_STACK5: info->i = ssp1601_state->stack[5]; break;
+ case CPUINFO_INT_REGISTER + SSP_PR0: info->i = ssp1601_state->r[0]; break;
+ case CPUINFO_INT_REGISTER + SSP_PR1: info->i = ssp1601_state->r[1]; break;
+ case CPUINFO_INT_REGISTER + SSP_PR2: info->i = ssp1601_state->r[2]; break;
+ case CPUINFO_INT_REGISTER + SSP_PR3: info->i = ssp1601_state->r[3]; break;
+ case CPUINFO_INT_REGISTER + SSP_PR4: info->i = ssp1601_state->r[4]; break;
+ case CPUINFO_INT_REGISTER + SSP_PR5: info->i = ssp1601_state->r[5]; break;
+ case CPUINFO_INT_REGISTER + SSP_PR6: info->i = ssp1601_state->r[6]; break;
+ case CPUINFO_INT_REGISTER + SSP_PR7: info->i = ssp1601_state->r[7]; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ssp1601); break;
+ case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(ssp1601); break;
+ case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(ssp1601); break;
+ case CPUINFO_FCT_EXIT: info->exit = CPU_EXIT_NAME(ssp1601); break;
+ case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(ssp1601); break;
+ case CPUINFO_FCT_BURN: info->burn = NULL; break;
+ case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(ssp1601); break;
+ case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ssp1601_state->g_cycles; break;
+
+ case DEVINFO_PTR_INTERNAL_MEMORY_MAP + AS_DATA: info->internal_map16 = NULL; break;
+ case DEVINFO_PTR_INTERNAL_MEMORY_MAP + AS_IO: info->internal_map16 = NULL; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, CHIP_NAME); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "SSP1601 DSP"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Grazvydas Ignotas"); break;
+
+ case CPUINFO_STR_FLAGS:
+ sprintf(info->s, "%c%c%c%c", (rST&SSP_FLAG_N)?'N':'.', (rST&SSP_FLAG_V)?'V':'.',
+ (rST&SSP_FLAG_Z)?'Z':'.', (rST&SSP_FLAG_L)?'L':'.');
+ break;
+
+ case CPUINFO_STR_REGISTER + SSP_R0: sprintf(info->s, "REG0 :%04X", ssp1601_state->gr[0].w.h); break;
+ case CPUINFO_STR_REGISTER + SSP_X: sprintf(info->s, "X :%04X", rX); break;
+ case CPUINFO_STR_REGISTER + SSP_Y: sprintf(info->s, "Y :%04X", rY); break;
+ case CPUINFO_STR_REGISTER + SSP_A: sprintf(info->s, "A :%08X", rA32); break;
+ case CPUINFO_STR_REGISTER + SSP_ST: sprintf(info->s, "ST :%04X", rST); break;
+ case CPUINFO_STR_REGISTER + SSP_STACK: sprintf(info->s, "STACK :%04X", rSTACK); break;
+ case CPUINFO_STR_REGISTER + SSP_PC: sprintf(info->s, "PC :%04X", rPC); break;
+ case CPUINFO_STR_REGISTER + SSP_P: sprintf(info->s, "P :%08X", rP.d); break;
+ case CPUINFO_STR_REGISTER + SSP_STACK0: sprintf(info->s, "STACK0 :%04X", ssp1601_state->stack[0]); break;
+ case CPUINFO_STR_REGISTER + SSP_STACK1: sprintf(info->s, "STACK1 :%04X", ssp1601_state->stack[1]); break;
+ case CPUINFO_STR_REGISTER + SSP_STACK2: sprintf(info->s, "STACK2 :%04X", ssp1601_state->stack[2]); break;
+ case CPUINFO_STR_REGISTER + SSP_STACK3: sprintf(info->s, "STACK3 :%04X", ssp1601_state->stack[3]); break;
+ case CPUINFO_STR_REGISTER + SSP_STACK4: sprintf(info->s, "STACK4 :%04X", ssp1601_state->stack[4]); break;
+ case CPUINFO_STR_REGISTER + SSP_STACK5: sprintf(info->s, "STACK5 :%04X", ssp1601_state->stack[5]); break;
+ case CPUINFO_STR_REGISTER + SSP_PR0: sprintf(info->s, "R0 :%02X", ssp1601_state->r[0]); break;
+ case CPUINFO_STR_REGISTER + SSP_PR1: sprintf(info->s, "R1 :%02X", ssp1601_state->r[1]); break;
+ case CPUINFO_STR_REGISTER + SSP_PR2: sprintf(info->s, "R2 :%02X", ssp1601_state->r[2]); break;
+ case CPUINFO_STR_REGISTER + SSP_PR3: sprintf(info->s, "R3 :%02X", ssp1601_state->r[3]); break;
+ case CPUINFO_STR_REGISTER + SSP_PR4: sprintf(info->s, "R4 :%02X", ssp1601_state->r[4]); break;
+ case CPUINFO_STR_REGISTER + SSP_PR5: sprintf(info->s, "R5 :%02X", ssp1601_state->r[5]); break;
+ case CPUINFO_STR_REGISTER + SSP_PR6: sprintf(info->s, "R6 :%02X", ssp1601_state->r[6]); break;
+ case CPUINFO_STR_REGISTER + SSP_PR7: sprintf(info->s, "R7 :%02X", ssp1601_state->r[7]); break;
+ }
+}
+
+// vim:ts=4
+
+
+DEFINE_LEGACY_CPU_DEVICE(SSP1601, ssp1601);