mame/src/emu/cpu/cubeqcpu/cubeqcpu.c
Aaron Giles 9407fecd2d Populated tag and static_config parts of fake CPU device. Removed 'config'
parameter from CPU_INIT. Modified CPU cores to pull config from the device
static_config.
2008-11-09 07:12:24 +00:00

2196 lines
66 KiB
C

/***************************************************************************
cubeqcpu.c
Implementation of the Cube Quest AM2901-based CPUs
TODO:
* Tidy up diassembly (split into different files?)
***************************************************************************/
#include "debugger.h"
#include "deprecat.h"
#include "cubeqcpu.h"
/***************************************************************************
CONSTANTS
***************************************************************************/
/* Am2901 Instruction Fields */
static const char *const ins[] =
{
"ADD ",
"SUBR ",
"SUBS ",
"OR ",
"AND ",
"NOTRS",
"EXOR ",
"EXNOR",
};
static const char *const src[] =
{
"A,Q",
"A,B",
"0,Q",
"0,B",
"0,A",
"D,A",
"D,Q",
"D,0",
};
static const char *const dst[] =
{
"QREG ",
"NOP ",
"RAMA ",
"RAMF ",
"RAMQD",
"RAMD ",
"RAMQU",
"RAMU ",
};
enum alu_src
{
AQ = 0,
AB = 1,
ZQ = 2,
ZB = 3,
ZA = 4,
DA = 5,
DQ = 6,
DZ = 7,
};
enum alu_ins
{
ADD = 0,
SUBR = 1,
SUBS = 2,
OR = 3,
AND = 4,
NOTRS = 5,
EXOR = 6,
EXNOR = 7,
};
enum alu_dst
{
QREG = 0,
NOP = 1,
RAMA = 2,
RAMF = 3,
RAMQD = 4,
RAMD = 5,
RAMQU = 6,
RAMU = 7,
};
/***************************************************************************
MACROS
***************************************************************************/
#define _BIT(x, n) ((x) & (1 << (n)))
/***************************************************************************
STRUCTURES & TYPEDEFS
***************************************************************************/
typedef struct
{
/* AM2901 internals */
UINT16 ram[16];
UINT16 q;
UINT16 f;
UINT16 y;
UINT32 cflag;
UINT32 vflag;
UINT8 pc; /* 2 x LS161 @ 6E, 6F */
UINT16 platch;
UINT8 rtnlatch; /* LS374 @ 5F */
UINT8 adrcntr; /* 2 x LS161 */
UINT16 adrlatch;
UINT16 dinlatch;
UINT16 ramwlatch;
UINT16 *sram;
int prev_ipram;
int prev_ipwrt;
void (*dac_w)(UINT16 data);
UINT16 *sound_data;
} cquestsnd_state;
typedef struct
{
/* AM2901 internals */
UINT16 ram[16];
UINT16 q;
UINT16 f;
UINT16 y;
UINT32 cflag;
UINT32 vflag;
UINT16 pc; /* 12-bit, but only 9 used */
UINT8 seqcnt; /* 4-bit counter */
UINT8 dsrclatch;
UINT8 rsrclatch;
UINT16 dynaddr; /* LS374 at 2D, 8D */
UINT16 dyndata; /* LS374 at 10B, 9B */
UINT16 yrlatch; /* LS374 at 9D, 10D */
UINT16 ydlatch; /* LS374 at 9C, 10C */
UINT16 dinlatch;
UINT8 divreg; /* LS74 at ? */
UINT16 linedata;
UINT16 lineaddr;
UINT16 *dram;
UINT16 *sram;
UINT8 prev_dred;
UINT8 prev_dwrt;
UINT8 wc;
UINT8 rc;
UINT8 clkcnt;
} cquestrot_state;
typedef struct
{
/* 12-bit AM2901 internals */
UINT16 ram[16];
UINT16 q;
UINT16 f;
UINT16 y;
UINT32 cflag;
UINT32 vflag;
UINT8 pc[2]; /* Two program counters; one for FG, other for BG */
UINT16 seqcnt; /* 12-bit */
UINT16 clatch; /* LS374 at 9E and 1-bit FF */
UINT8 zlatch; /* LS374 at 4H */
UINT16 xcnt;
UINT16 ycnt;
UINT8 sreg;
UINT16 fadlatch;
UINT16 badlatch;
UINT16 sramdlatch;
UINT8 fglatch;
UINT8 bglatch;
UINT8 gt0reg;
UINT8 fdxreg;
UINT32 field;
UINT32 clkcnt;
/* RAM */
UINT16 *sram;
UINT8 *ptr_ram;
UINT32 *e_stack;
UINT32 *o_stack;
} cquestlin_state;
/***************************************************************************
PUBLIC GLOBAL VARIABLES
***************************************************************************/
static int cquestsnd_icount;
static int cquestrot_icount;
static int cquestlin_icount;
/***************************************************************************
PRIVATE GLOBAL VARIABLES
***************************************************************************/
static cquestsnd_state cquestsnd;
static cquestrot_state cquestrot;
static cquestlin_state cquestlin;
/***************************************************************************
MEMORY ACCESSORS FOR 68000
***************************************************************************/
WRITE16_HANDLER( write_sndram )
{
COMBINE_DATA(&cquestsnd.sram[offset]);
}
READ16_HANDLER( read_sndram )
{
return cquestsnd.sram[offset];
}
WRITE16_HANDLER( write_rotram )
{
COMBINE_DATA(&cquestrot.dram[offset]);
}
READ16_HANDLER( read_rotram )
{
return cquestrot.dram[offset];
}
/***************************************************************************
INLINE FUNCTIONS
***************************************************************************/
/***************************************************************************
CONTEXT SWITCHING
***************************************************************************/
static CPU_GET_CONTEXT( cquestsnd )
{
/* Copy the context */
if (dst)
*(cquestsnd_state *)dst = cquestsnd;
}
static CPU_SET_CONTEXT( cquestsnd )
{
/* Copy the context */
if (src)
cquestsnd = *(cquestsnd_state *)src;
}
static CPU_GET_CONTEXT( cquestrot )
{
/* Copy the context */
if (dst)
*(cquestrot_state *)dst = cquestrot;
}
static CPU_SET_CONTEXT( cquestrot )
{
/* Copy the context */
if (src)
cquestrot = *(cquestrot_state *)src;
}
static CPU_GET_CONTEXT( cquestlin )
{
/* Copy the context */
if (dst)
*(cquestlin_state *)dst = cquestlin;
}
static CPU_SET_CONTEXT( cquestlin )
{
/* Copy the context */
if (src)
cquestlin = *(cquestlin_state *)src;
}
/***************************************************************************
SOUND INITIALIZATION AND SHUTDOWN
***************************************************************************/
static STATE_POSTLOAD( cquestsnd_postload )
{
}
static void cquestsnd_state_register(int index, const char *type)
{
state_save_register_item_array(type, index, cquestsnd.ram);
state_save_register_item(type, index, cquestsnd.q);
state_save_register_item(type, index, cquestsnd.f);
state_save_register_item(type, index, cquestsnd.y);
state_save_register_item(type, index, cquestsnd.cflag);
state_save_register_item(type, index, cquestsnd.vflag);
state_save_register_item(type, index, cquestsnd.pc);
state_save_register_item(type, index, cquestsnd.platch);
state_save_register_item(type, index, cquestsnd.rtnlatch);
state_save_register_item(type, index, cquestsnd.adrcntr);
state_save_register_item(type, index, cquestsnd.adrlatch);
state_save_register_item(type, index, cquestsnd.dinlatch);
state_save_register_item(type, index, cquestsnd.ramwlatch);
state_save_register_item(type, index, cquestsnd.prev_ipram);
state_save_register_item(type, index, cquestsnd.prev_ipwrt);
state_save_register_postload(Machine, cquestsnd_postload, NULL);
}
static CPU_INIT( cquestsnd )
{
cubeqst_snd_config* _config = (cubeqst_snd_config*)device->static_config;
memset(&cquestsnd, 0, sizeof(cquestsnd));
cquestsnd.dac_w = _config->dac_w;
cquestsnd.sound_data = (UINT16*)memory_region(Machine, _config->sound_data_region);
/* Allocate RAM shared with 68000 */
cquestsnd.sram = malloc(4096);
cquestsnd_state_register(index, "cquestsnd");
}
static CPU_RESET( cquestsnd )
{
cquestsnd.pc = 0;
}
static CPU_EXIT( cquestsnd )
{
free(cquestsnd.sram);
}
/***************************************************************************
ROTATE INITIALIZATION AND SHUTDOWN
***************************************************************************/
static STATE_POSTLOAD( cquestrot_postload )
{
}
static void cquestrot_state_register(int index, const char *type)
{
state_save_register_item_array(type, index, cquestrot.ram);
state_save_register_item(type, index, cquestrot.q);
state_save_register_item(type, index, cquestrot.f);
state_save_register_item(type, index, cquestrot.y);
state_save_register_item(type, index, cquestrot.cflag);
state_save_register_item(type, index, cquestrot.vflag);
state_save_register_item(type, index, cquestrot.pc);
state_save_register_item(type, index, cquestrot.seqcnt);
state_save_register_item(type, index, cquestrot.dsrclatch);
state_save_register_item(type, index, cquestrot.rsrclatch);
state_save_register_item(type, index, cquestrot.dynaddr);
state_save_register_item(type, index, cquestrot.dyndata);
state_save_register_item(type, index, cquestrot.yrlatch);
state_save_register_item(type, index, cquestrot.ydlatch);
state_save_register_item(type, index, cquestrot.dinlatch);
state_save_register_item(type, index, cquestrot.divreg);
state_save_register_item(type, index, cquestrot.linedata);
state_save_register_item(type, index, cquestrot.lineaddr);
state_save_register_item(type, index, cquestrot.prev_dred);
state_save_register_item(type, index, cquestrot.prev_dwrt);
state_save_register_item(type, index, cquestrot.wc);
state_save_register_item_pointer(type, index, cquestrot.dram, 16384);
state_save_register_item_pointer(type, index, cquestrot.sram, 2048);
state_save_register_postload(Machine, cquestrot_postload, NULL);
}
static CPU_INIT( cquestrot )
{
memset(&cquestrot, 0, sizeof(cquestrot));
/* Allocate RAM */
cquestrot.dram = malloc(16384 * sizeof(UINT16)); /* Shared with 68000 */
cquestrot.sram = malloc(2048 * sizeof(UINT16)); /* Private */
cquestrot_state_register(index, "cquestrot");
}
static CPU_RESET( cquestrot )
{
cquestrot.pc = 0;
cquestrot.wc = 0;
cquestrot.prev_dred = 1;
cquestrot.prev_dwrt = 1;
}
static CPU_EXIT( cquestrot )
{
free(cquestrot.dram);
free(cquestrot.sram);
}
/***************************************************************************
LINE DRAWER INITIALIZATION AND SHUTDOWN
***************************************************************************/
#define FOREGROUND 0
#define BACKGROUND 1
#define ODD_FIELD 0
#define EVEN_FIELD 1
static STATE_POSTLOAD( cquestlin_postload )
{
}
static void cquestlin_state_register(int index, const char *type)
{
state_save_register_item_array(type, index, cquestlin.ram);
state_save_register_item(type, index, cquestlin.q);
state_save_register_item(type, index, cquestlin.f);
state_save_register_item(type, index, cquestlin.y);
state_save_register_item(type, index, cquestlin.cflag);
state_save_register_item(type, index, cquestlin.vflag);
state_save_register_item(type, index, cquestlin.pc[0]);
state_save_register_item(type, index, cquestlin.pc[1]);
state_save_register_item(type, index, cquestlin.seqcnt);
state_save_register_item(type, index, cquestlin.clatch);
state_save_register_item(type, index, cquestlin.zlatch);
state_save_register_item(type, index, cquestlin.xcnt);
state_save_register_item(type, index, cquestlin.ycnt);
state_save_register_item(type, index, cquestlin.sreg);
state_save_register_item(type, index, cquestlin.fadlatch);
state_save_register_item(type, index, cquestlin.badlatch);
state_save_register_item(type, index, cquestlin.sramdlatch);
state_save_register_item(type, index, cquestlin.fglatch);
state_save_register_item(type, index, cquestlin.bglatch);
state_save_register_item(type, index, cquestlin.gt0reg);
state_save_register_item(type, index, cquestlin.fdxreg);
state_save_register_item(type, index, cquestlin.field);
state_save_register_item(type, index, cquestlin.clkcnt);
state_save_register_item_pointer(type, index, cquestlin.sram, 4096);
state_save_register_item_pointer(type, index, cquestlin.ptr_ram, 1024);
state_save_register_item_pointer(type, index, cquestlin.e_stack, 32768);
state_save_register_item_pointer(type, index, cquestlin.o_stack, 32768);
state_save_register_postload(Machine, cquestlin_postload, NULL);
}
static CPU_INIT( cquestlin )
{
memset(&cquestlin, 0, sizeof(cquestlin));
/* Allocate RAM */
cquestlin.sram = malloc(4096 * sizeof(UINT16)); /* Shared with rotate CPU */
cquestlin.ptr_ram = malloc(1024); /* Pointer RAM */
cquestlin.e_stack = malloc(32768 * sizeof(UINT32)); /* Stack DRAM: 32kx20 */
cquestlin.o_stack = malloc(32768 * sizeof(UINT32)); /* Stack DRAM: 32kx20 */
cquestlin_state_register(index, "cquestlin");
}
static CPU_RESET( cquestlin )
{
cquestlin.clkcnt = 0;
cquestlin.pc[FOREGROUND] = 0;
cquestlin.pc[BACKGROUND] = 0x80;
}
static CPU_EXIT( cquestlin )
{
free(cquestlin.sram);
free(cquestlin.e_stack);
free(cquestlin.o_stack);
free(cquestlin.ptr_ram);
}
/***************************************************************************
SOUND CORE EXECUTION LOOP
***************************************************************************/
#define SND_PC (cquestsnd.pc)
#define SND_DATA_IN (_ramen ? cquestsnd.sound_data[cquestsnd.platch] : cquestsnd.dinlatch)
enum snd_latch_type
{
PLTCH = 0,
DAC = 1,
ADLATCH = 2,
};
static int do_sndjmp(int jmp)
{
switch (jmp)
{
/* JUMP */ case 0: return 1;
/* MSB */ case 2: return cquestsnd.f & 0x8000 ? 0 : 1;
/* !MSB */ case 3: return cquestsnd.f & 0x8000 ? 1 : 0;
/* ZERO */ case 5: return cquestsnd.f == 0 ? 0 : 1;
/* OVR */ case 6: return cquestsnd.vflag ? 0 : 1;
/* LOOP */ case 7: return cquestsnd.adrcntr & 0x80 ? 0: 1;
}
return 0;
}
static CPU_EXECUTE( cquestsnd )
{
int calldebugger = ((Machine->debug_flags & DEBUG_FLAG_ENABLED) != 0);
cquestsnd_icount = cycles;
/* Core execution loop */
do
{
/* Decode the instruction */
UINT64 inst = cpu_readop64(SND_PC << 3);
UINT32 inslow = inst & 0xffffffff;
UINT32 inshig = inst >> 32;
int t = (inshig >> 24) & 0xff;
int b = (inshig >> 20) & 0xf;
int a = (inshig >> 16) & 0xf;
int ci = (inshig >> 15) & 1;
int i5_3 = (inshig >> 12) & 7;
int _ramen = (inshig >> 11) & 1;
int i2_0 = (inshig >> 8) & 7;
int rtnltch = (inshig >> 7) & 1;
int jmp = (inshig >> 4) & 7;
int inca = (inshig >> 3) & 1;
int i8_6 = (inshig >> 0) & 7;
int _ipram = (inslow >> 31) & 1;
int _ipwrt = (inslow >> 30) & 1;
int latch = (inslow >> 28) & 3;
int rtn = (inslow >> 27) & 1;
int _rin = (inslow >> 26) & 1;
if (calldebugger)
debugger_instruction_hook(Machine, cquestsnd.pc);
/* Don't think this matters, but just in case */
if (rtn)
t = cquestsnd.rtnlatch;
/* Handle the AM2901 ALU instruction */
{
UINT16 r = 0;
UINT16 s = 0;
UINT32 res = 0;
UINT32 cflag = 0;
UINT32 vflag = 0;
/* Determine the ALU sources */
switch (i2_0)
{
case AQ: r = cquestsnd.ram[a]; s = cquestsnd.q; break;
case AB: r = cquestsnd.ram[a]; s = cquestsnd.ram[b]; break;
case ZQ: r = 0; s = cquestsnd.q; break;
case ZB: r = 0; s = cquestsnd.ram[b]; break;
case ZA: r = 0; s = cquestsnd.ram[a]; break;
case DA: r = SND_DATA_IN; s = cquestsnd.ram[a]; break;
case DQ: r = SND_DATA_IN; s = cquestsnd.q; break;
case DZ: r = SND_DATA_IN; s = 0; break;
}
/* Perform the ALU operation */
switch (i5_3)
{
case ADD:
res = r + s + ci;
cflag = (res >> 16) & 1;
vflag = (((r & 0x7fff) + (s & 0x7fff) + ci) >> 15) ^ cflag;
break;
case SUBR:
res = ~r + s + ci;
cflag = (res >> 16) & 1;
vflag = (((s & 0x7fff) + (~r & 0x7fff) + ci) >> 15) ^ cflag;
break;
case SUBS:
res = r + ~s + ci;
cflag = (res >> 16) & 1;
vflag = (((r & 0x7fff) + (~s & 0x7fff) + ci) >> 15) ^ cflag;
break;
case OR:
res = r | s;
break;
case AND:
res = r & s;
break;
case NOTRS:
res = ~r & s;
break;
case EXOR:
res = r ^ s;
break;
case EXNOR:
res = ~(r ^ s);
break;
}
cquestsnd.f = res;
cquestsnd.cflag = cflag;
cquestsnd.vflag = vflag;
switch (i8_6)
{
case QREG:
cquestsnd.q = cquestsnd.f;
cquestsnd.y = cquestsnd.f;
break;
case NOP:
cquestsnd.y = cquestsnd.f;
break;
case RAMA:
cquestsnd.y = cquestsnd.ram[a];
cquestsnd.ram[b] = cquestsnd.f;
break;
case RAMF:
cquestsnd.ram[b] = cquestsnd.f;
cquestsnd.y = cquestsnd.f;
break;
case RAMQD:
{
UINT16 qin;
cquestsnd.ram[b] = (_rin ? 0 : 0x8000) | (cquestsnd.f >> 1);
cquestsnd.q >>= 1;
cquestsnd.y = cquestsnd.f;
/* When right shifting Q, we need to OR in a value */
qin = (((cquestsnd.y >> 15) ^ (cquestsnd.y >> 1)) & 1) ? 0 : 0x8000;
cquestsnd.q |= qin;
break;
}
case RAMD:
cquestsnd.ram[b] = (_rin ? 0 : 0x8000) | (cquestsnd.f >> 1);
cquestsnd.y = cquestsnd.f;
break;
case RAMQU:
cquestsnd.ram[b] = (cquestsnd.f << 1) | (_rin ? 0 : 0x0001);
cquestsnd.q <<= 1;
cquestsnd.y = cquestsnd.f;
break;
case RAMU:
cquestsnd.ram[b] = (cquestsnd.f << 1) | (_rin ? 0 : 0x0001);
cquestsnd.y = cquestsnd.f;
break;
}
}
/* Now handle any SRAM accesses from the previous cycle */
if (!cquestsnd.prev_ipram)
{
UINT16 addr = cquestsnd.adrlatch | (cquestsnd.adrcntr & 0x7f);
if (!cquestsnd.prev_ipwrt)
cquestsnd.sram[addr] = cquestsnd.ramwlatch;
else
cquestsnd.dinlatch = cquestsnd.sram[addr];
}
/* Handle latches */
if (latch == PLTCH)
{
cquestsnd.platch = ((t & 3) << 9) | ((cquestsnd.y >> 6) & 0x1ff);
}
else if (latch == DAC)
{
cquestsnd.dac_w((cquestsnd.y & 0xfff0) | ((cquestsnd.adrcntr >> 3) & 0xf));
}
else if (latch == ADLATCH)
{
/* Load the SRAM address counter - this value is instantly loaded */
cquestsnd.adrcntr = cquestsnd.y & 0x7f;
/* Also load the SRAM address latch */
cquestsnd.adrlatch = cquestsnd.y & 0x780;
}
/* Check for jump/return */
if ( do_sndjmp(jmp) )
cquestsnd.pc = rtn ? cquestsnd.rtnlatch : t;
else
cquestsnd.pc++;
/* Load the return latch? (Obviously a load and a ret in the same cycle are invalid) */
if (rtnltch)
cquestsnd.rtnlatch = t;
/* Only increment the sound counter if not loading */
if (inca && latch != ADLATCH)
cquestsnd.adrcntr++;
/* Latch data for a RAM write (do actual write on the next cycle) */
if (!_ipwrt)
cquestsnd.ramwlatch = cquestsnd.y;
/* Save level sensitive bits */
cquestsnd.prev_ipram = _ipram;
cquestsnd.prev_ipwrt = _ipwrt;
cquestsnd_icount--;
} while (cquestsnd_icount > 0);
return cycles - cquestsnd_icount;
}
/***************************************************************************
SOUND DISASSEMBLY HOOK
***************************************************************************/
static CPU_DISASSEMBLE( cquestsnd )
{
static const char *const jmps[] =
{
"JUMP ",
" ",
"JMSB ",
"JNMSB",
" ",
"JZERO",
"JOVR ",
"JLOOP",
};
static const char *const latches[] =
{
"PLTCH ",
"DAC ",
"ADLATCH",
" ",
};
UINT64 inst = BIG_ENDIANIZE_INT64(*(UINT64 *)oprom);
UINT32 inslow = inst & 0xffffffff;
UINT32 inshig = inst >> 32;
int t = (inshig >> 24) & 0xff;
int b = (inshig >> 20) & 0xf;
int a = (inshig >> 16) & 0xf;
int ci = (inshig >> 15) & 1;
int i5_3 = (inshig >> 12) & 7;
int _ramen = (inshig >> 11) & 1;
int i2_0 = (inshig >> 8) & 7;
int rtnltch = (inshig >> 7) & 1;
int jmp = (inshig >> 4) & 7;
int inca = (inshig >> 3) & 1;
int i8_6 = (inshig >> 0) & 7;
int _ipram = (inslow >> 31) & 1;
int _ipwrt = (inslow >> 30) & 1;
int latch = (inslow >> 28) & 3;
int rtn = (inslow >> 27) & 1;
int _rin = (inslow >> 26) & 1;
sprintf(buffer, "%s %s %s %x,%x,%c %.2x %s %s %.2x %s %s %s %c %c %c\n",
ins[i5_3],
src[i2_0],
dst[i8_6],
a,
b,
ci ? 'C' : ' ',
_rin,
jmps[jmp],
rtn ? "RET" : " ",
t,
latches[latch],
rtnltch ? "RTLATCH" : " ",
_ramen ? "PROM" : "RAM ",
_ipram ? ' ' : 'R',
_ipwrt ? ' ' : 'W',
inca ? 'I' : ' ');
return 1 | DASMFLAG_SUPPORTED;
}
/***************************************************************************
ROTATE CORE EXECUTION LOOP
***************************************************************************/
#define ROT_PC (cquestrot.pc & 0x1ff)
enum rot_spf
{
SPF_UNUSED0 = 0,
SPF_UNUSED1 = 1,
SPF_OP = 2,
SPF_RET = 3,
SPF_SQLTCH = 4,
SPF_SWRT = 5,
SPF_DIV = 6,
SPF_MULT = 7,
SPF_DRED = 8,
SPF_DWRT = 9,
};
enum rot_yout
{
YOUT_UNUSED0 = 0,
YOUT_UNUSED1 = 1,
YOUT_Y2LDA = 2,
YOUT_Y2LDD = 3,
YOUT_Y2DAD = 4,
YOUT_Y2DYN = 5,
YOUT_Y2R = 6,
YOUT_Y2D = 7,
};
/* Sync is asserted for the duration of every fourth cycle */
/* The Dynamic RAM latch clocks in a value at the end of this cycle */
/* So CPU waits for sync before reading from DRAM */
INLINE int do_rotjmp(int jmp)
{
int ret = 0;
switch (jmp & 7)
{
/* */ case 0: ret = 0; break;
/* SEQ */ case 1: ret = (cquestrot.seqcnt == 0xf); break;
/* CAROUT */ case 2: ret = cquestrot.cflag; break;
/* SYNC */ case 3: ret = !(cquestrot.clkcnt & 0x3); break;
/* LDWAIT */ case 4: ret = 0; break;
/* MSB */ case 5: ret = BIT(cquestrot.f, 15); break;
/* >=1 */ case 6: ret = (!_BIT(cquestrot.f, 15) && !(cquestrot.f == 0)); break;
/* ZERO */ case 7: ret = (cquestrot.f == 0); break;
}
return !(!ret ^ BIT(jmp, 3));
}
#define ROT_SRAM_ADDRESS ((cquestrot.dsrclatch & 2) ? cquestrot.yrlatch : (cquestrot.rsrclatch | 0x700))
static CPU_EXECUTE( cquestrot )
{
int calldebugger = ((Machine->debug_flags & DEBUG_FLAG_ENABLED) != 0);
cquestrot_icount = cycles;
/* Core execution loop */
do
{
/* Decode the instruction */
UINT64 inst = cpu_readop64(ROT_PC << 3);
UINT32 inslow = inst & 0xffffffff;
UINT32 inshig = inst >> 32;
int t = (inshig >> 20) & 0xfff;
int jmp = (inshig >> 16) & 0xf;
int spf = (inshig >> 12) & 0xf;
int rsrc = (inshig >> 11) & 0x1;
int yout = (inshig >> 8) & 0x7;
int sel = (inshig >> 6) & 0x3;
int dsrc = (inshig >> 4) & 0x3;
int b = (inshig >> 0) & 0xf;
int a = (inslow >> 28) & 0xf;
int i8_6 = (inslow >> 24) & 0x7;
int ci = (inslow >> 23) & 0x1;
int i5_3 = (inslow >> 20) & 0x7;
int _sex = (inslow >> 19) & 0x1;
int i2_0 = (inslow >> 16) & 0x7;
int dsrclatch;
UINT16 data_in = 0xffff;
if (calldebugger)
debugger_instruction_hook(Machine, ROT_PC);
/* Handle DRAM accesses - I ought to check this... */
if (!(cquestrot.clkcnt & 3))
{
if (cquestrot.wc)
{
cquestrot.wc = 0;
cquestrot.dram[cquestrot.dynaddr & 0x3fff] = cquestrot.dyndata;
}
if (cquestrot.rc)
{
cquestrot.rc = 0;
cquestrot.dinlatch = cquestrot.dram[cquestrot.dynaddr & 0x3fff];
}
}
/* Flag pending DRAM accesses */
if (!cquestrot.prev_dwrt)
cquestrot.wc = 1;
else if (!cquestrot.prev_dred)
cquestrot.rc = 1;
/* What's on the D-Bus? */
if (~cquestrot.dsrclatch & 0x10)
data_in = cquestrot.dinlatch;
else if (~cquestrot.dsrclatch & 0x20)
data_in = cquestrot.sram[ROT_SRAM_ADDRESS];
else if (~cquestrot.dsrclatch & 0x40)
data_in = cquestrot.ydlatch;
else if (~cquestrot.dsrclatch & 0x80)
data_in = t & 0xfff;
/* What's on the T-Bus? */
if ((spf == SPF_RET) && (cquestrot.dsrclatch & 0x80))
t = data_in;
else if (spf == SPF_OP)
t = (t & ~0xf) | (data_in >> 12);
if (~cquestrot.dsrclatch & 1)
cquestrot.sram[ROT_SRAM_ADDRESS] = data_in;
/* Sign extend ALU input? */
if (!_sex)
data_in = (data_in & ~0xf000) | ((data_in & 0x800) ? 0xf000 : 0);
/* No do the ALU operation */
{
UINT16 r = 0;
UINT16 s = 0;
UINT32 res = 0;
UINT32 cflag = 0;
UINT32 vflag = 0;
/* First, determine correct I1 bit */
if ((spf == SPF_MULT) && !_BIT(cquestrot.q, 0))
i2_0 |= 2;
/* Determine the ALU sources */
switch (i2_0)
{
case 0: r = cquestrot.ram[a]; s = cquestrot.q; break;
case 1: r = cquestrot.ram[a]; s = cquestrot.ram[b]; break;
case 2: r = 0; s = cquestrot.q; break;
case 3: r = 0; s = cquestrot.ram[b]; break;
case 4: r = 0; s = cquestrot.ram[a]; break;
case 5: r = data_in; s = cquestrot.ram[a]; break;
case 6: r = data_in; s = cquestrot.q; break;
case 7: r = data_in; s = 0; break;
}
/* Next, determine the I3 and carry bits */
if ((spf == SPF_DIV) && cquestrot.divreg)
{
i5_3 |= 1;
ci = 1;
}
/* Perform the ALU operation */
switch (i5_3)
{
case ADD:
res = r + s + ci;
cflag = (res >> 16) & 1;
vflag = (((r & 0x7fff) + (s & 0x7fff) + ci) >> 15) ^ cflag;
break;
case SUBR:
res = ~r + s + ci;
cflag = (res >> 16) & 1;
vflag = (((s & 0x7fff) + (~r & 0x7fff) + ci) >> 15) ^ cflag;
break;
case SUBS:
res = r + ~s + ci;
cflag = (res >> 16) & 1;
vflag = (((r & 0x7fff) + (~s & 0x7fff) + ci) >> 15) ^ cflag;
break;
case OR:
res = r | s;
break;
case AND:
res = r & s;
break;
case NOTRS:
res = ~r & s;
break;
case EXOR:
res = r ^ s;
break;
case EXNOR:
res = ~(r ^ s);
break;
}
cquestrot.f = res;
cquestrot.cflag = cflag;
cquestrot.vflag = vflag;
switch (i8_6)
{
case QREG:
cquestrot.q = cquestrot.f;
cquestrot.y = cquestrot.f;
break;
case NOP:
cquestrot.y = cquestrot.f;
break;
case RAMA:
cquestrot.y = cquestrot.ram[a];
cquestrot.ram[b] = cquestrot.f;
break;
case RAMF:
cquestrot.ram[b] = cquestrot.f;
cquestrot.y = cquestrot.f;
break;
case RAMQD:
{
UINT16 q0 = cquestrot.q & 1;
UINT16 r0 = cquestrot.f & 1;
UINT16 q15 = 0;
UINT16 r15 = 0;
/* Determine Q15 and RAM15 */
switch (sel)
{
case 0: q15 = r15 = 0;
break;
case 1: q15 = r15 = 0x8000;
break;
case 2: q15 = q0 << 15;
r15 = r0 << 15;
break;
case 3: q15 = r0 << 15;
r15 = (cquestrot.vflag ^ BIT(cquestrot.f, 15)) << 15;
break;
}
cquestrot.ram[b] = r15 | (cquestrot.f >> 1);
cquestrot.q = q15 | (cquestrot.q >> 1);
cquestrot.y = cquestrot.f;
break;
}
case RAMD:
{
UINT16 r0 = cquestrot.f & 1;
UINT16 r15 = 0;
switch (sel)
{
case 0: r15 = 0; break;
case 1: r15 = 0x8000; break;
case 2: r15 = r0 << 15; break;
case 3:
r15 = (cquestrot.vflag ^ BIT(cquestrot.f, 15)) << 15;
break;
}
cquestrot.ram[b] = r15 | (cquestrot.f >> 1);
cquestrot.y = cquestrot.f;
break;
}
case RAMQU:
{
UINT16 q15 = BIT(cquestrot.q, 15);
UINT16 r15 = BIT(cquestrot.f, 15);
UINT16 q0 = 0;
UINT16 r0 = 0;
switch (sel)
{
case 0: q0 = 0; r0 = 0; break;
case 1: q0 = 1; r0 = 1; break;
case 2: q0 = q15; r0 = r15; break;
case 3:
{
q0 = (spf == SPF_DIV) && !BIT(cquestrot.f, 15);
r0 = q15;
break;
}
}
cquestrot.ram[b] = (cquestrot.f << 1) | r0;
cquestrot.q = (cquestrot.q << 1) | q0;
cquestrot.y = cquestrot.f;
break;
}
case RAMU:
{
UINT16 q15 = BIT(cquestrot.q, 15);
UINT16 r15 = BIT(cquestrot.f, 15);
UINT16 r0 = 0;
switch (sel)
{
case 0: r0 = 0; break;
case 1: r0 = 1; break;
case 2: r0 = r15; break;
case 3: r0 = q15; break;
}
cquestrot.ram[b] = (cquestrot.f << 1) | r0;
cquestrot.y = cquestrot.f;
break;
}
}
}
/* Check for jump */
if ( do_rotjmp(jmp) )
cquestrot.pc = t;
else
cquestrot.pc = (cquestrot.pc + 1) & 0xfff;
/* Rising edge; update the sequence counter */
if (spf == SPF_SQLTCH)
cquestrot.seqcnt = t & 0xf;
else if ( (spf == SPF_MULT) || (spf == SPF_DIV) )
cquestrot.seqcnt = (cquestrot.seqcnt + 1) & 0xf;
/* Rising edge; write data source reg */
dsrclatch =
(~(0x10 << dsrc) & 0xf0)
| (rsrc ? 0x04 : 0x02)
| !(spf == SPF_SWRT);
/* R-latch is written on rising edge of dsrclatch bit 2 */
if (!_BIT(cquestrot.dsrclatch, 2) && _BIT(dsrclatch, 2))
cquestrot.rsrclatch = t & 0xff;
cquestrot.dsrclatch = dsrclatch;
/* Handle latching on rising edge */
switch (yout)
{
case YOUT_Y2LDA:
{
cquestrot.lineaddr = cquestrot.y & 0xfff;
break;
}
case YOUT_Y2LDD:
{
cquestrot.linedata = ((t & 0xf) << 12) | (cquestrot.y & 0xfff);
cquestlin.sram[cquestrot.lineaddr] = cquestrot.linedata;
break;
}
case YOUT_Y2DAD: cquestrot.dynaddr = cquestrot.y & 0x3fff; break;
case YOUT_Y2DYN: cquestrot.dyndata = cquestrot.y & 0xffff; break;
case YOUT_Y2R: cquestrot.yrlatch = cquestrot.y & 0x7ff; break;
case YOUT_Y2D: cquestrot.ydlatch = cquestrot.y; break;
}
/* Clock in the divide register */
cquestrot.divreg = (spf == SPF_DIV) && !_BIT(cquestrot.f, 15);
/* DRAM accessing */
cquestrot.prev_dred = !(spf == SPF_DRED);
cquestrot.prev_dwrt = !(spf == SPF_DWRT);
cquestrot.clkcnt++;
cquestrot_icount--;
} while (cquestrot_icount > 0);
return cycles - cquestrot_icount;
}
/***************************************************************************
ROTATE DISASSEMBLY HOOK
***************************************************************************/
static CPU_DISASSEMBLE( cquestrot )
{
static const char *const jmps[] =
{
" ",
"JSEQ ",
"JC ",
"JSYNC ",
"JLDWAIT",
"JMSB ",
"JGEONE ",
"JZERO ",
"JUMP ",
"JNSEQ ",
"JNC ",
"JNSYNC ",
"JNLDWAI",
"JNMSB ",
"JLTONE ",
"JNZERO ",
};
static const char *const youts[] =
{
" ",
" ",
"Y2LDA",
"Y2LDD",
"Y2DAD",
"Y2DIN",
"Y2R ",
"Y2D ",
};
static const char *const spfs[] =
{
" ",
" ",
"OP ",
"RET ",
"SQLTCH",
"SWRT ",
"DIV ",
"MULT ",
"DRED ",
"DWRT ",
"??? ",
"??? ",
"??? ",
"??? ",
"??? ",
"??? "
};
UINT64 inst = BIG_ENDIANIZE_INT64(*(UINT64 *)oprom);
UINT32 inslow = inst & 0xffffffff;
UINT32 inshig = inst >> 32;
int t = (inshig >> 20) & 0xfff;
int jmp = (inshig >> 16) & 0xf;
int spf = (inshig >> 12) & 0xf;
// int rsrc = (inshig >> 11) & 0x1;
int yout = (inshig >> 8) & 0x7;
int sel = (inshig >> 6) & 0x3;
// int dsrc = (inshig >> 4) & 0x3;
int b = (inshig >> 0) & 0xf;
int a = (inslow >> 28) & 0xf;
int i8_6 = (inslow >> 24) & 0x7;
int ci = (inslow >> 23) & 0x1;
int i5_3 = (inslow >> 20) & 0x7;
// int _sex = (inslow >> 19) & 0x1;
int i2_0 = (inslow >> 16) & 0x7;
sprintf(buffer, "%s %s,%s %x,%x,%c %d %s %s %s %.2x\n",
ins[i5_3],
src[i2_0],
dst[i8_6],
a,
b,
ci ? 'C' : ' ',
sel,
jmps[jmp],
youts[yout],
spfs[spf],
t);
return 1 | DASMFLAG_SUPPORTED;
}
/***************************************************************************
LINE DRAWER CORE EXECUTION LOOP
***************************************************************************/
#define VISIBLE_FIELD !cquestlin.field
enum line_spf
{
LSPF_UNUSUED = 0,
LSPF_FSTOP = 1,
LSPF_SREG = 2,
LSPF_FSTRT = 3,
LSPF_PWRT = 4,
LSPF_MULT = 5,
LSPF_LSTOP = 6,
LSPF_BRES = 7,
};
enum line_latch
{
LLATCH_UNUSED = 0,
LLATCH_SEQLATCH = 1,
LLATCH_XLATCH = 2,
LLATCH_YLATCH = 3,
LLATCH_BADLATCH = 4,
LLATCH_FADLATCH = 5,
LLATCH_CLATCH = 6,
LLATCH_ZLATCH = 7,
};
enum sreg_bits
{
SREG_E0 = 0,
SREG_DX_DY = 1,
SREG_DY = 2,
SREG_DX = 3,
SREG_LE0 = 4,
SREG_LDX_DY = 5,
SREG_LDY = 6,
SREG_LDX = 7,
};
INLINE int do_linjmp(int jmp)
{
int ret = 0;
switch (jmp & 7)
{
/* */ case 0: ret = 0; break;
/* MSB */ case 1: ret = BIT(cquestlin.f, 11); break;
/* SEQ */ case 2: ret = (cquestlin.seqcnt == 0xfff); break;
/* >0 */ case 3: ret = !(cquestlin.f == 0) && !_BIT(cquestlin.f, 11); break;
/* CAROUT */ case 4: ret = (cquestlin.cflag); break;
/* ZERO */ case 5: ret = (cquestlin.f == 0); break;
}
return !(!ret ^ BIT(jmp, 3));
}
void cubeqcpu_swap_line_banks(void)
{
cquestlin.field = cquestlin.field ^ 1;
}
void clear_stack(void)
{
memset(&cquestlin.ptr_ram[cquestlin.field * 256], 0, 256);
}
UINT8 get_ptr_ram_val(int i)
{
return cquestlin.ptr_ram[(VISIBLE_FIELD * 256) + i];
}
UINT32* get_stack_ram(void)
{
if (VISIBLE_FIELD == ODD_FIELD)
return cquestlin.o_stack;
else
return cquestlin.e_stack;
}
static CPU_EXECUTE( cquestlin )
{
#define LINE_PC ((cquestlin.pc[prog] & 0x7f) | ((prog == BACKGROUND) ? 0x80 : 0))
int calldebugger = ((Machine->debug_flags & DEBUG_FLAG_ENABLED) != 0);
UINT32 *stack_ram;
UINT8 *ptr_ram;
/* Check the field and set the stack/pointer RAM pointers appropriately */
if (cquestlin.field == ODD_FIELD)
{
stack_ram = cquestlin.o_stack;
ptr_ram = &cquestlin.ptr_ram[0];
}
else
{
stack_ram = cquestlin.e_stack;
ptr_ram = &cquestlin.ptr_ram[0x100];
}
cquestlin_icount = cycles;
/* Core execution loop */
do
{
/* Are we executing the foreground or backgroud program? */
int prog = (cquestlin.clkcnt & 3) ? BACKGROUND : FOREGROUND;
UINT64 inst = cpu_readop64(LINE_PC << 3);
UINT32 inslow = inst & 0xffffffff;
UINT32 inshig = inst >> 32;
int t = (inshig >> 24) & 0xff;
int jmp = (inshig >> 20) & 0xf;
int latch = (inshig >> 16) & 0x7;
int op = (inshig >> 15) & 0x1;
int spf = (inshig >> 12) & 0x7;
int b = (inshig >> 8) & 0xf;
int a = (inshig >> 4) & 0xf;
int i8_6 = (inshig >> 0) & 0x7;
int ci = (inslow >> 31) & 0x1;
int i5_3 = (inslow >> 28) & 0x7;
int _pbcs = (inslow >> 27) & 0x1;
int i2_0 = (inslow >> 24) & 0x7;
UINT16 data_in = 0;
if (calldebugger)
debugger_instruction_hook(Machine, cquestlin.pc[prog]);
/* Handle accesses to and from shared SRAM */
if (prog == FOREGROUND)
{
if (!_BIT(cquestlin.fglatch, 5))
data_in = cquestlin.sram[cquestlin.fadlatch];
else
data_in = cquestrot.linedata;
}
else
{
if (!_BIT(cquestlin.bglatch, 4))
cquestlin.sram[cquestlin.badlatch] = cquestlin.sramdlatch;
else if (_BIT(cquestlin.bglatch, 2))
data_in = cquestlin.sram[cquestlin.badlatch];
else
data_in = cquestrot.linedata;
}
/* Handle a write to stack RAM (/DOWRT) */
if ((cquestlin.clkcnt & 3) == 1)
{
if (_BIT(cquestlin.fglatch, 4) && (cquestlin.ycnt < 256))
{
/* 20-bit words */
UINT32 data;
UINT16 h = cquestlin.xcnt;
UINT8 v = cquestlin.ycnt & 0xff;
/* Clamp H between 0 and 319 */
if (h >= 320)
h = (h & 0x800) ? 0 : 319;
/* Stack word type depends on STOP/#START bit */
if ( _BIT(cquestlin.fglatch, 3) )
data = (0 << 19) | (h << 8) | cquestlin.zlatch;
else
data = (1 << 19) | ((cquestlin.clatch & 0x100) << 9) | (h << 8) | (cquestlin.clatch & 0xff);
stack_ram[(v << 7) | (ptr_ram[v] & 0x7f)] = data;
/* Also increment the pointer RAM entry. Note that it cannot exceed 128 */
ptr_ram[v] = (ptr_ram[v] + 1) & 0x7f;
}
}
/* Override T3-0? */
if (op)
t = (t & ~0xf) | (data_in >> 12);
/* Determine the correct I1 bit */
if ((spf == LSPF_MULT) && !_BIT(cquestlin.q, 0))
i2_0 |= 2;
/* Determine A0 (BRESA0) */
if ((prog == FOREGROUND) && !_BIT(cquestlin.fglatch, 2))
a |= cquestlin.gt0reg;
/* Now do the ALU operation */
{
UINT16 r = 0;
UINT16 s = 0;
UINT16 res = 0;
UINT32 cflag = 0;
UINT32 vflag = 0;
/* Determine the ALU sources */
switch (i2_0)
{
case 0: r = cquestlin.ram[a]; s = cquestlin.q; break;
case 1: r = cquestlin.ram[a]; s = cquestlin.ram[b]; break;
case 2: r = 0; s = cquestlin.q; break;
case 3: r = 0; s = cquestlin.ram[b]; break;
case 4: r = 0; s = cquestlin.ram[a]; break;
case 5: r = data_in; s = cquestlin.ram[a]; break;
case 6: r = data_in; s = cquestlin.q; break;
case 7: r = data_in; s = 0; break;
}
/* 12-bits */
r &= 0xfff;
s &= 0xfff;
/* Perform the 12-bit ALU operation */
switch (i5_3)
{
case ADD:
res = r + s + ci;
cflag = (res >> 12) & 1;
vflag = (((r & 0x7ff) + (s & 0x7ff) + ci) >> 11) ^ cflag;
break;
case SUBR:
res = (r ^ 0x0FFF) + s + ci;
cflag = (res >> 12) & 1;
vflag = (((s & 0x7ff) + (~r & 0x7ff) + ci) >> 11) ^ cflag;
break;
case SUBS:
res = r + (s ^ 0x0FFF) + ci;
cflag = (res >> 12) & 1;
vflag = (((r & 0x7ff) + (~s & 0x7ff) + ci) >> 11) ^ cflag;
break;
case OR:
res = r | s;
break;
case AND:
res = r & s;
break;
case NOTRS:
res = ~r & s;
break;
case EXOR:
res = r ^ s;
break;
case EXNOR:
res = ~(r ^ s);
break;
}
cquestlin.f = res & 0xfff;
cquestlin.cflag = cflag;
cquestlin.vflag = vflag;
switch (i8_6)
{
case QREG:
cquestlin.q = cquestlin.f;
cquestlin.y = cquestlin.f;
break;
case NOP:
cquestlin.y = cquestlin.f;
break;
case RAMA:
cquestlin.y = cquestlin.ram[a];
cquestlin.ram[b] = cquestlin.f;
break;
case RAMF:
cquestlin.ram[b] = cquestlin.f;
cquestlin.y = cquestlin.f;
break;
case RAMQD:
{
UINT16 r11 = (BIT(cquestlin.f, 11) ^ cquestlin.vflag) ? 0x800 : 0;
UINT16 q11 = (prog == BACKGROUND) ? 0x800 : 0;
cquestlin.ram[b] = r11 | (cquestlin.f >> 1);
cquestlin.q = q11 | (cquestlin.q >> 1);
cquestlin.y = cquestlin.f;
break;
}
case RAMD:
{
UINT16 r11 = (BIT(cquestlin.f, 11) ^ cquestlin.vflag) ? 0x800 : 0;
cquestlin.ram[b] = r11 | (cquestlin.f >> 1);
cquestlin.y = cquestlin.f;
break;
}
case RAMQU:
{
/* Determine shift inputs */
UINT16 r0 = (prog == BACKGROUND);
/* This should never happen - Q0 will be invalid */
cquestlin.ram[b] = (cquestlin.f << 1) | r0;
cquestlin.q = (cquestlin.q << 1) | 0;
cquestlin.y = cquestlin.f;
break;
}
case RAMU:
{
UINT16 r0 = (prog == BACKGROUND);
cquestlin.ram[b] = (cquestlin.f << 1) | r0;
cquestlin.y = cquestlin.f;
break;
}
}
}
/* Adjust program counter */
if ( do_linjmp(jmp) )
cquestlin.pc[prog] = t & 0x7f;
else
cquestlin.pc[prog] = (cquestlin.pc[prog] + 1) & 0x7f;
if (prog == BACKGROUND)
cquestlin.pc[prog] |= 0x80;
else
{
/* Handle events that happen during FG execution */
if (latch == LLATCH_XLATCH)
cquestlin.xcnt = cquestlin.y & 0xfff;
else
{
int _xcet;
int mux_sel = (BIT(cquestlin.sreg, SREG_DX_DY) << 1) | (BIT(cquestlin.sreg, SREG_DX) ^ BIT(cquestlin.sreg, SREG_DY));
if (mux_sel == 0)
_xcet = !(spf == LSPF_BRES);
else if (mux_sel == 1)
_xcet = _BIT(cquestlin.fglatch, 1);
else if (mux_sel == 2)
_xcet = !(cquestlin.gt0reg && (spf == LSPF_BRES));
else
_xcet = _BIT(cquestlin.fglatch, 0);
if (!_xcet)
cquestlin.xcnt = (cquestlin.xcnt + (_BIT(cquestlin.sreg, SREG_DX) ? 1 : -1)) & 0xfff;
}
if (latch == LLATCH_YLATCH)
cquestlin.ycnt = cquestlin.y & 0xfff;
else
{
int _ycet;
int mux_sel = (BIT(cquestlin.sreg, SREG_DX_DY) << 1) | (BIT(cquestlin.sreg, SREG_DX) ^ BIT(cquestlin.sreg, SREG_DY));
if (mux_sel == 0)
_ycet = !(cquestlin.gt0reg && (spf == LSPF_BRES));
else if (mux_sel == 1)
_ycet = _BIT(cquestlin.fglatch, 0);
else if (mux_sel == 2)
_ycet = !(spf == LSPF_BRES);
else
_ycet = _BIT(cquestlin.fglatch, 1);
if (!_ycet)
cquestlin.ycnt = (cquestlin.ycnt + (_BIT(cquestlin.sreg, SREG_DY) ? 1 : -1)) & 0xfff;
}
}
if (latch == LLATCH_CLATCH)
cquestlin.clatch = cquestlin.y & 0x1ff;
else if (latch == LLATCH_ZLATCH)
cquestlin.zlatch = cquestlin.y & 0xff;
else if (latch == LLATCH_FADLATCH)
cquestlin.fadlatch = cquestlin.y & 0xfff;
else if (latch == LLATCH_BADLATCH)
cquestlin.badlatch = cquestlin.y & 0xfff;
/* What about the SRAM dlatch? */
if ( !_BIT(cquestlin.bglatch, 5) )
cquestlin.sramdlatch = ((t & 0xf) << 12) | (cquestlin.y & 0x0fff);
/* BG and FG latches */
if (prog == FOREGROUND)
{
int mux_sel = (!(spf == LSPF_FSTOP) << 1) | !(spf == LSPF_LSTOP);
int dowrt;
int start_stop;
/* Handle the stack write and start/stop mux */
if (mux_sel == 0)
{
dowrt = 0;
start_stop = 0;
}
else if (mux_sel == 1)
{
dowrt = cquestlin.fdxreg ^ BIT(cquestlin.sreg, SREG_DX);
start_stop = cquestlin.fdxreg;
}
else if (mux_sel == 2)
{
dowrt = BIT(cquestlin.sreg, SREG_LDX) ^ BIT(cquestlin.sreg, SREG_DX);
start_stop = BIT(cquestlin.sreg, SREG_DX);
}
else
{
dowrt = (spf == LSPF_BRES) && (_BIT(cquestlin.sreg, SREG_DX_DY) || cquestlin.gt0reg);
start_stop = BIT(cquestlin.sreg, SREG_DY);
}
cquestlin.fglatch =
(!(latch == LLATCH_FADLATCH) << 5)
| (dowrt << 4)
| (start_stop << 3)
| (_pbcs << 2)
| (!(spf == LSPF_BRES) << 1)
| !(cquestlin.gt0reg && (spf == LSPF_BRES));
}
else
{
int _lpwrt = BIT(cquestlin.bglatch, 5);
cquestlin.bglatch =
(!(spf == LSPF_PWRT) << 5)
| (_lpwrt << 4)
| ((!_lpwrt || (!(spf == LSPF_PWRT) && (latch == LLATCH_BADLATCH))) << 2);
}
/* Clock-in another bit into the sign bit shifter? */
if (spf == LSPF_SREG)
{
/* The sign bit is inverted */
cquestlin.sreg = (cquestlin.sreg << 1) | !BIT(cquestlin.f, 11);
/* Also latch the >0 reg */
cquestlin.gt0reg = !(cquestlin.f == 0) && !_BIT(cquestlin.f, 11);
}
else if (spf == LSPF_FSTRT)
{
cquestlin.fdxreg = BIT(cquestlin.sreg, 3);
}
/* Load or increment sequence counter? */
if (latch == LLATCH_SEQLATCH)
{
cquestlin.seqcnt = cquestlin.y & 0xfff;
}
else if (spf == LSPF_BRES)
{
cquestlin.seqcnt = (cquestlin.seqcnt + 1) & 0xfff;
/* Also latch the >0 reg */
cquestlin.gt0reg = !(cquestlin.f == 0) && !_BIT(cquestlin.f, 11);
}
cquestlin_icount--;
cquestlin.clkcnt++;
} while (cquestlin_icount > 0);
return cycles - cquestlin_icount;
}
/***************************************************************************
LINE DRAWER DISASSEMBLY HOOK
***************************************************************************/
static CPU_DISASSEMBLE( cquestlin )
{
static const char *const jmps[] =
{
" ",
"JMSB ",
"JSEQ ",
"JGTZ ",
"JC ",
"JZ ",
"?????",
"?????",
"JUMP ",
"JNMSB",
"JNSEQ",
"JLEZ ",
"JNC ",
"JNZ ",
"?????",
"?????",
};
static const char *const latches[] =
{
" ",
"SEQLTCH",
"XLTCH ",
"YLTCH ",
"BGLTCH ",
"FGLTCH ",
"CLTCH ",
"ZLTCH ",
};
static const char *const spfs[] =
{
" ",
"FSTOP ",
"FREG ",
"FSTART",
"PWRT ",
"MULT ",
"LSTOP ",
"BRES ",
};
UINT64 inst = BIG_ENDIANIZE_INT64(*(UINT64 *)oprom);
UINT32 inslow = inst & 0xffffffff;
UINT32 inshig = inst >> 32;
int t = (inshig >> 24) & 0xff;
int jmp = (inshig >> 20) & 0xf;
int latch = (inshig >> 16) & 0x7;
int op = (inshig >> 15) & 0x1;
int spf = (inshig >> 12) & 0x7;
int b = (inshig >> 8) & 0xf;
int a = (inshig >> 4) & 0xf;
int i8_6 = (inshig >> 0) & 0x7;
int ci = (inslow >> 31) & 0x1;
int i5_3 = (inslow >> 28) & 0x7;
int _pbcs = (inslow >> 27) & 0x1;
int i2_0 = (inslow >> 24) & 0x7;
sprintf(buffer, "%s %s,%s %x,%x %c %s %.2x %s %s %s %s\n",
ins[i5_3],
src[i2_0],
dst[i8_6],
a,
b,
ci ? 'C' : ' ',
jmps[jmp],
t,
latches[latch],
op ? "OP" : " ",
_pbcs ? " " : "PB",
spfs[spf]);
return 1 | DASMFLAG_SUPPORTED;
}
/**************************************************************************
* Sound set_info
**************************************************************************/
static CPU_SET_INFO( cquestsnd )
{
switch (state)
{
/* --- the following bits of info are set as 64-bit signed integers --- */
case CPUINFO_INT_PC:
case CPUINFO_INT_REGISTER + CQUESTSND_PC: cquestsnd.pc = info->i; break;
case CPUINFO_INT_REGISTER + CQUESTSND_Q: cquestsnd.q = info->i; break;
case CPUINFO_INT_REGISTER + CQUESTSND_RTNLATCH: cquestsnd.rtnlatch = info->i; break;
case CPUINFO_INT_REGISTER + CQUESTSND_ADRCNTR: cquestsnd.adrcntr = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_DINLATCH: cquestsnd.dinlatch = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM0: cquestsnd.ram[0x0] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM1: cquestsnd.ram[0x1] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM2: cquestsnd.ram[0x2] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM3: cquestsnd.ram[0x3] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM4: cquestsnd.ram[0x4] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM5: cquestsnd.ram[0x5] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM6: cquestsnd.ram[0x6] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM7: cquestsnd.ram[0x7] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM8: cquestsnd.ram[0x8] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM9: cquestsnd.ram[0x9] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAMA: cquestsnd.ram[0xa] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAMB: cquestsnd.ram[0xb] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAMC: cquestsnd.ram[0xc] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAMD: cquestsnd.ram[0xd] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAME: cquestsnd.ram[0xe] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAMF: cquestsnd.ram[0xf] = info->i; break;
}
}
/**************************************************************************
* Sound get_info
**************************************************************************/
CPU_GET_INFO( cquestsnd )
{
switch (state)
{
/* --- the following bits of info are returned as 64-bit signed integers --- */
case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(cquestsnd); break;
case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; 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 = 8; break;
case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 8; break;
case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
case CPUINFO_INT_MAX_CYCLES: info->i = 1; break;
case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -3; 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 = 0; break;
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
case CPUINFO_INT_PC:
case CPUINFO_INT_REGISTER + CQUESTSND_PC: info->i = cquestsnd.pc; break;
case CPUINFO_INT_REGISTER + CQUESTSND_RTNLATCH: info->i = cquestsnd.rtnlatch; break;
case CPUINFO_INT_REGISTER + CQUESTSND_ADRCNTR: info->i = cquestsnd.adrcntr; 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(cquestsnd); break;
case CPUINFO_PTR_GET_CONTEXT: info->getcontext = CPU_GET_CONTEXT_NAME(cquestsnd);break;
case CPUINFO_PTR_SET_CONTEXT: info->setcontext = CPU_SET_CONTEXT_NAME(cquestsnd);break;
case CPUINFO_PTR_INIT: info->init = CPU_INIT_NAME(cquestsnd); break;
case CPUINFO_PTR_RESET: info->reset = CPU_RESET_NAME(cquestsnd); break;
case CPUINFO_PTR_EXIT: info->exit = CPU_EXIT_NAME(cquestsnd); break;
case CPUINFO_PTR_EXECUTE: info->execute = CPU_EXECUTE_NAME(cquestsnd); break;
case CPUINFO_PTR_BURN: info->burn = NULL; break;
case CPUINFO_PTR_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(cquestsnd); break;
case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cquestsnd_icount; break;
/* --- the following bits of info are returned as NULL-terminated strings --- */
case CPUINFO_STR_NAME: strcpy(info->s, "Sound CPU");break;
case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Cube Quest"); 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 Philip J Bennett"); break;
case CPUINFO_STR_FLAGS: sprintf(info->s, "......."); break;
case CPUINFO_STR_REGISTER + CQUESTSND_PC: sprintf(info->s, "PC: %02X", cquestsnd.pc); break;
case CPUINFO_STR_REGISTER + CQUESTSND_Q: sprintf(info->s, "Q: %04X", cquestsnd.q); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RTNLATCH: sprintf(info->s, "RTN: %02X", cquestsnd.rtnlatch); break;
case CPUINFO_STR_REGISTER + CQUESTSND_ADRCNTR: sprintf(info->s, "CNT: %02X", cquestsnd.adrcntr); break;
case CPUINFO_STR_REGISTER + CQUESTSND_DINLATCH: sprintf(info->s, "DIN: %04X", cquestsnd.dinlatch); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM0: sprintf(info->s, "RAM[0]: %04X", cquestsnd.ram[0x0]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM1: sprintf(info->s, "RAM[1]: %04X", cquestsnd.ram[0x1]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM2: sprintf(info->s, "RAM[2]: %04X", cquestsnd.ram[0x2]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM3: sprintf(info->s, "RAM[3]: %04X", cquestsnd.ram[0x3]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM4: sprintf(info->s, "RAM[4]: %04X", cquestsnd.ram[0x4]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM5: sprintf(info->s, "RAM[5]: %04X", cquestsnd.ram[0x5]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM6: sprintf(info->s, "RAM[6]: %04X", cquestsnd.ram[0x6]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM7: sprintf(info->s, "RAM[7]: %04X", cquestsnd.ram[0x7]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM8: sprintf(info->s, "RAM[8]: %04X", cquestsnd.ram[0x8]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAM9: sprintf(info->s, "RAM[9]: %04X", cquestsnd.ram[0x9]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAMA: sprintf(info->s, "RAM[A]: %04X", cquestsnd.ram[0xa]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAMB: sprintf(info->s, "RAM[B]: %04X", cquestsnd.ram[0xb]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAMC: sprintf(info->s, "RAM[C]: %04X", cquestsnd.ram[0xc]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAMD: sprintf(info->s, "RAM[D]: %04X", cquestsnd.ram[0xd]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAME: sprintf(info->s, "RAM[E]: %04X", cquestsnd.ram[0xe]); break;
case CPUINFO_STR_REGISTER + CQUESTSND_RAMF: sprintf(info->s, "RAM[F]: %04X", cquestsnd.ram[0xf]); break;
}
}
/**************************************************************************
* Rotate set_info
**************************************************************************/
static CPU_SET_INFO( cquestrot )
{
switch (state)
{
/* --- the following bits of info are set as 64-bit signed integers --- */
case CPUINFO_INT_PC:
case CPUINFO_INT_REGISTER + CQUESTROT_PC: cquestrot.pc = info->i; break;
case CPUINFO_INT_REGISTER + CQUESTROT_Q: cquestrot.q = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM0: cquestrot.ram[0x0] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM1: cquestrot.ram[0x1] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM2: cquestrot.ram[0x2] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM3: cquestrot.ram[0x3] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM4: cquestrot.ram[0x4] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM5: cquestrot.ram[0x5] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM6: cquestrot.ram[0x6] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM7: cquestrot.ram[0x7] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM8: cquestrot.ram[0x8] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM9: cquestrot.ram[0x9] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAMA: cquestrot.ram[0xa] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAMB: cquestrot.ram[0xb] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAMC: cquestrot.ram[0xc] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAMD: cquestrot.ram[0xd] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAME: cquestrot.ram[0xe] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAMF: cquestrot.ram[0xf] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_SEQCNT: cquestrot.seqcnt = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_DYNADDR: cquestrot.dynaddr = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_DYNDATA: cquestrot.dyndata = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_YRLATCH: cquestrot.yrlatch = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_YDLATCH: cquestrot.ydlatch = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_DINLATCH: cquestrot.dinlatch = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_DSRCLATCH:cquestrot.dsrclatch = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTROT_RSRCLATCH:cquestrot.rsrclatch = info->i; break;
}
}
/**************************************************************************
* Rotate get_info
**************************************************************************/
CPU_GET_INFO( cquestrot )
{
switch (state)
{
/* --- the following bits of info are returned as 64-bit signed integers --- */
case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(cquestrot); break;
case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; 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 = 8; break;
case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 8; break;
case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
case CPUINFO_INT_MAX_CYCLES: info->i = 1; break;
case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 9; break;
case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -3; 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 = 0; break;
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
case CPUINFO_INT_PC:
case CPUINFO_INT_REGISTER + CQUESTROT_PC: info->i = cquestrot.pc; 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(cquestrot); break;
case CPUINFO_PTR_GET_CONTEXT: info->getcontext = CPU_GET_CONTEXT_NAME(cquestrot);break;
case CPUINFO_PTR_SET_CONTEXT: info->setcontext = CPU_SET_CONTEXT_NAME(cquestrot);break;
case CPUINFO_PTR_INIT: info->init = CPU_INIT_NAME(cquestrot); break;
case CPUINFO_PTR_RESET: info->reset = CPU_RESET_NAME(cquestrot); break;
case CPUINFO_PTR_EXIT: info->exit = CPU_EXIT_NAME(cquestrot); break;
case CPUINFO_PTR_EXECUTE: info->execute = CPU_EXECUTE_NAME(cquestrot); break;
case CPUINFO_PTR_BURN: info->burn = NULL; break;
case CPUINFO_PTR_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(cquestrot); break;
case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cquestrot_icount; break;
/* --- the following bits of info are returned as NULL-terminated strings --- */
case CPUINFO_STR_NAME: strcpy(info->s, "Rotate CPU");break;
case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Cube Quest"); 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 Philip J Bennett"); break;
case CPUINFO_STR_FLAGS: sprintf(info->s, "%c%c%c", cquestrot.cflag ? 'C' : '.',
cquestrot.vflag ? 'V' : '.',
cquestrot.f ? '.' : 'Z'); break;
case CPUINFO_STR_REGISTER + CQUESTROT_PC: sprintf(info->s, "PC: %02X", cquestrot.pc); break;
case CPUINFO_STR_REGISTER + CQUESTROT_Q: sprintf(info->s, "Q: %04X", cquestrot.q); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM0: sprintf(info->s, "RAM[0]: %04X", cquestrot.ram[0x0]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM1: sprintf(info->s, "RAM[1]: %04X", cquestrot.ram[0x1]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM2: sprintf(info->s, "RAM[2]: %04X", cquestrot.ram[0x2]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM3: sprintf(info->s, "RAM[3]: %04X", cquestrot.ram[0x3]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM4: sprintf(info->s, "RAM[4]: %04X", cquestrot.ram[0x4]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM5: sprintf(info->s, "RAM[5]: %04X", cquestrot.ram[0x5]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM6: sprintf(info->s, "RAM[6]: %04X", cquestrot.ram[0x6]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM7: sprintf(info->s, "RAM[7]: %04X", cquestrot.ram[0x7]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM8: sprintf(info->s, "RAM[8]: %04X", cquestrot.ram[0x8]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAM9: sprintf(info->s, "RAM[9]: %04X", cquestrot.ram[0x9]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAMA: sprintf(info->s, "RAM[A]: %04X", cquestrot.ram[0xa]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAMB: sprintf(info->s, "RAM[B]: %04X", cquestrot.ram[0xb]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAMC: sprintf(info->s, "RAM[C]: %04X", cquestrot.ram[0xc]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAMD: sprintf(info->s, "RAM[D]: %04X", cquestrot.ram[0xd]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAME: sprintf(info->s, "RAM[E]: %04X", cquestrot.ram[0xe]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RAMF: sprintf(info->s, "RAM[F]: %04X", cquestrot.ram[0xf]); break;
case CPUINFO_STR_REGISTER + CQUESTROT_SEQCNT: sprintf(info->s, "SEQCNT: %01X", cquestrot.seqcnt); break;
case CPUINFO_STR_REGISTER + CQUESTROT_DYNADDR: sprintf(info->s, "DYNADDR: %04X", cquestrot.dynaddr); break;
case CPUINFO_STR_REGISTER + CQUESTROT_DYNDATA: sprintf(info->s, "DYNDATA: %04X", cquestrot.dyndata); break;
case CPUINFO_STR_REGISTER + CQUESTROT_YRLATCH: sprintf(info->s, "YRLATCH: %04X", cquestrot.yrlatch); break;
case CPUINFO_STR_REGISTER + CQUESTROT_YDLATCH: sprintf(info->s, "YDLATCH: %04X", cquestrot.ydlatch); break;
case CPUINFO_STR_REGISTER + CQUESTROT_DINLATCH: sprintf(info->s, "DINLATCH: %04X", cquestrot.dinlatch); break;
case CPUINFO_STR_REGISTER + CQUESTROT_DSRCLATCH:sprintf(info->s, "DSRCLATCH: %04X", cquestrot.dsrclatch); break;
case CPUINFO_STR_REGISTER + CQUESTROT_RSRCLATCH:sprintf(info->s, "RSRCLATCH: %04X", cquestrot.rsrclatch); break;
case CPUINFO_STR_REGISTER + CQUESTROT_LDADDR: sprintf(info->s, "LDADDR : %04X", cquestrot.lineaddr); break;
case CPUINFO_STR_REGISTER + CQUESTROT_LDDATA: sprintf(info->s, "LDDATA : %04X", cquestrot.linedata); break;
}
}
/**************************************************************************
* Line drawer set_info
**************************************************************************/
static CPU_SET_INFO( cquestlin )
{
switch (state)
{
/* --- the following bits of info are set as 64-bit signed integers --- */
case CPUINFO_INT_PC:
case CPUINFO_INT_REGISTER + CQUESTLIN_FGPC: cquestlin.pc[FOREGROUND] = info->i; break;
case CPUINFO_INT_REGISTER + CQUESTLIN_BGPC: cquestlin.pc[BACKGROUND] = info->i; break;
case CPUINFO_INT_REGISTER + CQUESTLIN_Q: cquestlin.q = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM0: cquestlin.ram[0x0] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM1: cquestlin.ram[0x1] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM2: cquestlin.ram[0x2] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM3: cquestlin.ram[0x3] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM4: cquestlin.ram[0x4] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM5: cquestlin.ram[0x5] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM6: cquestlin.ram[0x6] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM7: cquestlin.ram[0x7] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM8: cquestlin.ram[0x8] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM9: cquestlin.ram[0x9] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAMA: cquestlin.ram[0xa] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAMB: cquestlin.ram[0xb] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAMC: cquestlin.ram[0xc] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAMD: cquestlin.ram[0xd] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAME: cquestlin.ram[0xe] = info->i; break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAMF: cquestlin.ram[0xf] = info->i; break;
}
}
/**************************************************************************
* Line drawer get_info
**************************************************************************/
CPU_GET_INFO( cquestlin )
{
switch (state)
{
/* --- the following bits of info are returned as 64-bit signed integers --- */
case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(cquestlin); break;
case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; 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 = 8; break;
case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 8; break;
case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
case CPUINFO_INT_MAX_CYCLES: info->i = 1; break;
case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break;
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 8; break;
case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = -3; 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 = 0; break;
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
case CPUINFO_INT_PC:
case CPUINFO_INT_REGISTER + CQUESTLIN_FGPC: info->i = cquestlin.pc[cquestlin.clkcnt & 3 ? BACKGROUND : FOREGROUND]; 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(cquestlin); break;
case CPUINFO_PTR_GET_CONTEXT: info->getcontext = CPU_GET_CONTEXT_NAME(cquestlin);break;
case CPUINFO_PTR_SET_CONTEXT: info->setcontext = CPU_SET_CONTEXT_NAME(cquestlin);break;
case CPUINFO_PTR_INIT: info->init = CPU_INIT_NAME(cquestlin); break;
case CPUINFO_PTR_RESET: info->reset = CPU_RESET_NAME(cquestlin); break;
case CPUINFO_PTR_EXIT: info->exit = CPU_EXIT_NAME(cquestlin); break;
case CPUINFO_PTR_EXECUTE: info->execute = CPU_EXECUTE_NAME(cquestlin); break;
case CPUINFO_PTR_BURN: info->burn = NULL; break;
case CPUINFO_PTR_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(cquestlin); break;
case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &cquestlin_icount; break;
/* --- the following bits of info are returned as NULL-terminated strings --- */
case CPUINFO_STR_NAME: strcpy(info->s, "Line CPU"); break;
case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "Cube Quest"); 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 Philip J Bennett"); break;
case CPUINFO_STR_FLAGS: sprintf(info->s, "%c%c%c|%cG", cquestlin.cflag ? 'C' : '.',
cquestlin.vflag ? 'V' : '.',
cquestlin.f ? '.' : 'Z',
cquestlin.clkcnt & 3 ? 'B' : 'F'); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_FGPC: sprintf(info->s, "FPC: %02X", cquestlin.pc[FOREGROUND]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_BGPC: sprintf(info->s, "BPC: %02X", cquestlin.pc[BACKGROUND]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_Q: sprintf(info->s, "Q: %04X", cquestlin.q); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM0: sprintf(info->s, "RAM[0]: %04X", cquestlin.ram[0x0]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM1: sprintf(info->s, "RAM[1]: %04X", cquestlin.ram[0x1]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM2: sprintf(info->s, "RAM[2]: %04X", cquestlin.ram[0x2]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM3: sprintf(info->s, "RAM[3]: %04X", cquestlin.ram[0x3]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM4: sprintf(info->s, "RAM[4]: %04X", cquestlin.ram[0x4]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM5: sprintf(info->s, "RAM[5]: %04X", cquestlin.ram[0x5]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM6: sprintf(info->s, "RAM[6]: %04X", cquestlin.ram[0x6]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM7: sprintf(info->s, "RAM[7]: %04X", cquestlin.ram[0x7]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM8: sprintf(info->s, "RAM[8]: %04X", cquestlin.ram[0x8]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAM9: sprintf(info->s, "RAM[9]: %04X", cquestlin.ram[0x9]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAMA: sprintf(info->s, "RAM[A]: %04X", cquestlin.ram[0xa]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAMB: sprintf(info->s, "RAM[B]: %04X", cquestlin.ram[0xb]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAMC: sprintf(info->s, "RAM[C]: %04X", cquestlin.ram[0xc]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAMD: sprintf(info->s, "RAM[D]: %04X", cquestlin.ram[0xd]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAME: sprintf(info->s, "RAM[E]: %04X", cquestlin.ram[0xe]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_RAMF: sprintf(info->s, "RAM[F]: %04X", cquestlin.ram[0xf]); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_FADLATCH: sprintf(info->s, "FADDR: %04X", cquestlin.fadlatch); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_BADLATCH: sprintf(info->s, "BADDR: %04X", cquestlin.badlatch); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_SREG: sprintf(info->s, "SREG: %04X", cquestlin.sreg); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_XCNT: sprintf(info->s, "XCNT: %03X", cquestlin.xcnt); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_YCNT: sprintf(info->s, "YCNT: %03X", cquestlin.ycnt); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_CLATCH: sprintf(info->s, "CLATCH: %04X", cquestlin.clatch); break;
case CPUINFO_STR_REGISTER + CQUESTLIN_ZLATCH: sprintf(info->s, "ZLATCH: %04X", cquestlin.zlatch); break;
}
}