/* * 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 "debugger.h" #include "ssp1601.h" /* 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; const device_config *device; const address_space *program; const address_space *io; }; // 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() memory_decrypted_read_word(ssp1601_state->program, rPC++ << 1) #define PROGRAM_WORD(a) memory_read_word(ssp1601_state->program, (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 memory_read_word_16be(ssp1601_state->io, (reg << 1)); } static void write_ext(ssp1601_state_t *ssp1601_state, int reg, UINT32 d) { reg &= 7; memory_write_word_16be(ssp1601_state->io, (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 = device->token; state_save_register_device_item(device, 0, rX); state_save_register_device_item(device, 0, rY); state_save_register_device_item(device, 0, rA32); state_save_register_device_item(device, 0, rST); state_save_register_device_item(device, 0, rSTACK); state_save_register_device_item(device, 0, rPC); state_save_register_device_item(device, 0, rP.d); state_save_register_device_item(device, 0, PPC); state_save_register_device_item_array(device, 0, ssp1601_state->stack); state_save_register_device_item_array(device, 0, ssp1601_state->r); state_save_register_device_item_array(device, 0, 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 = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM); ssp1601_state->io = memory_find_address_space(device, ADDRESS_SPACE_IO); } static CPU_EXIT( ssp1601 ) { /* nothing to do */ } static CPU_RESET( ssp1601 ) { ssp1601_state_t *ssp1601_state = device->token; rPC = 0x400; rSTACK = 0; // ? using ascending stack rST = 0; } static CPU_EXECUTE( ssp1601 ) { ssp1601_state_t *ssp1601_state = device->token; ssp1601_state->g_cycles = cycles; 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); return cycles - ssp1601_state->g_cycles; } /************************************************************************** * MAME interface **************************************************************************/ static CPU_DISASSEMBLE( ssp1601 ) { //ssp1601_state_t *ssp1601_state = device->token; return dasm_ssp1601(buffer, pc, oprom); } #if (HAS_SSP1601) static CPU_SET_INFO( ssp1601 ) { ssp1601_state_t *ssp1601_state = device->token; 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; 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 CPUINFO_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 CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break; case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 16; break; case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -1; break; case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break; case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break; case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break; case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 16; break; case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 4; break; case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_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_PTR_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(ssp1601); break; case CPUINFO_PTR_GET_CONTEXT: info->getcontext = CPU_GET_CONTEXT_NAME(dummy); break; case CPUINFO_PTR_SET_CONTEXT: info->setcontext = CPU_SET_CONTEXT_NAME(dummy); break; case CPUINFO_PTR_INIT: info->init = CPU_INIT_NAME(ssp1601); break; case CPUINFO_PTR_RESET: info->reset = CPU_RESET_NAME(ssp1601); break; case CPUINFO_PTR_EXIT: info->exit = CPU_EXIT_NAME(ssp1601); break; case CPUINFO_PTR_EXECUTE: info->execute = CPU_EXECUTE_NAME(ssp1601); break; case CPUINFO_PTR_BURN: info->burn = NULL; break; case CPUINFO_PTR_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(ssp1601); break; case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ssp1601_state->g_cycles; break; case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_DATA: info->internal_map16 = NULL; break; case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_IO: info->internal_map16 = NULL; break; /* --- the following bits of info are returned as NULL-terminated strings --- */ case CPUINFO_STR_NAME: strcpy(info->s, CHIP_NAME); break; case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "SSP1601 DSP"); break; case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break; case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break; case CPUINFO_STR_CORE_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; } } #endif // vim:ts=4