#include "tms57002.h" #include "debugger.h" #ifdef __GNUC__ #define noinline __attribute__((noinline)) #else #define noinline /* */ #endif enum { IN_PLOAD = 0x00000001, IN_CLOAD = 0x00000002, SU_CVAL = 0x00000004, SU_MASK = 0x00000018, SU_ST0 = 0x00, SU_ST1 = 0x08, SU_PRG = 0x10, S_IDLE = 0x00000020, S_READ = 0x00000040, S_WRITE = 0x00000080, S_BRANCH = 0x00000100, S_HOST = 0x00000200 }; enum { ST0_INCS = 0x000001, ST0_DIRI = 0x000002, ST0_FI = 0x000004, ST0_SIM = 0x000008, ST0_PLRI = 0x000020, ST0_PBCI = 0x000040, ST0_DIRO = 0x000080, ST0_FO = 0x000100, ST0_SOM = 0x000600, ST0_PLRO = 0x000800, ST0_PBCO = 0x001000, ST0_CNS = 0x002000, ST0_WORD = 0x004000, ST0_SEL = 0x008000, ST0_M = 0x030000, ST0_M_64K = 0x000000, ST0_M_256K = 0x010000, ST0_M_1M = 0x020000, ST0_SRAM = 0x200000, ST1_AOV = 0x000001, ST1_SFAI = 0x000002, ST1_SFAO = 0x000004, ST1_MOVM = 0x000020, ST1_MOV = 0x000040, ST1_SFMA = 0x000180, ST1_SFMA_SHIFT = 7, ST1_SFMO = 0x001800, ST1_SFMO_SHIFT = 11, ST1_RND = 0x038000, ST1_RND_SHIFT = 15, ST1_CRM = 0x0C0000, ST1_CRM_SHIFT = 18, ST1_CRM_32 = 0x000000, ST1_CRM_16H = 0x040000, ST1_CRM_16L = 0x080000, ST1_DBP = 0x100000, ST1_CAS = 0x200000, ST1_CACHE = ST1_SFAI|ST1_SFAO|ST1_MOVM|ST1_SFMA|ST1_SFMO|ST1_RND|ST1_CRM|ST1_DBP }; enum { BR_UB, BR_CB, BR_IDLE }; enum { IBS = 8192, HBS = 4096 }; typedef struct { unsigned short op; short next; unsigned char param; } icd; typedef struct { unsigned int st1; short ipc; short next; } hcd; typedef struct { short hashbase[256]; hcd hashnode[HBS]; icd inst[IBS]; int hused, iused; } cd; typedef struct { int branch; short hnode; short ipc; } cstate; typedef struct { INT64 macc; UINT32 cmem[256]; UINT32 dmem0[256]; UINT32 dmem1[32]; UINT32 si[4], so[4]; UINT32 st0, st1, sti; UINT32 aacc, xoa, xba, xwr, xrd, creg; UINT8 pc, ca, id, ba0, ba1, rptc, rptc_next, sa; UINT32 xm_adr; UINT8 host[4], hidx, allow_update; cd cache; const address_space *program, *data; int icount; int unsupported_inst_warning; } tms57002_t; INLINE tms57002_t *get_safe_token(const device_config *device) { assert(device != NULL); assert(device->token != NULL); assert(device->type == CPU); assert(cpu_get_type(device) == CPU_TMS57002); return (tms57002_t *)device->token; } static void tms57002_cache_flush(tms57002_t *s); static const char *tms57002_get_memadr(UINT32 opcode, char type) { static char buff[2][10]; static int index = 0; char *buf; index = 1-index; buf = buff[index]; if(((opcode & 0x400) && (type == 'c')) || (!(opcode & 0x400) && (type == 'd'))) { if(opcode & 0x100) sprintf(buf, "%c(%02x)", type, opcode & 0xff); else if(opcode & 0x80) sprintf(buf, "%c*+", type); else sprintf(buf, "%c*", type); } else if(opcode & 0x200) sprintf(buf, "%c*+", type); else sprintf(buf, "%c*", type); return buf; } static CPU_DISASSEMBLE(tms57002) { UINT32 opcode = opram[0] | (opram[1] << 8) | (opram[2] << 16); UINT8 fa = opcode >> 18; char *buf = buffer; if(fa == 0x3f) { switch((opcode >> 11) & 0x7f) { // category 3 #define DASM3 #include "cpu/tms57002/tms57002.inc" #undef DASM3 default: sprintf(buf, "unk c3 %02x", (opcode >> 11) & 0x7f); break; } } else { switch(fa) { // category 1 case 0x00: buf[0] = 0; break; #define DASM1 #include "cpu/tms57002/tms57002.inc" #undef DASM1 default: sprintf(buf, "unk c1 %02x", fa); break; } buf += strlen(buf); if(buf != buffer) { strcpy(buf, " ; "); buf += 3; } switch((opcode >> 11) & 0x7f) { // category 2 case 0x00: if(buf != buffer) buf[-3] = 0; else sprintf(buf, "nop"); break; #define DASM2 #include "cpu/tms57002/tms57002.inc" #undef DASM2 default: sprintf(buf, "unk c2 %02x", (opcode >> 11) & 0x7f); break; } } return 1; } WRITE8_DEVICE_HANDLER(tms57002_pload_w) { tms57002_t *s = get_safe_token(device); UINT8 olds = s->sti; if(data) s->sti &= ~IN_PLOAD; else s->sti |= IN_PLOAD; if(olds ^ s->sti) s->hidx = 0; } WRITE8_DEVICE_HANDLER(tms57002_cload_w) { tms57002_t *s = get_safe_token(device); UINT8 olds = s->sti; if(data) s->sti &= ~IN_CLOAD; else s->sti |= IN_CLOAD; if(olds ^ s->sti) s->hidx = 0; } static CPU_RESET(tms57002) { tms57002_t *s = get_safe_token(device); s->sti = (s->sti & ~(SU_MASK|S_READ|S_WRITE|S_BRANCH|S_HOST)) | (SU_ST0|S_IDLE); s->pc = 0; s->ca = 0; s->hidx = 0; s->id = 0; s->ba0 = 0; s->ba1 = 0; s->st0 &= ~(ST0_INCS | ST0_DIRI | ST0_FI | ST0_SIM | ST0_PLRI | ST0_PBCI | ST0_DIRO | ST0_FO | ST0_SOM | ST0_PLRO | ST0_PBCO | ST0_CNS); s->st1 &= ~(ST1_AOV | ST1_SFAI | ST1_SFAO | ST1_MOVM | ST1_MOV | ST1_SFMA | ST1_SFMO | ST1_RND | ST1_CRM | ST1_DBP); s->xba = 0; // Not sure but makes sense tms57002_cache_flush(s); } WRITE8_DEVICE_HANDLER(tms57002_data_w) { tms57002_t *s = get_safe_token(device); switch(s->sti & (IN_PLOAD|IN_CLOAD)) { case 0: s->hidx = 0; s->sti &= ~SU_CVAL; break; case IN_PLOAD: s->host[s->hidx++] = data; if(s->hidx >= 3) { UINT32 val = (s->host[0]<<16) | (s->host[1]<<8) | s->host[2]; s->hidx = 0; switch(s->sti & SU_MASK) { case SU_ST0: s->st0 = val; s->sti = (s->sti & ~SU_MASK) | SU_ST1; break; case SU_ST1: s->st1 = val; s->sti = (s->sti & ~SU_MASK) | SU_PRG; break; case SU_PRG: memory_write_dword_32le(s->program, (s->pc++) << 2, val); break; } } break; case IN_CLOAD: if(s->sti & SU_CVAL) { s->host[s->hidx++] = data; if(s->hidx >= 4) { UINT32 val = (s->host[0]<<24) | (s->host[1]<<16) | (s->host[2]<<8) | s->host[3]; s->cmem[s->sa] = val; s->sti &= ~SU_CVAL; s->allow_update = 0; } } else { s->sa = data; s->hidx = 0; s->sti |= SU_CVAL; } break; case IN_PLOAD|IN_CLOAD: s->host[s->hidx++] = data; if(s->hidx >= 4) { UINT32 val = (s->host[0]<<24) | (s->host[1]<<16) | (s->host[2]<<8) | s->host[3]; s->hidx = 0; s->cmem[s->ca++] = val; } break; }; } READ8_DEVICE_HANDLER(tms57002_data_r) { tms57002_t *s = get_safe_token(device); UINT8 res; if(!(s->sti & S_HOST)) return 0xff; res = s->host[s->hidx]; s->hidx++; if(s->hidx == 4) { s->hidx = 0; s->sti &= ~S_HOST; } return res; } READ8_DEVICE_HANDLER(tms57002_empty_r) { return 1; } READ8_DEVICE_HANDLER(tms57002_dready_r) { tms57002_t *s = get_safe_token(device); return s->sti & S_HOST ? 0 : 1; } void tms57002_sync(const device_config *device) { tms57002_t *s = get_safe_token(device); if(s->sti & (IN_PLOAD | IN_CLOAD)) return; s->allow_update = 1; s->pc = 0; s->ca = 0; s->id = 0; if(!(s->st0 & ST0_INCS)) { s->ba0--; s->ba1++; } s->xba = (s->xba-1) & 0x7ffff; s->st1 &= ~(ST1_AOV | ST1_MOV); s->sti &= ~S_IDLE; } #ifdef UNUSED_FUNCTION static UINT32 tms57002_read_c(tms57002_t *s, UINT8 index) { UINT32 v = s->cmem[index]; if((s->st1 & ST1_CRM) != ST1_CRM_32) { if((s->st1 & ST1_CRM) == ST1_CRM_16H) v &= 0xffff0000; else if((s->st1 & ST1_CRM) == ST1_CRM_16L) v <<= 16; } return v; } static void tms57002_write_c(tms57002_t *s, UINT8 index, UINT32 v) { s->cmem[index] = v; } static void tms57002_write_d(tms57002_t *s, UINT8 index, UINT32 v) { if(s->st1 & ST1_DBP) s->dmem1[(s->ba1 + index) & 0x1f] = v; else s->dmem0[(s->ba0 + index) & 0xff] = v; } static UINT32 tms57002_read_d(tms57002_t *s, UINT8 index) { if(s->st1 & ST1_DBP) return s->dmem1[(s->ba1 + index) & 0x1f]; else return s->dmem0[(s->ba0 + index) & 0xff]; } static void tms57002_opc_write_c(tms57002_t *s, UINT32 opcode, UINT32 v) { if(opcode & 0x400) { if(opcode & 0x100) tms57002_write_c(s, opcode & 0xff, v); else if(opcode & 0x80) tms57002_write_c(s, s->ca++, v); else tms57002_write_c(s, s->ca, v); } else if(opcode & 0x200) tms57002_write_c(s, s->ca++, v); else tms57002_write_c(s, s->ca, v); } static UINT32 tms57002_opc_read_c(tms57002_t *s, UINT32 opcode) { if(opcode & 0x400) { if(opcode & 0x100) return tms57002_read_c(s, opcode & 0xff); else if(opcode & 0x80) return tms57002_read_c(s, s->ca++); else return tms57002_read_c(s, s->ca); } else if(opcode & 0x200) return tms57002_read_c(s, s->ca++); else return tms57002_read_c(s, s->ca); } static void tms57002_opc_write_d(tms57002_t *s, UINT32 opcode, UINT32 v) { if(!(opcode & 0x400)) { if(opcode & 0x100) tms57002_write_d(s, opcode & 0xff, v); else if(opcode & 0x80) tms57002_write_d(s, s->id++, v); else tms57002_write_d(s, s->id, v); } else if(opcode & 0x200) tms57002_write_d(s, s->id++, v); else tms57002_write_d(s, s->id, v); } static UINT32 tms57002_opc_read_d(tms57002_t *s, UINT32 opcode) { if(!(opcode & 0x400)) { if(opcode & 0x100) return tms57002_read_d(s, opcode & 0xff); else if(opcode & 0x80) return tms57002_read_d(s, s->id++); else return tms57002_read_d(s, s->id); } else if(opcode & 0x200) return tms57002_read_d(s, s->id++); else return tms57002_read_d(s, s->id); } #endif static void tms57002_xm_init(tms57002_t *s) { UINT32 adr = s->xoa + s->xba; UINT32 mask = 0; switch(s->st0 & ST0_M) { case ST0_M_64K: mask = 0x0ffff; break; case ST0_M_256K: mask = 0x3ffff; break; case ST0_M_1M: mask = 0xfffff; break; } if(s->st0 & ST0_WORD) adr <<= 2; else adr <<= 1; if(!(s->st0 & ST0_SEL)) adr <<= 1; s->xm_adr = adr & mask; } static void tms57002_xm_step_read(tms57002_t *s) { UINT32 adr = s->xm_adr; UINT8 v = memory_read_byte_8le(s->data, adr); int done; if(s->st0 & ST0_WORD) { if(s->st0 & ST0_SEL) { int off = (adr & 3) << 3; s->xrd = (s->xrd & ~(0xff << off)) | (v << off); done = off == 16; } else { int off = (adr & 7) << 2; s->xrd = (s->xrd & ~(0xf << off)) | ((v & 0xf) << off); done = off == 20; } } else { if(s->st0 & ST0_SEL) { int off = (adr & 1) << 3; s->xrd = (s->xrd & ~(0xff << off)) | (v << off); done = off == 8; if(done) s->xrd &= 0x00ffff; } else { int off = (adr & 3) << 2; s->xrd = (s->xrd & ~(0xf << off)) | ((v & 0xf) << off); done = off == 12; if(done) s->xrd &= 0x00ffff; } } if(done) { s->sti &= ~S_READ; s->xm_adr = 0; } else s->xm_adr = adr+1; } static void tms57002_xm_step_write(tms57002_t *s) { UINT32 adr = s->xm_adr; UINT8 v; int done; if(s->st0 & ST0_WORD) { if(s->st0 & ST0_SEL) { int off = (adr & 3) << 3; v = s->xwr >> off; done = off == 16; } else { int off = (adr & 7) << 2; v = (s->xwr >> off) & 0xf; done = off == 20; } } else { if(s->st0 & ST0_SEL) { int off = (adr & 1) << 3; v = s->xwr >> off; done = off == 8; } else { int off = (adr & 3) << 2; v = (s->xwr >> off) & 0xf; done = off == 12; } } memory_write_byte_8le(s->data, adr, v); if(done) { s->sti &= ~S_WRITE; s->xm_adr = 0; } else s->xm_adr = adr+1; } #ifdef UNUSED_FUNCTION static UINT32 tms57002_aacc_to_output(tms57002_t *s) { if(s->st1 & ST1_SFAO) return s->aacc << 7; else return s->aacc; } static INT64 tms57002_macc_to_output(tms57002_t *s) { INT64 m = s->macc; UINT64 m1; int over = 0, rmode; static const INT64 rounding[8] = { 0, 1LL << (48-32-1), 1LL << (48-24-1), 1LL << (48-30-1), 1LL << (48-16-1), 0, 0, 0 }; static const UINT64 rmask[8] = { ~0ULL, (~0ULL) << (48-32), (~0ULL) << (48-24), (~0ULL) << (48-30), (~0ULL) << (48-16), ~0ULL, ~0ULL, ~0ULL }; // Overflow detection and shifting switch((s->st1 & ST1_SFMO) >> ST1_SFMO_SHIFT) { case 0: // sfmo 0 m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; break; case 1: // sfmo 2 m1 = m & 0xfe00000000000ULL; if(m1 && m1 != 0xfe00000000000ULL) over = 1; m <<= 2; break; case 2: // sfmo 4 m1 = m & 0xff80000000000ULL; if(m1 && m1 != 0xff80000000000ULL) over = 1; m <<= 4; break; case 3: // sfmo -8 m >>= 8; break; } // Rounder rmode = (s->st1 & ST1_RND) >> ST1_RND_SHIFT; m = (m + rounding[rmode]) & rmask[rmode]; // Second overflow detection m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; // Overflow handling if(over) { s->st1 |= ST1_MOV; if(s->st1 & ST1_MOVM) { if(m & 0x8000000000000ULL) m = 0xffff800000000000ULL; else m = 0x00007fffffffffffULL; } } return m; } #endif static noinline INT64 tms57002_macc_to_output_0(tms57002_t *s, INT64 rounding, UINT64 rmask) { INT64 m = s->macc; UINT64 m1; int over = 0; // Overflow detection and shifting m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; m = (m + rounding) & rmask; // Second overflow detection m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; // Overflow handling if(over) { s->st1 |= ST1_MOV; } return m; } static noinline INT64 tms57002_macc_to_output_1(tms57002_t *s, INT64 rounding, UINT64 rmask) { INT64 m = s->macc; UINT64 m1; int over = 0; // Overflow detection and shifting m1 = m & 0xfe00000000000ULL; if(m1 && m1 != 0xfe00000000000ULL) over = 1; m <<= 2; m = (m + rounding) & rmask; // Second overflow detection m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; // Overflow handling if(over) { s->st1 |= ST1_MOV; } return m; } static noinline INT64 tms57002_macc_to_output_2(tms57002_t *s, INT64 rounding, UINT64 rmask) { INT64 m = s->macc; UINT64 m1; int over = 0; // Overflow detection and shifting m1 = m & 0xff80000000000ULL; if(m1 && m1 != 0xff80000000000ULL) over = 1; m <<= 4; m = (m + rounding) & rmask; // Second overflow detection m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; // Overflow handling if(over) { s->st1 |= ST1_MOV; } return m; } static noinline INT64 tms57002_macc_to_output_3(tms57002_t *s, INT64 rounding, UINT64 rmask) { INT64 m = s->macc; UINT64 m1; int over = 0; // Overflow detection and shifting m >>= 8; m = (m + rounding) & rmask; // Second overflow detection m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; // Overflow handling if(over) { s->st1 |= ST1_MOV; } return m; } static noinline INT64 tms57002_macc_to_output_0s(tms57002_t *s, INT64 rounding, UINT64 rmask) { INT64 m = s->macc; UINT64 m1; int over = 0; // Overflow detection and shifting m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; m = (m + rounding) & rmask; // Second overflow detection m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; // Overflow handling if(over) { s->st1 |= ST1_MOV; if(m & 0x8000000000000ULL) m = 0xffff800000000000ULL; else m = 0x00007fffffffffffULL; } return m; } static noinline INT64 tms57002_macc_to_output_1s(tms57002_t *s, INT64 rounding, UINT64 rmask) { INT64 m = s->macc; UINT64 m1; int over = 0; // Overflow detection and shifting m1 = m & 0xfe00000000000ULL; if(m1 && m1 != 0xfe00000000000ULL) over = 1; m <<= 2; m = (m + rounding) & rmask; // Second overflow detection m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; // Overflow handling if(over) { s->st1 |= ST1_MOV; if(m & 0x8000000000000ULL) m = 0xffff800000000000ULL; else m = 0x00007fffffffffffULL; } return m; } static noinline INT64 tms57002_macc_to_output_2s(tms57002_t *s, INT64 rounding, UINT64 rmask) { INT64 m = s->macc; UINT64 m1; int over = 0; // Overflow detection and shifting m1 = m & 0xff80000000000ULL; if(m1 && m1 != 0xff80000000000ULL) over = 1; m <<= 4; m = (m + rounding) & rmask; // Second overflow detection m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; // Overflow handling if(over) { s->st1 |= ST1_MOV; if(m & 0x8000000000000ULL) m = 0xffff800000000000ULL; else m = 0x00007fffffffffffULL; } return m; } static noinline INT64 tms57002_macc_to_output_3s(tms57002_t *s, INT64 rounding, UINT64 rmask) { INT64 m = s->macc; UINT64 m1; int over = 0; // Overflow detection and shifting m >>= 8; m = (m + rounding) & rmask; // Second overflow detection m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; // Overflow handling if(over) { s->st1 |= ST1_MOV; if(m & 0x8000000000000ULL) m = 0xffff800000000000ULL; else m = 0x00007fffffffffffULL; } return m; } #ifdef UNUSED_FUNCTION static INT64 tms57002_check_macc_overflow(tms57002_t *s) { INT64 m = s->macc; UINT64 m1; int over = 0; // Overflow detection switch((s->st1 & ST1_SFMO) >> ST1_SFMO_SHIFT) { case 0: // sfmo 0 m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) over = 1; break; case 1: // sfmo 2 m1 = m & 0xfe00000000000ULL; if(m1 && m1 != 0xfe00000000000ULL) over = 1; break; case 2: // sfmo 4 m1 = m & 0xff80000000000ULL; if(m1 && m1 != 0xff80000000000ULL) over = 1; break; case 3: // sfmo -8 break; } // Overflow handling if(over) { s->st1 |= ST1_MOV; if(s->st1 & ST1_MOVM) { if(m & 0x8000000000000ULL) m = 0xffff800000000000ULL; else m = 0x00007fffffffffffULL; } } return m; } #endif static noinline INT64 tms57002_check_macc_overflow_0(tms57002_t *s) { INT64 m = s->macc; UINT64 m1; // Overflow detection m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) { s->st1 |= ST1_MOV; } return m; } static noinline INT64 tms57002_check_macc_overflow_1(tms57002_t *s) { INT64 m = s->macc; UINT64 m1; // Overflow detection m1 = m & 0xfe00000000000ULL; if(m1 && m1 != 0xfe00000000000ULL) { s->st1 |= ST1_MOV; } return m; } static noinline INT64 tms57002_check_macc_overflow_2(tms57002_t *s) { INT64 m = s->macc; UINT64 m1; // Overflow detection m1 = m & 0xff80000000000ULL; if(m1 && m1 != 0xff80000000000ULL) { s->st1 |= ST1_MOV; } return m; } static INT64 tms57002_check_macc_overflow_3(tms57002_t *s) { return s->macc; } static noinline INT64 tms57002_check_macc_overflow_0s(tms57002_t *s) { INT64 m = s->macc; UINT64 m1; // Overflow detection m1 = m & 0xf800000000000ULL; if(m1 && m1 != 0xf800000000000ULL) { s->st1 |= ST1_MOV; if(m & 0x8000000000000ULL) m = 0xffff800000000000ULL; else m = 0x00007fffffffffffULL; } return m; } static noinline INT64 tms57002_check_macc_overflow_1s(tms57002_t *s) { INT64 m = s->macc; UINT64 m1; // Overflow detection m1 = m & 0xfe00000000000ULL; if(m1 && m1 != 0xfe00000000000ULL) { s->st1 |= ST1_MOV; if(m & 0x8000000000000ULL) m = 0xffff800000000000ULL; else m = 0x00007fffffffffffULL; } return m; } static noinline INT64 tms57002_check_macc_overflow_2s(tms57002_t *s) { INT64 m = s->macc; UINT64 m1; // Overflow detection m1 = m & 0xff80000000000ULL; if(m1 && m1 != 0xff80000000000ULL) { s->st1 |= ST1_MOV; if(m & 0x8000000000000ULL) m = 0xffff800000000000ULL; else m = 0x00007fffffffffffULL; } return m; } static INT64 tms57002_check_macc_overflow_3s(tms57002_t *s) { return s->macc; } #ifdef UNUSED_FUNCTION static INT64 tms57002_macc_to_loop(tms57002_t *s) { INT64 m = s->macc; // sfma shifting switch((s->st1 & ST1_SFMA) >> ST1_SFMA_SHIFT) { case 0: // sfma 0 break; case 1: // sfma 2 m <<= 2; break; case 2: // sfma 4 m <<= 4; break; case 3: // sfma -16 if(m & 0x8000000000000ULL) m |= 0xfff0000000000000ULL; m >>= 16; break; } return m; } static void tms57002_execute_cat1(tms57002_t *s, UINT32 opcode) { UINT32 c, d; INT64 r; switch(opcode >> 18) { case 0x00: // nop break; #define INTRP1 #include "cpu/tms57002/tms57002.inc" #undef INTRP1 default: fatalerror("Unhandled case in tms57002_execute_cat1"); } } static void tms57002_execute_cat2_pre(tms57002_t *s, UINT32 opcode) { switch((opcode >> 11) & 0x7f) { case 0x00: // nop break; #define INTRP2A #include "cpu/tms57002/tms57002.inc" #undef INTRP2A default: fatalerror("Unhandled case in tms57002_execute_cat2_pre"); } } static void tms57002_execute_cat2_post(tms57002_t *s, UINT32 opcode) { UINT32 c; switch((opcode >> 11) & 0x7f) { case 0x00: // nop break; #define INTRP2B #include "cpu/tms57002/tms57002.inc" #undef INTRP2B default: fatalerror("Unhandled case in tms57002_execute_cat2_post"); } } static void tms57002_execute_cat3(tms57002_t *s, UINT32 opcode) { switch((opcode >> 11) & 0x7f) { case 0x00: // nop break; #define INTRP3 #include "cpu/tms57002/tms57002.inc" #undef INTRP3 default: fatalerror("Unhandled case in tms57002_execute_cat3"); } } void tms57002_execute(tms57002_t *s) { while(!(s->sti & (S_IDLE | IN_PLOAD | IN_CLOAD))) { UINT32 opcode = memory_read_dword_32le(s->program, s->pc << 2); if(s->sti & (S_READ|S_WRITE)) { if(s->sti & S_READ) tms57002_xm_step_read(s); else tms57002_xm_step_write(s); } if((opcode & 0xfc0000) == 0xfc0000) tms57002_execute_cat3(s, opcode); else { tms57002_execute_cat2_pre(s, opcode); tms57002_execute_cat1(s, opcode); tms57002_execute_cat2_post(s, opcode); } if(s->rptc) s->rptc--; else if(s->sti & S_BRANCH) s->sti &= ~S_BRANCH; else s->pc++; // Wraps if it reaches 256 if(s->rptc_next) { s->rptc = s->rptc_next; s->rptc_next = 0; } } } #endif INLINE int xmode(UINT32 opcode, char type) { if(((opcode & 0x400) && (type == 'c')) || (!(opcode & 0x400) && (type == 'd'))) { if(opcode & 0x100) return 0; else if(opcode & 0x80) return 2; else return 1; } else if(opcode & 0x200) return 2; else return 1; } INLINE int sfao(UINT32 st1) { return st1 & ST1_SFAO ? 1 : 0; } INLINE int dbp(UINT32 st1) { return st1 & ST1_DBP ? 1 : 0; } INLINE int crm(UINT32 st1) { return (st1 & ST1_CRM) >> ST1_CRM_SHIFT; } INLINE int sfai(UINT32 st1) { return st1 & ST1_SFAI ? 1 : 0; } INLINE int sfmo(UINT32 st1) { return (st1 & ST1_SFMO) >> ST1_SFMO_SHIFT; } INLINE int rnd(UINT32 st1) { return (st1 & ST1_RND) >> ST1_RND_SHIFT; } INLINE int movm(UINT32 st1) { return st1 & ST1_MOVM ? 1 : 0; } INLINE int sfma(UINT32 st1) { return (st1 & ST1_SFMA) >> ST1_SFMA_SHIFT; } static void tms57002_cache_flush(tms57002_t *s) { int i; s->cache.hused = s->cache.iused = 0; for(i=0; i != 256; i++) s->cache.hashbase[i] = -1; for(i=0; i != HBS; i++) { s->cache.hashnode[i].st1 = 0; s->cache.hashnode[i].ipc = -1; s->cache.hashnode[i].next = -1; } for(i=0; i != IBS; i++) { s->cache.inst[i].op = 0; s->cache.inst[i].next = -1; s->cache.inst[i].param = 0; } } static void tms57002_decode_error(tms57002_t *s, UINT32 opcode) { char buf[256]; UINT8 opr[3]; if(s->unsupported_inst_warning) return; s->unsupported_inst_warning = 1; opr[0] = opcode; opr[1] = opcode >> 8; opr[2] = opcode >> 16; CPU_DISASSEMBLE_NAME(tms57002)(0, buf, s->pc, opr, opr); popmessage("tms57002: %s - Contact Mamedev", buf); } static void tms57002_decode_cat1(tms57002_t *s, UINT32 opcode, unsigned short *op, cstate *cs) { switch(opcode >> 18) { case 0x00: // nop break; #define CDEC1 #include "cpu/tms57002/tms57002.inc" #undef CDEC1 default: tms57002_decode_error(s, opcode); break; } } static void tms57002_decode_cat2_pre(tms57002_t *s, UINT32 opcode, unsigned short *op, cstate *cs) { switch((opcode >> 11) & 0x7f) { case 0x00: // nop break; #define CDEC2A #include "cpu/tms57002/tms57002.inc" #undef CDEC2A default: tms57002_decode_error(s, opcode); break; } } static void tms57002_decode_cat2_post(tms57002_t *s, UINT32 opcode, unsigned short *op, cstate *cs) { switch((opcode >> 11) & 0x7f) { case 0x00: // nop break; #define CDEC2B #include "cpu/tms57002/tms57002.inc" #undef CDEC2B default: tms57002_decode_error(s, opcode); break; } } static void tms57002_decode_cat3(tms57002_t *s, UINT32 opcode, unsigned short *op, cstate *cs) { switch((opcode >> 11) & 0x7f) { case 0x00: // nop break; #define CDEC3 #include "cpu/tms57002/tms57002.inc" #undef CDEC3 default: tms57002_decode_error(s, opcode); break; } } static void tms57002_add_one(tms57002_t *s, cstate *cs, unsigned short op, UINT8 param) { short ipc = s->cache.iused++; s->cache.inst[ipc].op = op; s->cache.inst[ipc].param = param; s->cache.inst[ipc].next = -1; if(cs->ipc != -1) s->cache.inst[cs->ipc].next = ipc; cs->ipc = ipc; if(cs->hnode != -1) { s->cache.hashnode[cs->hnode].ipc = ipc; cs->hnode = -1; } } static void tms57002_decode_one(tms57002_t *s, UINT32 opcode, cstate *cs, void (*dec)(tms57002_t *s, UINT32 opcode, unsigned short *op, cstate *cs)) { unsigned short op = 0; dec(s, opcode, &op, cs); if(!op) return; tms57002_add_one(s, cs, op, opcode & 0xff); } static short tms57002_get_hash(tms57002_t *s, unsigned char adr, UINT32 st1, short *pnode) { short hnode; st1 &= ST1_CACHE; *pnode = -1; hnode = s->cache.hashbase[adr]; while(hnode != -1) { if(s->cache.hashnode[hnode].st1 == st1) return s->cache.hashnode[hnode].ipc; *pnode = hnode; hnode = s->cache.hashnode[hnode].next; } return -1; } static short tms57002_get_hashnode(tms57002_t *s, unsigned char adr, UINT32 st1, short pnode) { short hnode = s->cache.hused++; s->cache.hashnode[hnode].st1 = st1 & ST1_CACHE; s->cache.hashnode[hnode].ipc = -1; s->cache.hashnode[hnode].next = -1; if(pnode == -1) s->cache.hashbase[adr] = hnode; else s->cache.hashnode[pnode].next = hnode; return hnode; } static int tms57002_decode_get_pc(tms57002_t *s) { UINT32 st1 = s->st1; short pnode, res; cstate cs; UINT8 adr = s->pc; res = tms57002_get_hash(s, adr, st1, &pnode); if(res != -1) return res; if(HBS - s->cache.hused < 256 || IBS - s->cache.iused < 256*3) { tms57002_cache_flush(s); pnode = -1; } cs.hnode = res = tms57002_get_hashnode(s, adr, st1, pnode); cs.ipc = -1; cs.branch = 0; for(;;) { short ipc; UINT32 opcode = memory_read_dword_32le(s->program, adr << 2); if((opcode & 0xfc0000) == 0xfc0000) tms57002_decode_one(s, opcode, &cs, tms57002_decode_cat3); else { tms57002_decode_one(s, opcode, &cs, tms57002_decode_cat2_pre); tms57002_decode_one(s, opcode, &cs, tms57002_decode_cat1); tms57002_decode_one(s, opcode, &cs, tms57002_decode_cat2_post); } tms57002_add_one(s, &cs, 0, 0); if(cs.branch) break; adr++; ipc = tms57002_get_hash(s, adr, st1, &pnode); if(ipc != -1) { s->cache.inst[cs.ipc].next = ipc; break; } cs.hnode = tms57002_get_hashnode(s, adr, s->st1, pnode); } s->st1 = st1; return s->cache.hashnode[res].ipc; } static CPU_EXECUTE(tms57002) { tms57002_t *s = get_safe_token(device); int initial_cycles = cycles; int ipc = -1; while(cycles > 0 && !(s->sti & (S_IDLE | IN_PLOAD | IN_CLOAD))) { int iipc; debugger_instruction_hook(device, s->pc); if(ipc == -1) ipc = tms57002_decode_get_pc(s); iipc = ipc; if(s->sti & (S_READ|S_WRITE)) { if(s->sti & S_READ) tms57002_xm_step_read(s); else tms57002_xm_step_write(s); } for(;;) { UINT32 c, d; INT64 r; const icd *i = s->cache.inst + ipc; ipc = i->next; switch(i->op) { case 0: goto inst; #define CINTRP #include "cpu/tms57002/tms57002.inc" #undef CINTRP default: fatalerror("Unhandled opcode in tms57002_execute"); } } inst: cycles--; if(s->rptc) { s->rptc--; ipc = iipc; } else if(s->sti & S_BRANCH) { s->sti &= ~S_BRANCH; ipc = -1; } else s->pc++; // Wraps if it reaches 256, next wraps too if(s->rptc_next) { s->rptc = s->rptc_next; s->rptc_next = 0; } } if(cycles > 0) cycles = 0; return initial_cycles - cycles; } static CPU_INIT(tms57002) { tms57002_t *s = get_safe_token(device); tms57002_cache_flush(s); s->sti = S_IDLE; s->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM); s->data = memory_find_address_space(device, ADDRESS_SPACE_DATA); } static CPU_SET_INFO(tms57002) { } static ADDRESS_MAP_START(internal_pgm, ADDRESS_SPACE_PROGRAM, 32) AM_RANGE(0x000, 0x3ff) AM_RAM ADDRESS_MAP_END CPU_GET_INFO(tms57002) { tms57002_t *s = (device != NULL && device->token != NULL) ? get_safe_token(device) : NULL; switch(state) { case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(tms57002_t); break; case CPUINFO_INT_INPUT_LINES: info->i = 0; break; case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; 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 = 4; 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 = 3; break; case CPUINFO_INT_DATABUS_WIDTH_PROGRAM: info->i = 32; break; case CPUINFO_INT_ADDRBUS_WIDTH_PROGRAM: info->i = 8; break; case CPUINFO_INT_ADDRBUS_SHIFT_PROGRAM: info->i = -2; break; case CPUINFO_INT_DATABUS_WIDTH_DATA: info->i = 8; break; case CPUINFO_INT_ADDRBUS_WIDTH_DATA: info->i = 20; break; case CPUINFO_INT_ADDRBUS_SHIFT_DATA: info->i = 0; break; case CPUINFO_INT_DATABUS_WIDTH_IO: info->i = 0; break; case CPUINFO_INT_ADDRBUS_WIDTH_IO: info->i = 0; break; case CPUINFO_INT_ADDRBUS_SHIFT_IO: info->i = 0; break; case CPUINFO_FCT_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(tms57002); break; case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(tms57002); break; case CPUINFO_FCT_RESET: info->reset = CPU_RESET_NAME(tms57002); break; case CPUINFO_FCT_EXECUTE: info->execute = CPU_EXECUTE_NAME(tms57002); break; case CPUINFO_FCT_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(tms57002); break; case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &s->icount; break; case CPUINFO_PTR_INTERNAL_MEMORY_MAP: info->internal_map32 = ADDRESS_MAP_NAME(internal_pgm); break; case CPUINFO_STR_NAME: strcpy( info->s, "TMS57002" ); break; case CPUINFO_STR_CORE_FAMILY: strcpy( info->s, "Texas Instruments TMS57002 (DASP)" ); 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 Olivier Galibert" ); break; } }