mame/src/emu/cpu/tms57002/tms57002.c
Aaron Giles 03b5da1a55 Added 'options' parameter to the CPU_DISASSEMBLE prototype. For now, the
debugger always passes 0 for this. unidasm has been updated to accept a
mode parameter, which is passed for the options.
2009-09-07 00:26:56 +00:00

1395 lines
28 KiB
C

#include "tms57002.h"
#include "debugger.h"
CPU_DISASSEMBLE(tms57002);
#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);
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, 0);
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 DEVINFO_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_PROGRAM:info->internal_map32 = ADDRESS_MAP_NAME(internal_pgm); break;
case DEVINFO_STR_NAME: strcpy( info->s, "TMS57002" ); break;
case DEVINFO_STR_FAMILY: strcpy( info->s, "Texas Instruments TMS57002 (DASP)" ); 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 Olivier Galibert" ); break;
}
}