/*** Glue Code (******************************************
Glue code to hook up Retrocade's CCPU emulator to MAME's
architecture. Really, it's not so bad!
**********************************************************/
#include "driver.h"
#include "mamedbg.h"
#include "ccpu.h"
static UINT8 ccpu_reg_layout[] = {
CCPU_PC, CCPU_CFLAG, CCPU_CSTATE, CCPU_A, CCPU_B, CCPU_I, -1,
CCPU_P, CCPU_J, CCPU_ACC, CCPU_CMP, CCPU_PA0, 0,
};
/* Layout of the debugger windows x,y,w,h */
static UINT8 ccpu_win_layout[] = {
25, 0,55, 2, /* register window (top rows) */
0, 0,24,22, /* disassembler window (left colums) */
25, 3,55, 9, /* memory #1 window (right, upper middle) */
25,13,55, 9, /* memory #2 window (right, lower middle) */
0,23,80, 1, /* command line window (bottom rows) */
};
/* the MAME version of the CCPU registers */
typedef struct ccpuRegs
{
UINT16 accVal;
UINT16 cmpVal;
UINT8 pa0;
UINT8 cFlag;
UINT16 eRegPC;
UINT16 eRegA;
UINT16 eRegB;
UINT16 eRegI;
UINT16 eRegJ;
UINT8 eRegP;
UINT8 eCState;
} ccpuRegs;
#define CCPU_FETCH(a) ((unsigned)cpu_readop(a))
#define CCPU_READPORT(a) (cpu_readport (a))
#define CCPU_WRITEPORT(a,v) (cpu_writeport (a,v))
#define RAW_VECTORS 1
/* this #define works around the naming conflict with the opcode_table
in cinedbg.c */
#define opcode_table _opcode_table
/* This prototype was missing */
extern void CinemaVectorData (int fromx, int fromy, int tox, int toy, int color);
int ccpu_ICount = 1000;
extern UINT16 ioSwitches;
extern UINT16 ioInputs;
void ccpu_reset(void *param)
{
cineReset();
}
void ccpu_exit(void)
{
/* nothing to do ? */
}
int ccpu_execute(int cycles)
{
int newCycles;
newCycles = cineExec(cycles);
return newCycles;
}
unsigned ccpu_get_context(void *dst)
{
if( dst )
{
CONTEXTCCPU context;
ccpuRegs *Regs = dst;
cGetContext (&context);
Regs->accVal = context.accVal;
Regs->cmpVal = context.cmpVal;
Regs->pa0 = context.pa0;
Regs->cFlag = context.cFlag;
Regs->eRegPC = context.eRegPC;
Regs->eRegA = context.eRegA;
Regs->eRegB = context.eRegB;
Regs->eRegI = context.eRegI;
Regs->eRegJ = context.eRegJ;
Regs->eRegP = context.eRegP;
Regs->eCState = context.eCState;
}
return sizeof(ccpuRegs);
}
void ccpu_set_context(void *src)
{
if( src )
{
CONTEXTCCPU context;
ccpuRegs *Regs = src;
context.accVal = Regs->accVal;
context.cmpVal = Regs->cmpVal;
context.pa0 = Regs->pa0;
context.cFlag = Regs->cFlag;
context.eRegPC = Regs->eRegPC;
context.eRegA = Regs->eRegA;
context.eRegB = Regs->eRegB;
context.eRegI = Regs->eRegI;
context.eRegJ = Regs->eRegJ;
context.eRegP = Regs->eRegP;
context.eCState = (CINESTATE)Regs->eCState;
cSetContext (&context);
}
}
unsigned ccpu_get_pc(void)
{
CONTEXTCCPU context;
cGetContext (&context);
return context.eRegPC;
}
void ccpu_set_pc(unsigned val)
{
CONTEXTCCPU context;
cGetContext (&context);
context.eRegPC = val;
cSetContext (&context);
}
unsigned ccpu_get_sp(void)
{
CONTEXTCCPU context;
cGetContext (&context);
return context.eRegP; /* Is this a stack pointer? */
}
void ccpu_set_sp(unsigned val)
{
CONTEXTCCPU context;
cGetContext (&context);
context.eRegP = val; /* Is this a stack pointer? */
cSetContext (&context);
}
unsigned ccpu_get_reg(int regnum)
{
CONTEXTCCPU context;
cGetContext (&context);
switch( regnum )
{
case CCPU_ACC: return context.accVal;
case CCPU_CMP: return context.cmpVal;
case CCPU_PA0: return context.pa0;
case CCPU_CFLAG: return context.cFlag;
case CCPU_PC: return context.eRegPC;
case CCPU_A: return context.eRegA;
case CCPU_B: return context.eRegB;
case CCPU_I: return context.eRegI;
case CCPU_J: return context.eRegJ;
case CCPU_P: return context.eRegP;
case CCPU_CSTATE: return context.eCState;
/* TODO: return contents of [SP + wordsize * (REG_SP_CONTENTS-regnum)] */
default:
if( regnum <= REG_SP_CONTENTS )
return 0;
}
return 0;
}
void ccpu_set_reg(int regnum, unsigned val)
{
CONTEXTCCPU context;
cGetContext (&context);
switch( regnum )
{
case CCPU_ACC: context.accVal = val; break;
case CCPU_CMP: context.cmpVal = val; break;
case CCPU_PA0: context.pa0 = val; break;
case CCPU_CFLAG: context.cFlag = val; break;
case CCPU_PC: context.eRegPC = val; break;
case CCPU_A: context.eRegA = val; break;
case CCPU_B: context.eRegB = val; break;
case CCPU_I: context.eRegI = val; break;
case CCPU_J: context.eRegJ = val; break;
case CCPU_P: context.eRegP = val; break;
case CCPU_CSTATE: context.eCState = val; break;
/* TODO: set contents of [SP + wordsize * (REG_SP_CONTENTS-regnum)] */
default:
if( regnum <= REG_SP_CONTENTS )
{
unsigned offset = /* SP? + */ (REG_SP_CONTENTS-regnum);
(void)offset;
}
}
cSetContext (&context);
}
void ccpu_set_nmi_line(int state)
{
/* nothing to do */
}
void ccpu_set_irq_line(int irqline, int state)
{
/* nothing to do */
}
void ccpu_set_irq_callback(int (*callback)(int irqline))
{
/* nothing to do */
}
const char *ccpu_info(void *context, int regnum)
{
static char buffer[16][47+1];
static int which = 0;
CONTEXTCCPU *r = context;
which = ++which % 16;
buffer[which][0] = '\0';
if( !context )
{
static CONTEXTCCPU tmp;
cGetContext(&tmp);
r = &tmp;
}
switch( regnum )
{
case CPU_INFO_REG+CCPU_PC: sprintf(buffer[which], "PC:%04X", r->eRegPC); break;
case CPU_INFO_REG+CCPU_CFLAG: sprintf(buffer[which], "C:%02X", r->cFlag); break;
case CPU_INFO_REG+CCPU_CSTATE: sprintf(buffer[which], "S:%X", r->eCState); break;
case CPU_INFO_REG+CCPU_A: sprintf(buffer[which], "A:%03X", r->eRegA); break;
case CPU_INFO_REG+CCPU_B: sprintf(buffer[which], "B:%03X", r->eRegB); break;
case CPU_INFO_REG+CCPU_I: sprintf(buffer[which], "I:%03X", r->eRegI); break;
case CPU_INFO_REG+CCPU_P: sprintf(buffer[which], "P:%X", r->eRegP); break;
case CPU_INFO_REG+CCPU_J: sprintf(buffer[which], "J:%03X", r->eRegJ); break;
case CPU_INFO_REG+CCPU_ACC: sprintf(buffer[which], "ACC:%03X", r->accVal); break;
case CPU_INFO_REG+CCPU_CMP: sprintf(buffer[which], "CMP:%03X", r->cmpVal); break;
case CPU_INFO_REG+CCPU_PA0: sprintf(buffer[which], "PA0:%02X", r->pa0); break;
break;
case CPU_INFO_FLAGS:
/* TODO: no idea how the flags should look like */
sprintf(buffer[which], "%c-%c%c%c%c",
(r->cFlag) ? 'C' : 'c',
(r->eCState == state_A || r->eCState == state_AA) ? 'A':' ',
(r->eCState == state_A) ? 'A':' ',
(r->eCState == state_B || r->eCState == state_BB) ? 'B':' ',
(r->eCState == state_B) ? 'B':' ');
break;
case CPU_INFO_NAME: return "CCPU";
case CPU_INFO_FAMILY: return "Cinematronics CPU";
case CPU_INFO_VERSION: return "1.0";
case CPU_INFO_FILE: return __FILE__;
case CPU_INFO_CREDITS: return "Copyright 1997/1998 Jeff Mitchell and the Retrocade Alliance\nCopyright 1997 Zonn Moore";
case CPU_INFO_REG_LAYOUT: return (const char *)ccpu_reg_layout;
case CPU_INFO_WIN_LAYOUT: return (const char *)ccpu_win_layout;
}
return buffer[which];
}
/* TODO: hook up the disassembler */
unsigned ccpu_dasm(char *buffer, unsigned pc)
{
#ifdef MAME_DEBUG
return DasmCCPU(buffer,pc);
#else
sprintf( buffer, "$%02X", cpu_readop(pc) );
return 1;
#endif
}
void ccpu_Config (int jmi, int msize, int monitor)
{
cineSetJMI (jmi);
cineSetMSize (msize);
cineSetMonitor (monitor);
}
void ccpu_SetInputs(int inputs, int switches)
{
/* ioInputs = inputs;
ioSwitches = switches;*/
}
/* To do:
- make RAM external */
/*============================================================================================*
BELOW LIES THE CORE OF THE CCPU. THE CODE WAS KINDLY GIVEN TO MAME BY ZONN MOORE,
JEFF MITCHELL, AND NEIL BRADLEY. I HAVE PRETTY HEAVILY CLEANED IT UP.
*============================================================================================*/
/*
* cinecore.c, cinedbg.c, cineops.c -- Cinematronics game emulator
* copyright 1997/1998 Jeff Mitchell and the Retrocade Alliance
* copyright 1997 Zonn Moore
*
* This Cinematronics emulator may be freely used in any non-commercial
* venture, and is to be considered as under the Gnu Public Licence
* (GPL, copyleft). To avoid a huge deluge of email, I also allow the
* MAME team usage under the so-called MAME licence for non-commercial
* use.
*
* There are some restrictions, however, mostly to help further development
* of the emulator and continue the enjoyment these fine games have
* provided.
*
* 1) Jeff Mitchell (skeezix@skeleton.org) is the authoritative maintainer for
* the C implementation of the "CCPU" written by Zonn Moore. Modifications
* or changes to this code may not be distributed in source form, in whole
* or in part, without the written permission of the maintainer. (ie: At
* some point after changes have been made, submit them to the maintainer
* for inclusion into the authoritative source tree, for all to use.)
* 2) Credit must be given where appropriate: Jeff Mitchell, author of the
* C version. Zonn Moore for the ASM version and all original research,
* original documentation, etc. (The C version is a rewrite of Zonn's
* brilliant work.) Neil Bradley, for the 32bit conversion of the ASM
* core, and technical assistance. Without him, the C version wouldn't
* have been written. Where possible, please include references to the
* official website for the software (see below), so that others may
* easily find the sources.
* 3) Users of this software are encouraged to periodically check the
* official website for new revisions, bugfixes, etc. This is an
* ongoing project, with many optimizations yet to be done.
*
* Games known to work 100% or nearly so, at some point or another of
* the emulators development (but not necessarily right now :):
* RipOff, Solar Quest, Spacewar, Speed Freak, Star Castle, Star Hawk,
* Tail Gunner, War of the Worlds, Warrior
*
* For reference, all of the cinematronics games are:
* Armor Attack, Barrier, Boxing Bugs, Demon, Ripoff, Solar Quest,
* Spacewar, Speed Freak, Star Castle, Star Hawk, Sundance, Tail Gunner
* War of the worlds, Warrior
* (There is another, but it has not been made available yet)
*
* USAGE:
* 1) The emulator works like any other "processor" emulator
* 2) It does expect a few variables to be set, however, indicating
* which switches were connected on the original boards. (Most
* important is the variable to chose whethor or not to use the MI
* or EI flag...). See below.
* 3) The emulator expects the memory to ALREADY be interleaved into
* "normalacy". The cinem ROMs are slow to read otherwise...
* 4) Endianness doesn't matter; its code nice and slowly :)
* 5) Compile time options may be set to obtain debugging tool, runtime
* traces, etc etc.
* 6) The emulator does the vector handling; you need provide a routine
* to receive the vector draw requests, so that it may queue them up
* 7) Zonn will be documenting the method by which the game palettes
* may be derived, where applicable.
*
* INITIALIZATION:
* Take, for example, the game RipOff (the reaosn I got into this mess :).
* The following variables need to be set, and the functions called, in
* order to have the "cpu" run properly (courtesy Neil Bradley, Zonn Moore):
* bFlipX = 0; bFlipY = 1; bSwapXY = 0; (for vector generation)
* ioInputs = 0xffff; ioSwitches = 0xfff0; (cleared values)
* bOverlay = 0xff; (No overlay)
* cineSetJMI(1); (JMI Allowed)
* cineSetMSize(0); (8K)
* cineSetMonitor(0); (Bi-level display)
*
* If masking values are needed by anyone for the various game
* controllers and whatnot, let me know, and I'll put up a document.
*
* SUPPORT:
* FTP and WEB:
* Official support archive is at ftp.retrocade.com and www.retrocade.com.
* Various mirrors will be kept (ie: skeleton.org, the Emulation Repository,
* erc.), and are yet to be announced.
* EMAIL:
* The C version: Jeff Mitchell is skeezix@skeleton.org
* The ASM version: Neil Bradley (neil@synthcom.com) and
* Zonn Moore (zonn@zonn.com)
*
* An emulator for the Cinematronics vector game hardware, originally
* for use in the Retrocade emulator project. All work is based on
* documentation and sources and testbeds created by Zonn. He's a freak.
*
* Last modified: 02/17/98
*
* 12/04/97: Created a "SETFC" macro for storing the flag_C var
* (shift and mask it at inspection time)
* 12/??/97: Fixed subtraction bugs (using register_B for A0 instead
* of register_A). Fixed input mask value in opINP.
* 12/24/97: Added #define for CCPUSSTEP for single stepping
* 12/25/97: Added ioSwitches &= (!SW_ABORT) into the top
* of the cineExec call. This fixed Star Castle, but
* broke others :/
* Made opLSLe_A_.. handle multiple consecutive occurances
* so things would be a little faster, and so DOS versus
* Unix traces would be easier.
* Changed above ioSwitches fix to ~SW_ABORT instead. This
* rebroke StarCastle and Sundance, but fixed Barrier. *sigh*
*/
/* Optional #defines for debugging:
* CCPUBREAK -- causes stopage on unknown upcodes
* For these to operate, the debugging variables must be set as well.
* This allows runtime selection of traces, etc.
* CCPUSSTEP -- force single stepping
*
* Debug Variables:
* ccpubreak -- set to non-zero to enable "break"ing
*/
/* 1) Need to macro-ize everything, so that I can have this whole
* source file written by a perl script generator easier.
* 4) Any of the jumps weird? JNC?
* 5) JEI's all fucked? Are the tredirector's set right in the first place?
* What about all those damned JPP8, 16 and 32s? They work right?
* 6) Store ccpu_jmi_dip and other new state vars in struct?
* 7) Various OUT functions correct?
*/
#include <stdio.h>
#include <string.h>
#include "ccpu.h"
/*
* Use 0xF000 so as to keep the current page, since it may well
* have been changed with JPP.
*/
#define JMP() register_PC = ((register_PC - 1) & 0xF000) + register_J; ccpu_ICount -= 2
/* Declare needed macros */
#ifdef macintosh
#define UNFINISHED(x) { SysBeep (0); }
#else
#define UNFINISHED(x) { if (errorlog) fprintf (errorlog, "UNFINISHED: %s\n", x); }
#endif
/* Handy new operators ... */
/* for Zonn translation :) */
#define SAR(var,arg) (((signed short int) var) >> arg)
/* for setting/checking the A0 flag */
#define SETA0(var) (acc_a0 = var)
#define GETA0() (acc_a0)
/* for setting/checking the Carry flag */
#define SETFC(val) (flag_C = val)
#define GETFC() ((flag_C >> 8) & 0xFF)
static int bailOut = FALSE;
/* C-CPU context information begins -- */
static CINEWORD register_PC = 0; /* C-CPU registers; program counter */
static CINEWORD register_A = 0; /* A-Register (accumulator) */
static CINEWORD register_B = 0; /* B-Register (accumulator) */
static CINEBYTE register_I = 0; /* I-Register (last access RAM location) */
static CINEWORD register_J = 0; /* J-Register (target address for JMP opcodes) */
static CINEBYTE register_P = 0; /* Page-Register (4 bits) */
static CINEWORD FromX = 0; /* X-Register (start of a vector) */
static CINEWORD FromY = 0; /* Y-Register (start of a vector) */
static CINEWORD register_T = 0; /* T-Register (vector draw length timer) */
static CINEWORD flag_C = 0; /* C-CPU flags; carry. Is word sized, instead
* of CINEBYTE, so we can do direct assignment
* and then change to BYTE during inspection.
*/
static CINEWORD cmp_old = 0; /* last accumulator value */
static CINEWORD cmp_new = 0; /* new accumulator value */
static CINEBYTE acc_a0 = 0; /* bit0 of A-reg at last accumulator access */
static CINESTATE state = state_A;/* C-CPU state machine current state */
static CINEWORD ram[256]; /* C-CPU ram (for all pages) */
static int ccpu_jmi_dip = 0; /* as set by cineSetJMI */
static int ccpu_msize = 0; /* as set by cineSetMSize */
static int ccpu_monitor = 0; /* as set by cineSetMonitor */
static CINEBYTE vgShiftLength = 0; /* number of shifts loaded into length reg */
static CINEWORD vgColour = 0;
/* -- Context information ends. */
int bNewFrame;
/* Note: I have removed all of this assuming that the vector drawing function can handle things */
#if !RAW_VECTORS
int bFlipX;
int bFlipY;
int bSwapXY;
int bOverlay;
extern int sdwGameXSize;
extern int sdwGameYSize;
extern int sdwXOffset;
extern int sdwYOffset;
#endif
/* functions */
#include "ccputabl.c"
/*
* cineExec() is what performs all the "processors" work; it will
* continue to execute until something horrible happens, a watchpoint
* is hit, cycle count exceeded, or other happy things.
*/
CINELONG cineExec (CINELONG cycles)
{
ccpu_ICount = cycles;
bailOut = FALSE;
do
{
int opcode;
CALL_MAME_DEBUG;
/*
* goto the correct piece of code
* for the current opcode. That piece of code will set the state
* for the next run, as well.
*/
opcode = CCPU_FETCH (register_PC++);
state = (*cineops[state][opcode]) (opcode);
ccpu_ICount -= ccpu_cycles[opcode];
/*
* the opcode code has set a state and done mischief with flags and
* the program counter; now jump back to the top and run through another
* opcode.
*/
if (bailOut)
/* ccpu_ICount = 0; */
ccpu_ICount -= 100;
}
while (ccpu_ICount > 0);
return cycles - ccpu_ICount;
}
/*
* the actual opcode code; each piece should be careful to
* (1) set the correct state
* (2) increment the program counter as necessary
* (3) piss with the flags as needed
* otherwise the next opcode will be completely buggered.
*/
CINESTATE opINP_A_AA (int opcode)
{
/*
* bottom 4 bits of opcode are the position of the bit we want;
* obtain input value, shift over that no, and truncate to last bit.
* NOTE: Masking 0x07 does interesting things on Sundance and
* others, but masking 0x0F makes RipOff and others actually work :)
*/
cmp_new = (CCPU_READPORT (CCPU_PORT_IOINPUTS) >> (opcode & 0x0F)) & 0x01;
SETA0 (register_A); /* save old accA bit0 */
SETFC (register_A);
cmp_old = register_A; /* save old accB */
register_A = cmp_new; /* load new accB; zero other bits */
return state_AA;
}
CINESTATE opINP_B_AA (int opcode)
{
/*
* bottom 3 bits of opcode are the position of the bit we want;
* obtain Switches value, shift over that no, and truncate to last bit.
*/
cmp_new = (CCPU_READPORT (CCPU_PORT_IOSWITCHES) >> (opcode & 0x07)) & 0x01;
SETA0 (register_A); /* save old accA bit0 */
SETFC (register_A);
cmp_old = register_B; /* save old accB */
register_B = cmp_new; /* load new accB; zero other bits */
return state_AA;
}
CINESTATE opOUTsnd_A (int opcode)
{
if (!(register_A & 0x01))
CCPU_WRITEPORT (CCPU_PORT_IOOUTPUTS, CCPU_READPORT (CCPU_PORT_IOOUTPUTS) | (0x01 << (opcode & 0x07)));
else
CCPU_WRITEPORT (CCPU_PORT_IOOUTPUTS, CCPU_READPORT (CCPU_PORT_IOOUTPUTS) & ~(0x01 << (opcode & 0x07)));
if ((opcode & 0x07) == 0x05)
{
/* reset coin counter */
}
return state_A;
}
CINESTATE opOUTbi_A_A (int opcode)
{
if ((opcode & 0x07) != 6)
return opOUTsnd_A (opcode);
vgColour = register_A & 0x01 ? 0x0f: 0x07;
return state_A;
}
CINESTATE opOUT16_A_A (int opcode)
{
if ((opcode & 0x07) != 6)
return opOUTsnd_A (opcode);
if ((register_A & 0x1) != 1)
{
vgColour = FromX & 0x0F;
if (!vgColour)
vgColour = 1;
}
return state_A;
}
CINESTATE opOUT64_A_A (int opcode)
{
return state_A;
}
CINESTATE opOUTWW_A_A (int opcode)
{
if ((opcode & 0x07) != 6)
return opOUTsnd_A (opcode);
if ((register_A & 0x1) == 1)
{
CINEWORD temp_word = ~FromX & 0x0FFF;
if (!temp_word) /* black */
vgColour = 0;
else
{ /* non-black */
if (temp_word & 0x0888)
/* bright */
vgColour = ((temp_word >> 1) & 0x04) | ((temp_word >> 6) & 0x02) | ((temp_word >> 11) & 0x01) | 0x08;
else if (temp_word & 0x0444)
/* dim bits */
vgColour = (temp_word & 0x04) | ((temp_word >> 5) & 0x02) | ((temp_word >> 10) & 0x01);
}
} /* colour change? == 1 */
return state_A;
}
CINESTATE opOUTsnd_B (int opcode)
{
return state_BB;
}
CINESTATE opOUTbi_B_BB (int opcode)
{
CINEBYTE temp_byte = opcode & 0x07;
if (temp_byte - 0x06)
return opOUTsnd_B (opcode);
vgColour = ((register_B & 0x01) << 3) | 0x07;
return state_BB;
}
CINESTATE opOUT16_B_BB (int opcode)
{
CINEBYTE temp_byte = opcode & 0x07;
if (temp_byte - 0x06)
return opOUTsnd_B (opcode);
if ((register_B & 0xFF) != 1)
{
vgColour = FromX & 0x0F;
if (!vgColour)
vgColour = 1;
}
return state_BB;
}
CINESTATE opOUT64_B_BB (int opcode)
{
return state_BB;
}
CINESTATE opOUTWW_B_BB (int opcode)
{
return state_BB;
}
/* LDA imm (0x) */
CINESTATE opLDAimm_A_AA (int opcode)
{
CINEWORD temp_word = opcode & 0x0F; /* pick up immediate value */
temp_word <<= 8; /* LDAimm is the HIGH nibble!*/
cmp_new = temp_word; /* set new comparison flag */
SETA0 (register_A); /* save old accA bit0 */
SETFC (register_A); /* ??? clear carry? */
cmp_old = register_A; /* step back cmp flag */
register_A = temp_word; /* set the register */
return state_AA; /* swap state and end opcode */
}
CINESTATE opLDAimm_B_AA (int opcode)
{
CINEWORD temp_word = opcode & 0x0F; /* pick up immediate value */
temp_word <<= 8; /* LDAimm is the HIGH nibble!*/
cmp_new = temp_word; /* set new comparison flag */
SETA0 (register_A); /* save old accA bit0 */
SETFC (register_A);
cmp_old = register_B; /* step back cmp flag */
register_B = temp_word; /* set the register */
return state_AA;
}
CINESTATE opLDAdir_A_AA (int opcode)
{
CINEBYTE temp_byte = opcode & 0x0F; /* snag imm value */
register_I = (register_P << 4) + temp_byte; /* set I register */
cmp_new = ram[register_I]; /* new acc value */
SETA0 (register_A); /* back up bit0 */
SETFC (register_A);
cmp_old = register_A; /* store old acc */
register_A = cmp_new; /* store new acc */
return state_AA;
}
CINESTATE opLDAdir_B_AA (int opcode)
{
CINEBYTE temp_byte = opcode & 0x0F; /* snag imm value */
register_I = (register_P << 4) + temp_byte; /* set I register */
cmp_new = ram[register_I]; /* new acc value */
SETA0 (register_A); /* back up bit0 */
SETFC (register_A);
cmp_old = register_B; /* store old acc */
register_B = cmp_new; /* store new acc */
return state_AA;
}
CINESTATE opLDAirg_A_AA (int opcode)
{
cmp_new = ram[register_I];
SETA0 (register_A);
SETFC (register_A);
cmp_old = register_A;
register_A = cmp_new;
return state_AA;
}
CINESTATE opLDAirg_B_AA (int opcode)
{
cmp_new = ram[register_I];
SETA0 (register_A);
SETFC (register_A);
cmp_old = register_B;
register_B = cmp_new;
return state_AA;
}
/* ADD imm */
CINESTATE opADDimm_A_AA (int opcode)
{
CINEWORD temp_word = opcode & 0x0F; /* get imm value */
cmp_new = temp_word; /* new acc value */
SETA0 (register_A); /* save old accA bit0 */
cmp_old = register_A; /* store old acc for later */
register_A += temp_word; /* add values */
SETFC (register_A); /* store carry and extra */
register_A &= 0xFFF; /* toss out >12bit carry */
return state_AA;
}
CINESTATE opADDimm_B_AA (int opcode)
{
CINEWORD temp_word = opcode & 0x0F; /* get imm value */
cmp_new = temp_word; /* new acc value */
SETA0 (register_A); /* save old accA bit0 */
cmp_old = register_B; /* store old acc for later */
register_B += temp_word; /* add values */
SETFC (register_B); /* store carry and extra */
register_B &= 0xFFF; /* toss out >12bit carry */
return state_AA;
}
/* ADD imm extended */
CINESTATE opADDimmX_A_AA (int opcode)
{
cmp_new = CCPU_FETCH (register_PC++); /* get extended value */
SETA0 (register_A); /* save old accA bit0 */
cmp_old = register_A; /* store old acc for later */
register_A += cmp_new; /* add values */
SETFC (register_A); /* store carry and extra */
register_A &= 0xFFF; /* toss out >12bit carry */
return state_AA;
}
CINESTATE opADDimmX_B_AA (int opcode)
{
cmp_new = CCPU_FETCH (register_PC++); /* get extended value */
SETA0 (register_A); /* save old accA bit0 */
cmp_old = register_B; /* store old acc for later */
register_B += cmp_new; /* add values */
SETFC (register_B); /* store carry and extra */
register_B &= 0xFFF; /* toss out >12bit carry */
return state_AA;
}
CINESTATE opADDdir_A_AA (int opcode)
{
CINEBYTE temp_byte = opcode & 0x0F; /* fetch imm value */
register_I = (register_P << 4) + temp_byte; /* set regI addr */
cmp_new = ram[register_I]; /* fetch imm real value */
SETA0 (register_A); /* store bit0 */
cmp_old = register_A; /* store old acc value */
register_A += cmp_new; /* do acc operation */
SETFC (register_A); /* store carry and extra */
register_A &= 0x0FFF;
return state_AA;
}
CINESTATE opADDdir_B_AA (int opcode)
{
CINEBYTE temp_byte = opcode & 0x0F; /* fetch imm value */
register_I = (register_P << 4) + temp_byte; /* set regI addr */
cmp_new = ram[register_I]; /* fetch imm real value */
SETA0 (register_A); /* store bit0 */
cmp_old = register_B; /* store old acc value */
register_B += cmp_new; /* do acc operation */
SETFC (register_B); /* store carry and extra */
register_B &= 0x0FFF;
return state_AA;
}
CINESTATE opAWDirg_A_AA (int opcode)
{
cmp_new = ram[register_I];
SETA0 (register_A);
cmp_old = register_A;
register_A += cmp_new;
SETFC (register_A);
register_A &= 0x0FFF;
return state_AA;
}
CINESTATE opAWDirg_B_AA (int opcode)
{
cmp_new = ram[register_I];
SETA0 (register_A);
cmp_old = register_B;
register_B += cmp_new;
SETFC (register_B);
register_B &= 0x0FFF;
return state_AA;
}
CINESTATE opSUBimm_A_AA (int opcode)
{
/*
* SUBtractions are negate-and-add instructions of the CCPU; what
* a pain in the ass.
*/
CINEWORD temp_word = opcode & 0x0F;
cmp_new = temp_word;
SETA0 (register_A);
cmp_old = register_A;
temp_word = (temp_word ^ 0xFFF) + 1; /* ones compliment */
register_A += temp_word; /* add */
SETFC (register_A); /* pick up top bits */
register_A &= 0x0FFF; /* mask final regA value */
return state_AA;
}
CINESTATE opSUBimm_B_AA (int opcode)
{
/*
* SUBtractions are negate-and-add instructions of the CCPU; what
* a pain in the ass.
*/
CINEWORD temp_word = opcode & 0x0F;
cmp_new = temp_word;
SETA0 (register_A);
cmp_old = register_B;
temp_word = (temp_word ^ 0xFFF) + 1; /* ones compliment */
register_B += temp_word; /* add */
SETFC (register_B); /* pick up top bits */
register_B &= 0x0FFF; /* mask final regA value */
return state_AA;
}
CINESTATE opSUBimmX_A_AA (int opcode)
{
CINEWORD temp_word = CCPU_FETCH (register_PC++); /* snag imm value */
cmp_new = temp_word; /* save cmp value */
SETA0 (register_A); /* store bit0 */
cmp_old = register_A; /* back up regA */
temp_word = (temp_word ^ 0xFFF) + 1; /* ones compliment */
register_A += temp_word; /* add */
SETFC (register_A); /* pick up top bits */
register_A &= 0x0FFF; /* mask final regA value */
return state_AA;
}
CINESTATE opSUBimmX_B_AA (int opcode)
{
CINEWORD temp_word = CCPU_FETCH (register_PC++); /* snag imm value */
cmp_new = temp_word; /* save cmp value */
SETA0 (register_A); /* store bit0 */
cmp_old = register_B; /* back up regA */
temp_word = (temp_word ^ 0xFFF) + 1; /* ones compliment */
register_B += temp_word; /* add */
SETFC (register_B); /* pick up top bits */
register_B &= 0x0FFF; /* mask final regA value */
return state_AA;
}
CINESTATE opSUBdir_A_AA (int opcode)
{
CINEWORD temp_word = opcode & 0x0F; /* fetch imm value */
register_I = (register_P << 4) + temp_word; /* set regI addr */
cmp_new = ram[register_I];
SETA0 (register_A);
cmp_old = register_A;
temp_word = (cmp_new ^ 0xFFF) + 1; /* ones compliment */
register_A += temp_word; /* add */
SETFC (register_A); /* pick up top bits */
register_A &= 0x0FFF; /* mask final regA value */
return state_AA;
}
CINESTATE opSUBdir_B_AA (int opcode)
{
CINEWORD temp_word;
CINEBYTE temp_byte = opcode & 0x0F; /* fetch imm value */
register_I = (register_P << 4) + temp_byte; /* set regI addr */
cmp_new = ram[register_I];
SETA0 (register_A);
cmp_old = register_B;
temp_word = (cmp_new ^ 0xFFF) + 1; /* ones compliment */
register_B += temp_word; /* add */
SETFC (register_B); /* pick up top bits */
register_B &= 0x0FFF; /* mask final regA value */
return state_AA;
}
CINESTATE opSUBirg_A_AA (int opcode)
{
CINEWORD temp_word;
/* sub [i] */
cmp_new = ram[register_I];
SETA0 (register_A);
cmp_old = register_A;
temp_word = (cmp_new ^ 0xFFF) + 1; /* ones compliment */
register_A += temp_word; /* add */
SETFC (register_A); /* pick up top bits */
register_A &= 0x0FFF; /* mask final regA value */
return state_AA;
}
CINESTATE opSUBirg_B_AA (int opcode)
{
CINEWORD temp_word;
/* sub [i] */
cmp_new = ram[register_I];
SETA0 (register_A);
cmp_old = register_B;
temp_word = (cmp_new ^ 0xFFF) + 1; /* ones compliment */
register_B += temp_word; /* add */
SETFC (register_B); /* pick up top bits */
register_B &= 0x0FFF; /* mask final regA value */
return state_AA;
}
/* CMP dir */
CINESTATE opCMPdir_A_AA (int opcode)
{
/*
* compare direct mode; don't modify regs, just set carry flag or not.
*/
CINEWORD temp_word;
CINEBYTE temp_byte = opcode & 0x0F; /* obtain relative addr */
register_I = (register_P << 4) + temp_byte; /* build real addr */
temp_word = ram[register_I];
cmp_new = temp_word; /* new acc value */
SETA0 (register_A); /* backup bit0 */
cmp_old = register_A; /* backup old acc */
temp_word = (temp_word ^ 0xFFF) + 1; /* ones compliment */
temp_word += register_A;
SETFC (temp_word); /* pick up top bits */
return state_AA;
}
CINESTATE opCMPdir_B_AA (int opcode)
{
CINEWORD temp_word;
CINEBYTE temp_byte = opcode & 0x0F; /* obtain relative addr */
register_I = (register_P << 4) + temp_byte; /* build real addr */
temp_word = ram[register_I];
cmp_new = temp_word; /* new acc value */
SETA0 (register_A); /* backup bit0 */
cmp_old = register_B; /* backup old acc */
temp_word = (temp_word ^ 0xFFF) + 1; /* ones compliment */
temp_word += register_B;
SETFC (temp_word); /* pick up top bits */
return state_AA;
}
/* AND [i] */
CINESTATE opANDirg_A_AA (int opcode)
{
cmp_new = ram[register_I]; /* new acc value */
SETA0 (register_A);
SETFC (register_A);
cmp_old = register_A;
register_A &= cmp_new;
return state_AA;
}
CINESTATE opANDirg_B_AA (int opcode)
{
cmp_new = ram[register_I]; /* new acc value */
SETA0 (register_A);
SETFC (register_A);
cmp_old = register_B;
register_B &= cmp_new;
return state_AA;
}
/* LDJ imm */
CINESTATE opLDJimm_A_A (int opcode)
{
CINEBYTE temp_byte = CCPU_FETCH (register_PC++); /* upper part of address */
temp_byte = (temp_byte << 4) | /* Silly CCPU; Swap */
(temp_byte >> 4); /* nibbles */
/* put the upper 8 bits above the existing 4 bits */
register_J = (opcode & 0x0F) | (temp_byte << 4);
return state_A;
}
CINESTATE opLDJimm_B_BB (int opcode)
{
CINEBYTE temp_byte = CCPU_FETCH (register_PC++); /* upper part of address */
temp_byte = (temp_byte << 4) | /* Silly CCPU; Swap */
(temp_byte >> 4); /* nibbles */
/* put the upper 8 bits above the existing 4 bits */
register_J = (opcode & 0x0F) | (temp_byte << 4);
return state_BB;
}
/* LDJ irg */
CINESTATE opLDJirg_A_A (int opcode)
{
/* load J reg from value at last dir addr */
register_J = ram[register_I];
return state_A;
}
CINESTATE opLDJirg_B_BB (int opcode)
{
register_J = ram[register_I];
return state_BB;
}
/* LDP imm */
CINESTATE opLDPimm_A_A (int opcode)
{
/* load page register from immediate */
register_P = opcode & 0x0F; /* set page register */
return state_A;
}
CINESTATE opLDPimm_B_BB (int opcode)
{
/* load page register from immediate */
register_P = opcode & 0x0F; /* set page register */
return state_BB;
}
/* LDI dir */
CINESTATE opLDIdir_A_A (int opcode)
{
/* load regI directly .. */
CINEBYTE temp_byte = (register_P << 4) + /* get ram page ... */
(opcode & 0x0F); /* and imm half of ram addr.. */
register_I = ram[temp_byte] & 0xFF; /* set/mask new register_I */
return state_A;
}
CINESTATE opLDIdir_B_BB (int opcode)
{
CINEBYTE temp_byte = (register_P << 4) + /* get ram page ... */
(opcode & 0x0F); /* and imm half of ram addr.. */
register_I = ram[temp_byte] & 0xFF; /* set/mask new register_I */
return state_BB;
}
/* STA dir */
CINESTATE opSTAdir_A_A (int opcode)
{
CINEBYTE temp_byte = opcode & 0x0F; /* snag imm value */
register_I = (register_P << 4) + temp_byte; /* set I register */
ram[register_I] = register_A; /* store acc to RAM */
return state_A;
}
CINESTATE opSTAdir_B_BB (int opcode)
{
CINEBYTE temp_byte = opcode & 0x0F; /* snag imm value */
register_I = (register_P << 4) + temp_byte; /* set I register */
ram[register_I] = register_B; /* store acc to RAM */
return state_BB;
}
/* STA irg */
CINESTATE opSTAirg_A_A (int opcode)
{
/*
* STA into address specified in regI. Nice and easy :)
*/
ram[register_I] = register_A; /* store acc */
return state_A;
}
CINESTATE opSTAirg_B_BB (int opcode)
{
ram[register_I] = register_B; /* store acc */
return state_BB;
}
/* XLT */
CINESTATE opXLT_A_AA (int opcode)
{
/*
* XLT is weird; it loads the current accumulator with the bytevalue
* at ROM location pointed to by the accumulator; this allows the
* program to read the program itself..
* NOTE! Next opcode is *IGNORED!* because of a twisted side-effect
*/
cmp_new = CCPU_FETCH (((register_PC - 1) & 0xF000) + register_A); /* store new acc value */
SETA0 (register_A); /* store bit0 */
SETFC (register_A);
cmp_old = register_A; /* back up acc */
register_A = cmp_new; /* new acc value */
register_PC++; /* bump PC twice because XLT is fucked up */
return state_AA;
}
CINESTATE opXLT_B_AA (int opcode)
{
cmp_new = CCPU_FETCH (((register_PC - 1) & 0xF000) + register_B); /* store new acc value */
SETA0 (register_A); /* store bit0 */
SETFC (register_A);
cmp_old = register_B; /* back up acc */
register_B = cmp_new; /* new acc value */
register_PC++; /* bump PC twice because XLT is fucked up */
return state_AA;
}
/* MUL [i] */
CINESTATE opMULirg_A_AA (int opcode)
{
CINEBYTE temp_byte = opcode & 0xFF; /* (for ease and speed) */
CINEWORD temp_word = ram[register_I]; /* pick up ram value */
cmp_new = temp_word;
temp_word <<= 4; /* shift into ADD position */
register_B <<= 4; /* get sign bit 15 */
register_B |= (register_A >> 8); /* bring in A high nibble */
register_A = ((register_A & 0xFF) << 8) | /* shift over 8 bits */
temp_byte; /* pick up opcode */
if (register_A & 0x100)
{ /* 1bit shifted out? */
register_A = (register_A >> 8) |
((register_B & 0xFF) << 8);
SETA0 (register_A & 0xFF); /* store bit0 */
register_A >>= 1;
register_A &= 0xFFF;
register_B = SAR(register_B,4);
cmp_old = register_B & 0x0F;
register_B = SAR(register_B,1);
register_B &= 0xFFF;
register_B += cmp_new;
SETFC (register_B);
register_B &= 0xFFF;
}
else
{
register_A = (register_A >> 8) | /* Bhigh | Alow */
((register_B & 0xFF) << 8);
temp_word = register_A & 0xFFF;
SETA0 (temp_word & 0xFF); /* store bit0 */
cmp_old = temp_word;
temp_word += cmp_new;
SETFC (temp_word);
register_A >>= 1;
register_A &= 0xFFF;
register_B = SAR(register_B,5);
register_B &= 0xFFF;
}
return state_AA;
}
CINESTATE opMULirg_B_AA (int opcode)
{
CINEWORD temp_word = ram[register_I];
cmp_new = temp_word;
cmp_old = register_B;
SETA0 (register_A & 0xFF);
register_B <<= 4;
register_B = SAR(register_B,5);
if (register_A & 0x01)
{
register_B += temp_word;
SETFC (register_B);
register_B &= 0x0FFF;
}
else
{
temp_word += register_B;
SETFC (temp_word);
}
return state_AA;
}
/* LSRe */
CINESTATE opLSRe_A_AA (int opcode)
{
/*
* EB; right shift pure; fill new bit with zero.
*/
CINEWORD temp_word = 0x0BEB;
cmp_new = temp_word;
SETA0 (register_A);
cmp_old = register_A;
temp_word += register_A;
SETFC (temp_word);
register_A >>= 1;
return state_AA;
}
CINESTATE opLSRe_B_AA (int opcode)
{
CINEWORD temp_word = 0x0BEB;
cmp_new = temp_word;
SETA0 (register_A);
cmp_old = register_B;
temp_word += register_B;
SETFC (temp_word);
register_B >>= 1;
return state_AA;
}
CINESTATE opLSRf_A_AA (int opcode)
{
UNFINISHED ("opLSRf 1\n");
return state_AA;
}
CINESTATE opLSRf_B_AA (int opcode)
{
UNFINISHED ("opLSRf 2\n");
return state_AA;
}
CINESTATE opLSLe_A_AA (int opcode)
{
/*
* EC; left shift pure; fill new bit with zero *
*/
CINEWORD temp_word = 0x0CEC;
cmp_new = temp_word;
SETA0 (register_A);
cmp_old = register_A;
temp_word += register_A;
SETFC (temp_word);
register_A <<= 1;
register_A &= 0x0FFF;
return state_AA;
}
CINESTATE opLSLe_B_AA (int opcode)
{
CINEWORD temp_word = 0x0CEC; /* data register */
cmp_new = temp_word; /* magic value */
SETA0 (register_A); /* back up bit0 */
cmp_old = register_B; /* store old acc */
temp_word += register_B; /* add to acc */
SETFC (temp_word); /* store carry flag */
register_B <<= 1; /* add regA to itself */
register_B &= 0xFFF; /* toss excess bits */
return state_AA;
}
CINESTATE opLSLf_A_AA (int opcode)
{
UNFINISHED ("opLSLf 1\n");
return state_AA;
}
CINESTATE opLSLf_B_AA (int opcode)
{
UNFINISHED ("opLSLf 2\n");
return state_AA;
}
CINESTATE opASRe_A_AA (int opcode)
{
/* agh! I dislike these silly 12bit processors :P */
cmp_new = 0x0DED;
SETA0 (register_A); /* store bit0 */
SETFC (register_A);
cmp_old = register_A;
register_A <<= 4; /* get sign bit */
register_A = SAR(register_A,5);
register_A &= 0xFFF;
return state_AA;
}
CINESTATE opASRe_B_AA (int opcode)
{
cmp_new = 0x0DED;
SETA0 (register_A);
SETFC (register_A);
cmp_old = register_B;
register_B <<= 4;
register_B = SAR(register_B,5);
register_B &= 0x0FFF;
return state_AA;
}
CINESTATE opASRf_A_AA (int opcode)
{
UNFINISHED ("opASRf 1\n");
return state_AA;
}
CINESTATE opASRf_B_AA (int opcode)
{
UNFINISHED ("opASRf 2\n");
return state_AA;
}
CINESTATE opASRDe_A_AA (int opcode)
{
/*
* Arithmetic shift right of D (A+B) .. B is high (sign bits).
* divide by 2, but leave the sign bit the same. (ie: 1010 -> 1001)
*/
CINEWORD temp_word = 0x0EEE;
CINEWORD temp_word_2;
cmp_new = temp_word; /* save new acc value */
SETA0 (register_A & 0xFF); /* save old accA bit0 */
cmp_old = register_A; /* save old acc */
temp_word += register_A;
SETFC (temp_word);
register_A <<= 4;
register_B <<= 4;
temp_word_2 = (register_B >> 4) << 15;
register_B = SAR(register_B,5);
register_A = (register_A >> 1) | temp_word_2;
register_A >>= 4;
register_B &= 0x0FFF;
return state_AA;
}
CINESTATE opASRDe_B_AA (int opcode)
{
CINEWORD temp_word = 0x0EEE;
cmp_new = temp_word;
SETA0 (register_A & 0xFF);
cmp_old = register_B;
temp_word += register_B;
SETFC (temp_word);
register_B <<= 4;
register_B = SAR(register_B,5);
register_B &= 0x0FFF;
return state_AA;
}
CINESTATE opASRDf_A_AA (int opcode)
{
UNFINISHED ("opASRDf 1\n");
return state_AA;
}
CINESTATE opASRDf_B_AA (int opcode)
{
UNFINISHED ("opASRDf 2\n");
return state_AA;
}
CINESTATE opLSLDe_A_AA (int opcode)
{
/* LSLDe -- Left shift through both accumulators; lossy in middle. */
CINEWORD temp_word = 0x0FEF;
cmp_new = temp_word;
SETA0 (register_A);
cmp_old = register_A;
temp_word += register_A;
SETFC (temp_word);
register_A <<= 1; /* logical shift left */
register_A &= 0xFFF;
register_B <<= 1;
register_B &= 0xFFF;
return state_AA;
}
CINESTATE opLSLDe_B_AA (int opcode)
{
UNFINISHED ("opLSLD 1\n");
return state_AA;
}
CINESTATE opLSLDf_A_AA (int opcode)
{
/* LSLDf */
CINEWORD temp_word = 0x0FFF;
cmp_new = temp_word;
SETA0 (register_A);
cmp_old = register_A;
temp_word += register_A;
SETFC (temp_word);
register_A <<= 1;
register_A &= 0x0FFF;
register_B <<= 1;
register_B &= 0x0FFF;
return state_AA;
}
CINESTATE opLSLDf_B_AA (int opcode)
{
/* not 'the same' as the A->AA version above */
CINEWORD temp_word = 0x0FFF;
cmp_new = temp_word;
SETA0 (register_A);
cmp_old = register_B;
temp_word += register_B;
SETFC (temp_word);
register_B <<= 1;
register_B &= 0x0FFF;
return state_AA;
}
CINESTATE opJMP_A_A (int opcode)
{
/*
* simple jump; change PC and continue..
*/
JMP();
return state_A;
}
CINESTATE opJMP_B_BB (int opcode)
{
JMP();
return state_BB;
}
CINESTATE opJEI_A_A (int opcode)
{
if (FromX & 0x800)
FromX |= 0xF000;
if (!(CCPU_READPORT (CCPU_PORT_IOOUTPUTS) & 0x80))
{
if ((CCPU_READPORT (CCPU_PORT_IN_JOYSTICKY) - (CINESWORD)FromX) < 0x800)
JMP();
}
else
{
if ((CCPU_READPORT (CCPU_PORT_IN_JOYSTICKX) - (CINESWORD)FromX) < 0x800)
JMP();
}
return state_A;
}
CINESTATE opJEI_B_BB (int opcode)
{
if (FromX & 0x800)
FromX |= 0xF000;
if (!(CCPU_READPORT (CCPU_PORT_IOOUTPUTS) & 0x80))
{
if ((CCPU_READPORT (CCPU_PORT_IN_JOYSTICKY) - (CINESWORD)FromX) < 0x800)
JMP();
}
else
{
if ((CCPU_READPORT (CCPU_PORT_IN_JOYSTICKX) - (CINESWORD)FromX) < 0x800)
JMP();
}
return state_BB;
}
CINESTATE opJEI_A_B (int opcode)
{
if (FromX & 0x800)
FromX |= 0xF000;
if (!(CCPU_READPORT (CCPU_PORT_IOOUTPUTS) & 0x80))
{
if ((CCPU_READPORT (CCPU_PORT_IN_JOYSTICKY) - (CINESWORD)FromX) < 0x800)
JMP();
}
else
{
if ((CCPU_READPORT (CCPU_PORT_IN_JOYSTICKX) - (CINESWORD)FromX) < 0x800)
JMP();
}
return state_B;
}
CINESTATE opJMI_A_A (int opcode)
{
/*
* previous instruction was not an ACC instruction, nor was the
* instruction twice back a USB, therefore minus flag test the
* current A-reg
*/
/* negative acc? */
if (register_A & 0x800)
JMP(); /* yes -- do jump */
return state_A;
}
CINESTATE opJMI_AA_A (int opcode)
{
/* previous acc negative? Jump if so... */
if (cmp_old & 0x800)
JMP();
return state_A;
}
CINESTATE opJMI_BB_A (int opcode)
{
if (register_B & 0x800)
JMP();
return state_A;
}
CINESTATE opJMI_B_BB (int opcode)
{
if (register_A & 0x800)
JMP();
return state_BB;
}
CINESTATE opJLT_A_A (int opcode)
{
/* jump if old acc equals new acc */
if (cmp_new < cmp_old)
JMP();
return state_A;
}
CINESTATE opJLT_B_BB (int opcode)
{
if (cmp_new < cmp_old)
JMP();
return state_BB;
}
CINESTATE opJEQ_A_A (int opcode)
{
/* jump if equal */
if (cmp_new == cmp_old)
JMP();
return state_A;
}
CINESTATE opJEQ_B_BB (int opcode)
{
if (cmp_new == cmp_old)
JMP();
return state_BB;
}
CINESTATE opJA0_A_A (int opcode)
{
if (acc_a0 & 0x01)
JMP();
return state_A;
}
CINESTATE opJA0_B_BB (int opcode)
{
if (acc_a0 & 0x01)
JMP();
return state_BB;
}
CINESTATE opJNC_A_A (int opcode)
{
if (!(GETFC() & 0xF0))
JMP(); /* no carry, so jump */
return state_A;
}
CINESTATE opJNC_B_BB (int opcode)
{
if (!(GETFC() & 0xF0))
JMP(); /* no carry, so jump */
return state_BB;
}
CINESTATE opJDR_A_A (int opcode)
{
/*
* Calculate number of cycles executed since
* last 'VDR' instruction, add two and use as
* cycle count, never branch
*/
return state_A;
}
CINESTATE opJDR_B_BB (int opcode)
{
/*
* Calculate number of cycles executed since
* last 'VDR' instruction, add two and use as
* cycle count, never branch
*/
return state_BB;
}
CINESTATE opNOP_A_A (int opcode)
{
return state_A;
}
CINESTATE opNOP_B_BB (int opcode)
{
return state_BB;
}
CINESTATE opJPP32_A_B (int opcode)
{
/*
* 00 = Offset 0000h
* 01 = Offset 1000h
* 02 = Offset 2000h
* 03 = Offset 3000h
* 04 = Offset 4000h
* 05 = Offset 5000h
* 06 = Offset 6000h
* 07 = Offset 7000h
*/
CINEWORD temp_word = (register_P & 0x07) << 12; /* rom offset */
register_PC = register_J + temp_word;
return state_B;
}
CINESTATE opJPP32_B_BB (int opcode)
{
CINEWORD temp_word = (register_P & 0x07) << 12; /* rom offset */
register_PC = register_J + temp_word;
return state_BB;
}
CINESTATE opJPP16_A_B (int opcode)
{
/*
* 00 = Offset 0000h
* 01 = Offset 1000h
* 02 = Offset 2000h
* 03 = Offset 3000h
*/
CINEWORD temp_word = (register_P & 0x03) << 12; /* rom offset */
register_PC = register_J + temp_word;
return state_B;
}
CINESTATE opJPP16_B_BB (int opcode)
{
CINEWORD temp_word = (register_P & 0x03) << 12; /* rom offset */
register_PC = register_J + temp_word;
return state_BB;
}
CINESTATE opJMP_A_B (int opcode)
{
JMP();
return state_B;
}
CINESTATE opJPP8_A_B (int opcode)
{
/*
* "long jump"; combine P and J to jump to a new far location (that can
* be more than 12 bits in address). After this jump, further jumps
* are local to this new page.
*/
CINEWORD temp_word = ((register_P & 0x03) - 1) << 12; /* rom offset */
register_PC = register_J + temp_word;
return state_B;
}
CINESTATE opJPP8_B_BB (int opcode)
{
CINEWORD temp_word = ((register_P & 0x03) - 1) << 12; /* rom offset */
register_PC = register_J + temp_word;
return state_BB;
}
CINESTATE opJMI_A_B (int opcode)
{
if (register_A & 0x800)
JMP();
return state_B;
}
CINESTATE opJMI_AA_B (int opcode)
{
UNFINISHED ("opJMI 3\n");
return state_B;
}
CINESTATE opJMI_BB_B (int opcode)
{
UNFINISHED ("opJMI 4\n");
return state_B;
}
CINESTATE opJLT_A_B (int opcode)
{
if (cmp_new < cmp_old)
JMP();
return state_B;
}
CINESTATE opJEQ_A_B (int opcode)
{
if (cmp_new == cmp_old)
JMP();
return state_B;
}
CINESTATE opJA0_A_B (int opcode)
{
if (GETA0() & 0x01)
JMP();
return state_B;
}
CINESTATE opJNC_A_B (int opcode)
{
if (!(GETFC() & 0x0F0))
JMP(); /* if no carry, jump */
return state_B;
}
CINESTATE opJDR_A_B (int opcode)
{
/* register_PC++; */
fprintf (stderr, "The hell? No PC incrementing?\n");
return state_B;
}
/* NOP */
CINESTATE opNOP_A_B (int opcode)
{
return state_B;
}
CINESTATE opLLT_A_AA (int opcode)
{
CINEBYTE temp_byte = 0;
while (1)
{
CINEWORD temp_word = register_A >> 8; /* register_A's high bits */
temp_word &= 0x0A; /* only want PA11 and PA9 */
if (temp_word)
{
temp_word ^= 0x0A; /* flip the bits */
if (temp_word)
break; /* if not zero, mismatch found */
}
temp_word = register_B >> 8; /* regB's top bits */
temp_word &= 0x0A; /* only want SA11 and SA9 */
if (temp_word)
{
temp_word ^= 0x0A; /* flip bits */
if (temp_word)
break; /* if not zero, mismatch found */
}
register_A <<= 1; /* shift regA */
register_B <<= 1; /* shift regB */
temp_byte ++;
if (!temp_byte)
return state_AA;
/* try again */
}
vgShiftLength = temp_byte;
register_A &= 0x0FFF;
register_B &= 0x0FFF;
return state_AA;
}
CINESTATE opLLT_B_AA (int opcode)
{
UNFINISHED ("opLLT 1\n");
return state_AA;
}
CINESTATE opVIN_A_A (int opcode)
{
/* set the starting address of a vector */
FromX = register_A & 0xFFF; /* regA goes to x-coord */
FromY = register_B & 0xFFF; /* regB goes to y-coord */
return state_A;
}
CINESTATE opVIN_B_BB (int opcode)
{
FromX = register_A & 0xFFF; /* regA goes to x-coord */
FromY = register_B & 0xFFF; /* regB goes to y-coord */
return state_BB;
}
CINESTATE opWAI_A_A (int opcode)
{
/* wait for a tick on the watchdog */
bNewFrame = 1;
bailOut = TRUE;
return state;
}
CINESTATE opWAI_B_BB (int opcode)
{
bNewFrame = 1;
bailOut = TRUE;
return state;
}
CINESTATE opVDR_A_A (int opcode)
{
/* set ending points and draw the vector, or buffer for a later draw. */
int ToX = register_A & 0xFFF;
int ToY = register_B & 0xFFF;
/*
* shl 20, sar 20; this means that if the CCPU reg should be -ve,
* we should be negative as well.. sign extended.
*/
if (FromX & 0x800)
FromX |= 0xFFFFF000;
if (ToX & 0x800)
ToX |= 0xFFFFF000;
if (FromY & 0x800)
FromY |= 0xFFFFF000;
if (ToY & 0x800)
ToY |= 0xFFFFF000;
/* figure out the vector */
ToX -= FromX;
ToX = SAR(ToX,vgShiftLength);
ToX += FromX;
ToY -= FromY;
ToY = SAR(ToY,vgShiftLength);
ToY += FromY;
/* do orientation flipping, etc. */
/* NOTE: this has been removed on the assumption that the vector draw routine can do it all */
#if !RAW_VECTORS
if (bFlipX)
{
ToX = sdwGameXSize - ToX;
FromX = sdwGameXSize - FromX;
}
if (bFlipY)
{
ToY = sdwGameYSize - ToY;
FromY = sdwGameYSize - FromY;
}
FromX += sdwXOffset;
ToX += sdwXOffset;
FromY += sdwYOffset;
ToY += sdwYOffset;
/* check real coords */
if (bSwapXY)
{
CINEWORD temp_word;
temp_word = ToY;
ToY = ToX;
ToX = temp_word;
temp_word = FromY;
FromY = FromX;
FromX = temp_word;
}
#endif
/* render the line */
CinemaVectorData (FromX, FromY, ToX, ToY, vgColour);
return state_A;
}
CINESTATE opVDR_B_BB (int opcode)
{
UNFINISHED ("opVDR B 1\n");
return state_BB;
}
/*
* some code needs to be changed based on the machine or switches set.
* Instead of getting disorganized, I'll put the extra dispatchers
* here. The main dispatch loop jumps here, checks options, and
* redispatches to the actual opcode handlers.
*/
/* JPP series of opcodes */
CINESTATE tJPP_A_B (int opcode)
{
/* MSIZE -- 0 = 4k, 1 = 8k, 2 = 16k, 3 = 32k */
switch (ccpu_msize)
{
case CCPU_MEMSIZE_4K:
case CCPU_MEMSIZE_8K:
return opJPP8_A_B (opcode);
case CCPU_MEMSIZE_16K:
return opJPP16_A_B (opcode);
case CCPU_MEMSIZE_32K:
return opJPP32_A_B (opcode);
}
fprintf (stderr, "Out of range JPP!\n");
return opJPP32_A_B (opcode);
}
CINESTATE tJPP_B_BB (int opcode)
{
/* MSIZE -- 0 = 4k, 1 = 8k, 2 = 16k, 3 = 32k */
switch (ccpu_msize)
{
case CCPU_MEMSIZE_4K:
case CCPU_MEMSIZE_8K:
return opJPP8_B_BB (opcode);
case CCPU_MEMSIZE_16K:
return opJPP16_B_BB (opcode);
case CCPU_MEMSIZE_32K:
return opJPP32_B_BB (opcode);
}
fprintf (stderr, "Out of range JPP!\n");
return state;
}
/* JMI series of opcodes */
CINESTATE tJMI_A_B (int opcode)
{
return (ccpu_jmi_dip) ? opJMI_A_B (opcode) : opJEI_A_B (opcode);
}
CINESTATE tJMI_A_A (int opcode)
{
return (ccpu_jmi_dip) ? opJMI_A_A (opcode) : opJEI_A_A (opcode);
}
CINESTATE tJMI_AA_B (int opcode)
{
return (ccpu_jmi_dip) ? opJMI_AA_B (opcode) : opJEI_AA_B (opcode);
}
CINESTATE tJMI_AA_A (int opcode)
{
return (ccpu_jmi_dip) ? opJMI_AA_A (opcode) : opJEI_A_A (opcode);
}
CINESTATE tJMI_B_BB1 (int opcode)
{
return (ccpu_jmi_dip) ? opJMI_B_BB (opcode) : opJEI_B_BB (opcode);
}
CINESTATE tJMI_BB_B (int opcode)
{
return (ccpu_jmi_dip) ? opJMI_BB_B (opcode) : opJEI_A_B (opcode);
}
CINESTATE tJMI_BB_A (int opcode)
{
return (ccpu_jmi_dip) ? opJMI_BB_A (opcode) : opJEI_A_A (opcode);
}
/*
* OUT series of opcodes:
* ccpu_monitor can be one of:
* 1 -- 16-level colour
* 2 -- 64-level colour
* 3 -- War of the Worlds colour
* other -- bi-level
*/
CINESTATE tOUT_A_A (int opcode)
{
switch (ccpu_monitor)
{
case CCPU_MONITOR_16LEV:
return opOUT16_A_A (opcode);
case CCPU_MONITOR_64LEV:
return opOUT64_A_A (opcode);
case CCPU_MONITOR_WOWCOL:
return opOUTWW_A_A (opcode);
default:
return opOUTbi_A_A (opcode);
}
}
CINESTATE tOUT_B_BB (int opcode)
{
switch (ccpu_monitor)
{
case CCPU_MONITOR_16LEV:
return opOUT16_B_BB (opcode);
case CCPU_MONITOR_64LEV:
return opOUT64_B_BB (opcode);
case CCPU_MONITOR_WOWCOL:
return opOUTWW_B_BB (opcode);
default:
return opOUTbi_B_BB (opcode);
}
}
/* Reset C-CPU registers, flags, etc to default starting values
*/
void cineReset(void)
{
/* zero registers */
register_PC = 0;
register_A = 0;
register_B = 0;
register_I = 0;
register_J = 0;
register_P = 0;
FromX = 0;
FromY = 0;
register_T = 0;
/* zero flags */
flag_C = 0;
/* reset state */
state = state_A;
/* reset RAM */
memset(ram, 0, sizeof(ram));
/* reset internal state */
cmp_old = 0;
cmp_new = 0;
SETA0 (0);
}
void cineSetJMI(int j)
{
ccpu_jmi_dip = j;
/*
if (ccpu_jmi_dip)
fprintf (stderr, "CCPU JMI Set: Yes.\n");
else
fprintf (stderr, "CCPU JMI Set: No.\n");
*/
}
void cineSetMSize(int m)
{
ccpu_msize = m;
/*
switch (m)
{
case 0:
fprintf (stderr, "CCPU Address Space: 4k\n");
break;
case 1:
fprintf (stderr, "CCPU Address Space: 8k\n");
break;
case 2:
fprintf (stderr, "CCPU Address Space: 16k\n");
break;
case 3:
fprintf (stderr, "CCPU Address Space: 32k\n");
break;
default:
fprintf (stderr, "CCPU Address Space: Error\n");
break;
}
*/
}
void cineSetMonitor(int m)
{
ccpu_monitor = m;
/*
switch (m)
{
case 1:
fprintf (stderr, "CCPU Monitor: 16-colour\n");
break;
case 2:
fprintf (stderr, "CCPU Monitor: 64-colour\n");
break;
case 3:
fprintf (stderr, "CCPU Monitor: War-of-the-Worlds-colour\n");
break;
default:
fprintf (stderr, "CCPU Monitor: bi-level-display\n");
break;
}
*/
}
void cSetContext(CONTEXTCCPU *c)
{
cmp_old = c -> accVal;
cmp_new = c -> cmpVal;
SETA0 (c -> pa0);
flag_C = c -> cFlag;
register_PC = c -> eRegPC;
register_A = c -> eRegA;
register_B = c -> eRegB;
register_I = c -> eRegI;
register_J = c -> eRegJ;
register_P = c -> eRegP;
state = (CINESTATE)c -> eCState;
}
void cGetContext(CONTEXTCCPU *c)
{
c -> accVal = cmp_old;
c -> cmpVal = cmp_new;
c -> pa0 = GETA0();
c -> cFlag = GETFC();
c -> eRegPC = register_PC;
c -> eRegA = register_A;
c -> eRegB = register_B;
c -> eRegI = register_I;
c -> eRegJ = register_J;
c -> eRegP = register_P;
c -> eCState = state;
}