/****************************************************************************/
/*              Beebem - (c) David Alan Gilbert 1994                        */
/*              ------------------------------------                        */
/* This program may be distributed freely within the following restrictions:*/
/*                                                                          */
/* 1) You may not charge for this program or for any part of it.            */
/* 2) This copyright message must be distributed with all copies.           */
/* 3) This program must be distributed complete with source code.  Binary   */
/*    only distribution is not permitted.                                   */
/* 4) The author offers no warrenties, or guarentees etc. - you use it at   */
/*    your own risk.  If it messes something up or destroys your computer   */
/*    thats YOUR problem.                                                   */
/* 5) You may use small sections of code from this program in your own      */
/*    applications - but you must acknowledge its use.  If you plan to use  */
/*    large sections then please ask the author.                            */
/*                                                                          */
/* If you do not agree with any of the above then please do not use this    */
/* program.                                                                 */
/* Please report any problems to the author at gilbertd@cs.man.ac.uk        */
/****************************************************************************/
/* 6502 core - 6502 emulator core - David Alan Gilbert 16/10/94 */
//
//
//    4 Feb 97 MHG all opcodes supported
//
//
#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>

#include "6502core.h"
#include "beebmem.h"
#include "disc8271.h"
#include "sysvia.h"
#include "uservia.h"
#include "video.h"
#include "sound.h"


extern int DumpAfterEach;
void	do_sound(void);

void	check_op(int a);



CycleCountT TotalCycles=0;

static int ProgramCounter;
static int Accumulator,XReg,YReg;
static unsigned char StackReg,PSR;



#define		AC	Accumulator
#define		XR	XReg
#define		YR	YReg
#define		SET_SIGN(src) ( ((src)&0x80) ? PSR|=FlagN:PSR&=~FlagN)
#define		SET_ZERO(src) ( ((src)==0) ? PSR|=FlagZ:PSR&=~FlagZ)
#define		SET_CARRY(src) ( (src) ? PSR|=FlagC:PSR&=~FlagC)
#define		SET_OVERFLOW(src) ( (src) ? PSR|=FlagV:PSR&=~FlagV)

#define 	IF_SIGN()	(PSR & flagN)
#define 	IF_ZERO()	(PSR & FlagZ)
#define 	IF_CARRY()	(PSR & FlagC)
#define 	IF_DECIMAL() (PSR & FlagD)

#define		STORE(a,b)			BEEBWRITEMEM_FAST(a,b)
#define		LOAD(a)				BEEBREADMEM_FAST(a)

#define		SP 			StackReg



unsigned char intStatus=0; /* bit set (nums in IRQ_Nums) if interrupt being caused */
unsigned char NMIStatus=0; /* bit set (nums in NMI_Nums) if NMI being caused */
unsigned int NMILock=0; /* Well I think NMI's are maskable - to stop repeated NMI's - the lock is released when an RTI is done */

typedef int int16;

void	u_stoshr (unsigned int val, int16 address, unsigned int index)
{
  val &= (((address >> 8) + 1) & 0xff);
  if (((address & 0xff) + index) > 0xff)
    address = val;
  STORE ((address + index), val);
}

/* Stats */
int Stats[256];

enum PSRFlags {
  FlagC=1,
  FlagZ=2,
  FlagI=4,
  FlagD=8,
  FlagB=16,
  FlagV=64,
  FlagN=128
};

/* Note how GETCFLAG is special since being bit 0 we don't need to test it to get a clean 0/1 */
#define GETCFLAG ((PSR & FlagC))
#define GETZFLAG ((PSR & FlagZ)>0)
#define GETIFLAG ((PSR & FlagI)>0)
#define GETDFLAG ((PSR & FlagD)>0)
#define GETBFLAG ((PSR & FlagB)>0)
#define GETVFLAG ((PSR & FlagV)>0)
#define GETNFLAG ((PSR & FlagN)>0)


/* Types for internal function arrays */
typedef void (*InstrHandlerFuncType)(int16 Operand);
typedef int16 (*AddrModeHandlerFuncType)(int WantsAddr);

static int CyclesTable[]={
  7,6,0,0,0,3,5,0,3,2,2,0,0,4,6,0, /* 0 */
  2,5,0,0,0,4,6,0,2,4,0,0,0,4,7,0, /* 1 */
  6,6,0,0,3,3,5,0,4,2,2,0,4,4,6,0, /* 2 */
  2,5,0,0,0,4,6,0,2,4,0,0,0,4,7,0, /* 3 */
  6,6,0,0,0,3,5,0,3,2,2,0,3,4,6,0, /* 4 */
  2,5,0,0,0,4,6,0,2,4,0,0,0,4,7,0, /* 5 */
  6,6,0,0,0,3,5,0,4,2,2,0,5,4,6,0, /* 6 */
  2,5,0,0,0,4,6,0,2,4,0,0,0,4,7,0, /* 7 */
  0,6,0,0,3,3,3,0,2,0,2,0,4,4,4,0, /* 8 */
  2,6,0,0,4,4,4,0,2,5,2,0,0,5,0,0, /* 9 */
  2,6,2,0,3,3,3,0,2,2,2,0,4,4,4,0, /* a */
  2,5,0,0,4,4,4,0,2,4,2,0,4,4,4,0, /* b */
  2,6,0,0,3,3,5,0,2,2,2,0,4,4,6,0, /* c */
  2,5,0,0,0,4,6,0,2,4,0,0,0,4,7,0, /* d */
  2,6,0,0,3,3,5,0,2,2,2,0,4,4,6,0, /* e */
  2,5,0,0,0,4,6,0,2,4,0,0,0,4,7,0  /* f */
}; /* CyclesTable */

/* The number of cycles to be used by the current instruction - exported to
   allow fernangling by memory subsystem */
unsigned int Cycles;

/* A macro to speed up writes - uses a local variable called 'tmpaddr' */
#define FASTWRITE(addr,val) tmpaddr=addr; if (tmpaddr<0x8000) BEEBWRITEMEM_DIRECT(tmpaddr,val) else BeebWriteMem(tmpaddr,val);

/* Get a two byte address from the program counter, and then post inc the program counter */
#define GETTWOBYTEFROMPC(var) \
  var=WholeRam[ProgramCounter]; \
  var|=(WholeRam[ProgramCounter+1]<<8); \
  ProgramCounter+=2;

/*----------------------------------------------------------------------------*/
inline int SignExtendByte(signed char in) {
  /*if (in & 0x80) return(in | 0xffffff00); else return(in); */
  /* I think this should sign extend by virtue of the casts - gcc does anyway - the code
  above will definitly do the trick */
  return((int)in);
} /* SignExtendByte */

/*----------------------------------------------------------------------------*/
/* Set the Z flag if 'in' is 0, and N if bit 7 is set - leave all other bits  */
/* untouched.                                                                 */
static void SetPSRZN(const unsigned char in) {
  PSR&=~(FlagZ | FlagN);
  PSR|=((in==0)<<1) | (in & 128);
}; /* SetPSRZN */

/*----------------------------------------------------------------------------*/
/* Note: n is 128 for true - not 1                                            */
static void SetPSR(int mask,int c,int z,int i,int d,int b, int v, int n) {
  PSR&=~mask;
  PSR|=c | (z<<1) | (i<<2) | (d<<3) | (b<<4) | (v<<6) | n;
} /* SetPSR */

/*----------------------------------------------------------------------------*/
/* NOTE!!!!! n is 128 or 0 - not 1 or 0                                       */
static void SetPSRCZN(int c,int z, int n) {
  PSR&=~(FlagC | FlagZ | FlagN);
  PSR|=c | (z<<1) | n;
} /* SetPSRCZN */

/*----------------------------------------------------------------------------*/
void DumpRegs(void) {
  static char FlagNames[]="CZIDB-VNczidb-vn";
  int FlagNum;

  fprintf(stderr,"  PC=0x%x A=0x%x X=0x%x Y=0x%x S=0x%x PSR=0x%x=",
    ProgramCounter,Accumulator,XReg,YReg,StackReg,PSR);
  for(FlagNum=0;FlagNum<8;FlagNum++)
    fputc(FlagNames[FlagNum+8*((PSR & (1<<FlagNum))==0)],stderr);
  fputc('\n',stderr);
} /* DumpRegs */

/*----------------------------------------------------------------------------*/
static void Push(unsigned char ToPush) {
  BEEBWRITEMEM_DIRECT(0x100+StackReg,ToPush);
  StackReg--;
} /* Push */

/*----------------------------------------------------------------------------*/
static unsigned char Pop(void) {
  StackReg++;
  return(WholeRam[0x100+StackReg]);
} /* Pop */

/*----------------------------------------------------------------------------*/
static void PushWord(int16 topush) {
  Push((topush>>8) & 255);
  Push(topush & 255);
} /* PushWord */

/*----------------------------------------------------------------------------*/
static int16 PopWord() {
  int16 RetValue;

  RetValue=Pop();
  RetValue|=(Pop()<<8);
  return(RetValue);
} /* PopWord */

/*----------------------------------------------------------------------------*/
/* Sets 2^8 result for carry */
static int16 BCDAdd(int16 in1,int16 in2) {
  int16 result,hn;
  int WasCarried=((in1 | in2) & 256)>0;
  int TmpCarry=0;
  result=(in1 & 0xf)+(in2 & 0xf);
  if (result>9) {
    result&=0xf;
    result+=6;
    result&=0xf;
    TmpCarry=1;
  }
  hn=(in1 &0xf0)+(in2 &0xf0)+(TmpCarry?0x10:0);
  if (hn>0x9f) {
    hn&=0xf0;
    hn+=0x60;
    hn&=0xf0;
    WasCarried|=1;
  }
  return(result | hn | (WasCarried*256));
} /* BCDAdd */

/*----------------------------------------------------------------------------*/
/* Sets 2^8 result for borrow */
static int16 BCDSubtract(int16 in1,int16 in2) {
  int16 result,hn;
  int WasBorrowed=((in1 | in2) & 256)>0;
  int TmpBorrow=0;
  result=(in1 & 0xf)-(in2 & 0xf);
  if (result<0) {
    result&=0xf;
    result-=6;
    result&=0xf;
    TmpBorrow=1;
  }
  hn=(in1 &0xf0)-(in2 &0xf0)-(TmpBorrow?0x10:0);
  if (hn <0) {
    hn&=0xf0;
    hn-=0x60;
    hn&=0xf0;
    WasBorrowed|=1;
  }
  return(result | hn | (WasBorrowed*256));
} /* BCDSubtract */

/*-------------------------------------------------------------------------*/
/* Relative addressing mode handler                                        */
static int16 RelAddrModeHandler_Data(void) {
  int EffectiveAddress;

  /* For branches - is this correct - i.e. is the program counter incremented
     at the correct time? */
  EffectiveAddress=SignExtendByte((signed char)WholeRam[ProgramCounter++]);
  EffectiveAddress+=ProgramCounter;

  return(EffectiveAddress);
} /* RelAddrModeHandler */

/*----------------------------------------------------------------------------*/
static void ADCInstrHandler(int16 operand) {
  /* NOTE! Not sure about C and V flags */
  int TmpResultV,TmpResultC;
  if (!GETDFLAG) {
    TmpResultC=Accumulator+operand+GETCFLAG;
    TmpResultV=(signed char)Accumulator+(signed char)operand+GETCFLAG;
    Accumulator=TmpResultC & 255;
    SetPSR(FlagC | FlagZ | FlagV | FlagN, (TmpResultC & 256)>0,Accumulator==0,0,0,0,((Accumulator & 128)>0) ^ (TmpResultV<0),(Accumulator & 128));
  } else {
    TmpResultC=BCDAdd(Accumulator,operand);
    TmpResultC=BCDAdd(TmpResultC,GETCFLAG);
    Accumulator=TmpResultC & 255;
    SetPSR(FlagC | FlagZ | FlagV | FlagN, (TmpResultC & 256)>0,Accumulator==0,0,0,0,((Accumulator & 128)>0) ^ ((TmpResultC & 256)>0),(Accumulator & 128));
  }
} /* ADCInstrHandler */

/*----------------------------------------------------------------------------*/
static void ANDInstrHandler(int16 operand) {
  Accumulator=Accumulator & operand;
  PSR&=~(FlagZ | FlagN);
  PSR|=((Accumulator==0)<<1) | (Accumulator & 128);
} /* ANDInstrHandler */

static void ASLInstrHandler(int16 address) {
  unsigned char oldVal,newVal;
  oldVal=BEEBREADMEM_FAST(address);
  newVal=(((unsigned int)oldVal)<<1);
  BEEBWRITEMEM_FAST(address,newVal);
  SetPSRCZN((oldVal & 128)>0, newVal==0,newVal & 128);
} /* ASLInstrHandler */

static void ASLORAInstrHandler(int16 address)
{
  unsigned char oldVal,newVal;
  oldVal=BEEBREADMEM_FAST(address);
  newVal=(((unsigned int)oldVal)<<1);
  newVal|=Accumulator;
  BEEBWRITEMEM_FAST(address,newVal);
  SetPSRCZN((oldVal & 128)>0, newVal==0,newVal & 128);
} /* ASLInstrHandler */

static void ASLInstrHandler_Acc(void) {
  unsigned char oldVal,newVal;
  /* Accumulator */
  oldVal=Accumulator;
  Accumulator=newVal=(((unsigned int)Accumulator)<<1);
  SetPSRCZN((oldVal & 128)>0, newVal==0,newVal & 128);
} /* ASLInstrHandler_Acc */

static void BCCInstrHandler(void) {
  if (!GETCFLAG) {
    ProgramCounter=RelAddrModeHandler_Data();
    Cycles++;
  } else ProgramCounter++;
} /* BCCInstrHandler */

static void BCSInstrHandler(void) {
  if (GETCFLAG) {
    ProgramCounter=RelAddrModeHandler_Data();
    Cycles++;
  } else ProgramCounter++;
} /* BCSInstrHandler */

static void BEQInstrHandler(void) {
  if (GETZFLAG) {
    ProgramCounter=RelAddrModeHandler_Data();
    Cycles++;
  } else ProgramCounter++;
} /* BEQInstrHandler */

static void BITInstrHandler(int16 operand) {
  PSR&=~(FlagZ | FlagN | FlagV);
  /* z if result 0, and NV to top bits of operand */
  PSR|=(((Accumulator & operand)==0)<<1) | (operand & 192);
} /* BITInstrHandler */

static void BMIInstrHandler(void) {
  if (GETNFLAG) {
    ProgramCounter=RelAddrModeHandler_Data();
    Cycles++;
  } else ProgramCounter++;
} /* BMIInstrHandler */

static void BNEInstrHandler(void) {
  if (!GETZFLAG) {
    ProgramCounter=RelAddrModeHandler_Data();
    Cycles++;
  } else ProgramCounter++;
} /* BNEInstrHandler */

static void BPLInstrHandler(void) {
  if (!GETNFLAG) {
    ProgramCounter=RelAddrModeHandler_Data();
    Cycles++;
  } else ProgramCounter++;
}; /* BPLInstrHandler */

static void BRKInstrHandler(void) {
  PushWord(ProgramCounter+1);
  SetPSR(FlagB,0,0,0,0,1,0,0); /* Set B before pushing */
  Push(PSR);
  SetPSR(FlagI,0,0,1,0,0,0,0); /* Set I after pushing - see Birnbaum */
  ProgramCounter=BeebReadMem(0xfffe) | (BeebReadMem(0xffff)<<8);
} /* BRKInstrHandler */

static void BVCInstrHandler(void) {
  if (!GETVFLAG) {
    ProgramCounter=RelAddrModeHandler_Data();
    Cycles++;
  } else ProgramCounter++;
} /* BVCInstrHandler */

static void BVSInstrHandler(void) {
  if (GETVFLAG) {
    ProgramCounter=RelAddrModeHandler_Data();
    Cycles++;
  } else ProgramCounter++;
} /* BVSInstrHandler */

static void CMPInstrHandler(int16 operand) {
  /* NOTE! Should we consult D flag ? */
  unsigned char result=Accumulator-operand;
  SetPSRCZN(Accumulator>=operand,Accumulator==operand,result & 128);
} /* CMPInstrHandler */

static void CPXInstrHandler(int16 operand) {
  unsigned char result=(XReg-operand);
  SetPSRCZN(XReg>=operand,XReg==operand,result & 128);
} /* CPXInstrHandler */

static void CPYInstrHandler(int16 operand) {
  unsigned char result=(YReg-operand);
  SetPSRCZN(YReg>=operand,YReg==operand,result & 128);
} /* CPYInstrHandler */

static void DECInstrHandler(int16 address) {
  unsigned char val;

  val=BEEBREADMEM_FAST(address);

  val=(val-1);

  BEEBWRITEMEM_FAST(address,val);
  SetPSRZN(val);
} /* DECInstrHandler */

static void DEXInstrHandler(void) {
  XReg=(XReg-1) & 255;
  SetPSRZN(XReg);
} /* DEXInstrHandler */

static void EORInstrHandler(int16 operand) {
  Accumulator^=operand;
  SetPSRZN(Accumulator);
} /* EORInstrHandler */

static void INCInstrHandler(int16 address) {
  unsigned char val;

  val=BEEBREADMEM_FAST(address);

  val=(val+1) & 255;

  BEEBWRITEMEM_FAST(address,val);
  SetPSRZN(val);
} /* INCInstrHandler */

static void INXInstrHandler(void) {
  XReg+=1;
  XReg&=255;
  SetPSRZN(XReg);
} /* INXInstrHandler */

static void JSRInstrHandler(int16 address) {
  PushWord(ProgramCounter-1);
  ProgramCounter=address;
} /* JSRInstrHandler */

static void LDAInstrHandler(int16 operand) {
  Accumulator=operand;
  SetPSRZN(Accumulator);
} /* LDAInstrHandler */


static void LDXInstrHandler(int16 operand) {
  XReg=operand;
  SetPSRZN(XReg);
} /* LDXInstrHandler */

static void LDYInstrHandler(int16 operand) {
  YReg=operand;
  SetPSRZN(YReg);
} /* LDYInstrHandler */

static void LSRInstrHandler(int16 address) {
  unsigned char oldVal,newVal;
  oldVal=BEEBREADMEM_FAST(address);
  newVal=(((unsigned int)oldVal)>>1);
  BEEBWRITEMEM_FAST(address,newVal);
  SetPSRCZN((oldVal & 1)>0, newVal==0,0);
} /* LSRInstrHandler */

static void LSRInstrHandler_Acc(void) {
  unsigned char oldVal,newVal;
  /* Accumulator */
  oldVal=Accumulator;
  Accumulator=newVal=(((unsigned int)Accumulator)>>1) & 255;
  SetPSRCZN((oldVal & 1)>0, newVal==0,0);
} /* LSRInstrHandler_Acc */

static void ORAInstrHandler(int16 operand) {
  Accumulator=Accumulator | operand;
  SetPSRZN(Accumulator);
} /* ORAInstrHandler */

static void ROLInstrHandler(int16 address) {
  unsigned char oldVal,newVal;

  oldVal=BEEBREADMEM_FAST(address);
  newVal=((unsigned int)oldVal<<1) & 254;
  newVal+=GETCFLAG;
  BEEBWRITEMEM_FAST(address,newVal);
  SetPSRCZN((oldVal & 128)>0,newVal==0,newVal & 128);
} /* ROLInstrHandler */

static void ROLInstrHandler_Acc(void) {
  unsigned char oldVal,newVal;

  oldVal=Accumulator;
  newVal=((unsigned int)oldVal<<1) & 254;
  newVal+=GETCFLAG;
  Accumulator=newVal;
  SetPSRCZN((oldVal & 128)>0,newVal==0,newVal & 128);
} /* ROLInstrHandler_Acc */

static void ROLANDInstrHandler(int16 address) {
  unsigned char oldVal,newVal;

  oldVal=BEEBREADMEM_FAST(address);
  newVal=((unsigned int)oldVal<<1) & 254;
  newVal+=GETCFLAG;
  Accumulator&=newVal;
  BEEBWRITEMEM_FAST(address,newVal);
  newVal=Accumulator;
  SetPSRCZN((oldVal & 128)>0,newVal==0,newVal & 128);
} /* ROLInstrHandler */

static void RORInstrHandler(int16 address) {
  unsigned char oldVal,newVal;

  oldVal=BEEBREADMEM_FAST(address);
  newVal=((unsigned int)oldVal>>1) & 127;
  newVal+=GETCFLAG*128;
  BEEBWRITEMEM_FAST(address,newVal);
  SetPSRCZN(oldVal & 1,newVal==0,newVal & 128);
} /* RORInstrHandler */

static void RORInstrHandler_Acc(void) {
  unsigned char oldVal,newVal;

  oldVal=Accumulator;
  newVal=((unsigned int)oldVal>>1) & 127;
  newVal+=GETCFLAG*128;
  Accumulator=newVal;
  SetPSRCZN(oldVal & 1,newVal==0,newVal & 128);
} /* RORInstrHandler_Acc */

static void SBCInstrHandler(int16 operand) {
  /* NOTE! Not sure about C and V flags */
  int TmpResultV,TmpResultC;
  if (!GETDFLAG) {
    TmpResultV=(signed char)Accumulator-(signed char)operand-(1-GETCFLAG);
    TmpResultC=Accumulator-operand-(1-GETCFLAG);
    Accumulator=TmpResultC & 255;
    SetPSR(FlagC | FlagZ | FlagV | FlagN, TmpResultC>=0,Accumulator==0,0,0,0,
      ((Accumulator & 128)>0) ^ ((TmpResultV & 256)!=0),(Accumulator & 128));
  } else {
    /* BCD subtract - note: V is probably duff*/
    TmpResultC=BCDSubtract(Accumulator,operand);
    if (!GETCFLAG) TmpResultC=BCDSubtract(TmpResultC,0x01);
    Accumulator=TmpResultC & 0xff;
    SetPSR(FlagC | FlagZ | FlagV | FlagN, (TmpResultC & 256)==0, Accumulator==0,
    0,0,0,((Accumulator & 128)>0) ^ ((TmpResultC & 256)>0),
    Accumulator & 0x80);
  }
} /* SBCInstrHandler */

static void STXInstrHandler(int16 address) {
  BEEBWRITEMEM_FAST(address,XReg);
} /* STXInstrHandler */

static void STYInstrHandler(int16 address) {
  BEEBWRITEMEM_FAST(address,YReg);
} /* STYInstrHandler */

void	error(char *t1,char *t2);

static void BadInstrHandler(unsigned char a)
{
	char str[128];
#if 0
	printf("bad opcode %x\n",a);
  fprintf(stderr,"Bad instruction handler called:\n");
  DumpRegs();
  fprintf(stderr,"Dumping main memory\n");
  beebmem_dumpstate();
  abort();
#endif
	sprintf(str,"Unreconised 6502 opcode: 0x%x\n",a);
	error(str,"");
} /* BadInstrHandler */

/*-------------------------------------------------------------------------*/
/* Absolute  addressing mode handler                                       */
static int16 AbsAddrModeHandler_Data(void) {
  int FullAddress;

  /* Get the address from after the instruction */

  GETTWOBYTEFROMPC(FullAddress)

  /* And then read it */
  return(BEEBREADMEM_FAST(FullAddress));
} /* AbsAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Absolute  addressing mode handler                                       */
static int16 AbsAddrModeHandler_Address(void) {
  int FullAddress;

  /* Get the address from after the instruction */
  GETTWOBYTEFROMPC(FullAddress)

  /* And then read it */
  return(FullAddress);
} /* AbsAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Zero page addressing mode handler                                       */
static int16 ZeroPgAddrModeHandler_Address(void) {
  return(WholeRam[ProgramCounter++]);
} /* ZeroPgAddrModeHandler_Address */

/*-------------------------------------------------------------------------*/
/* Indexed with X preinc addressing mode handler                           */
static int16 IndXAddrModeHandler_Data(void) {
  unsigned char ZeroPageAddress;
  int EffectiveAddress;

  ZeroPageAddress=(WholeRam[ProgramCounter++]+XReg) & 255;

  EffectiveAddress=WholeRam[ZeroPageAddress] | (WholeRam[ZeroPageAddress+1]<<8);
  return(BEEBREADMEM_FAST(EffectiveAddress));
} /* IndXAddrModeHandler_Data */

/*-------------------------------------------------------------------------*/
/* Indexed with X preinc addressing mode handler                           */
static int16 IndXAddrModeHandler_Address(void) {
  unsigned char ZeroPageAddress;
  int EffectiveAddress;

  ZeroPageAddress=(WholeRam[ProgramCounter++]+XReg) & 255;

  EffectiveAddress=WholeRam[ZeroPageAddress] | (WholeRam[ZeroPageAddress+1]<<8);
  return(EffectiveAddress);
} /* IndXAddrModeHandler_Address */

/*-------------------------------------------------------------------------*/
/* Indexed with Y postinc addressing mode handler                          */
static int16 IndYAddrModeHandler_Data(void) {
  int EffectiveAddress;
  unsigned char ZPAddr=WholeRam[ProgramCounter++];
  EffectiveAddress=WholeRam[ZPAddr]+YReg;
  EffectiveAddress+=(WholeRam[ZPAddr+1]<<8);

  return(BEEBREADMEM_FAST(EffectiveAddress));
} /* IndYAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Indexed with Y postinc addressing mode handler                          */
static int16 IndYAddrModeHandler_Address(void) {
  int EffectiveAddress;
  unsigned char ZPAddr=WholeRam[ProgramCounter++];
  EffectiveAddress=WholeRam[ZPAddr]+YReg;
  EffectiveAddress+=(WholeRam[ZPAddr+1]<<8);

  return(EffectiveAddress);
} /* IndYAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Zero page wih X offset addressing mode handler                          */
static int16 ZeroPgXAddrModeHandler_Data(void) {
  int EffectiveAddress;
  EffectiveAddress=(WholeRam[ProgramCounter++]+XReg) & 255;
  return(WholeRam[EffectiveAddress]);
} /* ZeroPgXAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Zero page wih X offset addressing mode handler                          */
static int16 ZeroPgXAddrModeHandler_Address(void) {
  int EffectiveAddress;
  EffectiveAddress=(WholeRam[ProgramCounter++]+XReg) & 255;
  return(EffectiveAddress);
} /* ZeroPgXAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Absolute with X offset addressing mode handler                          */
static int16 AbsXAddrModeHandler_Data(void) {
  int EffectiveAddress;
  GETTWOBYTEFROMPC(EffectiveAddress);
  EffectiveAddress+=XReg;
  EffectiveAddress&=0xffff;

  return(BEEBREADMEM_FAST(EffectiveAddress));
} /* AbsXAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Absolute with X offset addressing mode handler                          */
static int16 AbsXAddrModeHandler_Address(void) {
  int EffectiveAddress;
  GETTWOBYTEFROMPC(EffectiveAddress)
  EffectiveAddress+=XReg;
  EffectiveAddress&=0xffff;

  return(EffectiveAddress);
} /* AbsXAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Absolute with Y offset addressing mode handler                          */
static int16 AbsYAddrModeHandler_Data(void) {
  int EffectiveAddress;
  GETTWOBYTEFROMPC(EffectiveAddress)
  EffectiveAddress+=YReg;

  return(BEEBREADMEM_FAST(EffectiveAddress));
} /* AbsYAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Absolute with Y offset addressing mode handler                          */
static int16 AbsYAddrModeHandler_Address(void) {
  int EffectiveAddress;
  GETTWOBYTEFROMPC(EffectiveAddress)
  EffectiveAddress+=YReg;

  return(EffectiveAddress);
} /* AbsYAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Indirect addressing mode handler                                        */
static int16 IndAddrModeHandler_Address(void) {
  /* For jump indirect only */
  int VectorLocation;
  int EffectiveAddress;

  GETTWOBYTEFROMPC(VectorLocation)

  EffectiveAddress=BEEBREADMEM_FAST(VectorLocation);
  EffectiveAddress|=BEEBREADMEM_FAST(VectorLocation+1) << 8;

  return(EffectiveAddress);
} /* IndAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Zero page with Y offset addressing mode handler                         */
static int16 ZeroPgYAddrModeHandler_Data(void) {
  int EffectiveAddress;
  EffectiveAddress=(WholeRam[ProgramCounter++]+YReg) & 255;
  return(WholeRam[EffectiveAddress]);
} /* ZeroPgYAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Zero page with Y offset addressing mode handler                         */
static int16 ZeroPgYAddrModeHandler_Address(void) {
  int EffectiveAddress;
  EffectiveAddress=(WholeRam[ProgramCounter++]+YReg) & 255;
  return(EffectiveAddress);
} /* ZeroPgYAddrModeHandler */

/*-------------------------------------------------------------------------*/
/* Initialise 6502core                                                     */
void Init6502core(void) {
  ProgramCounter=BeebReadMem(0xfffc) | (BeebReadMem(0xfffd)<<8);
  Accumulator=XReg=YReg=0; /* For consistancy of execution */
  StackReg=0xff; /* Initial value ? */
  PSR=FlagI; /* Interrupts off for starters */

  intStatus=0;
  NMIStatus=0;
  NMILock=0;
} /* Init6502core */

#include "via.h"

/*-------------------------------------------------------------------------*/
void DoInterrupt(void) {
  PushWord(ProgramCounter);
  Push(PSR & ~FlagB);
  ProgramCounter=BeebReadMem(0xfffe) | (BeebReadMem(0xffff)<<8);
  SetPSR(FlagI,0,0,1,0,0,0,0);
} /* DoInterrupt */

/*-------------------------------------------------------------------------*/
void DoNMI(void) {
  /*cerr << "Doing NMI\n"; */
  NMILock=1;
  PushWord(ProgramCounter);
  Push(PSR);
  ProgramCounter=BeebReadMem(0xfffa) | (BeebReadMem(0xfffb)<<8);
  SetPSR(FlagI,0,0,1,0,0,0,0); /* Normal interrupts should be disabled during NMI ? */
} /* DoNMI */


static void ANCInstrHandler(int16 operand)
{
  unsigned char oldval;

  oldval=operand & Accumulator;
  Accumulator=oldval;
  SetPSRZN(Accumulator);
} /* LDAInstrHandler */

//
// BAD OPCODE JAMS THE MACHINE
//
static void STOPi()
{
}

//
// ANC:	LDA+AND
//	A = ( A & #data)
// 0B
// IMM
//
static void ANCi(int16 data)
{
  Accumulator=data & Accumulator;
  SetPSRZN(Accumulator);
}

// NO OPERATION
static void NOPi(int16 a)
{
}

//
// 82,c2,e2
//
static void NOPSi(int16 a)
{
}

//
// RMW - ASL+ORA - SHIFT & OR with Accum
// 03,	07,	0f, 	13,  	17, 	1b,  	1f
// INDX,	ZP,	ABS,	INDY,	ZPX,	ABSY,	ABSX
//
static void SLOi(int16 address)
{
	/* src = asl(src); AC = ora(src); */
  unsigned char oldVal,newVal;

  oldVal=BEEBREADMEM_FAST(address);      // LOAD val from adress
  newVal=(((unsigned int)oldVal)<<1);    //

//  newVal|=Accumulator;                   // ORA
  Accumulator|=newVal;                   // ORA


  BEEBWRITEMEM_FAST(address,newVal);     // STORE VALUE
  SetPSRCZN((oldVal & 128)>0, newVal==0,newVal & 128);
}


//
//	ASR:
//
//	A= (A & #data) >> 1
//
//	4B
// IMM
//
static void ASRi(int16 data)
{
	unsigned char oldVal,newVal;
  	oldVal=Accumulator;
	newVal=oldVal & data;
  	newVal=(((unsigned int)newVal)>>1);
	Accumulator=newVal;
  	SetPSRCZN((oldVal & 1)>0, newVal==0,0);
}

//
//	RLA:	ROL + AND
//
//	23,	27,	2F,	33,	37,	3B,	3F
// INDX,	ZP,	ABS,	INDY,	ZPX,	ABSY,	ABSX
//
static void RLAi(int16 address)
{
  	/* src = rol(src); AC = and(src); */
  unsigned char oldVal,newVal;
  oldVal=BEEBREADMEM_FAST(address);      // LOAD val from adress
  newVal=((unsigned int)oldVal<<1) & 254;
  newVal+=GETCFLAG;

  Accumulator&=newVal;
//  newVal&=Accumulator;


  BEEBWRITEMEM_FAST(address,newVal);     // STORE VALUE
  SetPSRCZN((oldVal & 128)>0,newVal==0,newVal & 128);
}

//
//	SRE:	 LSR + EOR
//
//	43,	47,	4F,	53,	57,	5B,	5F
//	INDX,	ZP,	ABS,	INDY,	ZPX,	ABSY,	ABSX
//
static void SREi(int16 address)
{
	/* src = lsr(src); AC = eor(src); */
  unsigned char oldVal,newVal;

  oldVal=BEEBREADMEM_FAST(address);
  newVal=(((unsigned int)oldVal)>>1);
  newVal^=Accumulator;
  BEEBWRITEMEM_FAST(address,newVal);
  SetPSRCZN((oldVal & 1)>0, newVal==0,0);
}


//
// RRA:	ROR+ADC
//
//	INDX,	ZP,	ABS,	INDY,	ZPX,	ABSY,	ABSX
//	63,	67,	6F,	73,	77,	7B,	7F
//
static void RRAi(int16 address)
{
		/* src = ror(src); AC = adc(src);
		 * the real operation discovered by msmakela
		 * ADC only does the BCD fixup */
  unsigned char oldVal,newVal;

  oldVal=BEEBREADMEM_FAST(address);
  newVal=((unsigned int)oldVal>>1) & 127;
  newVal+=GETCFLAG*128;
  BEEBWRITEMEM_FAST(address,newVal);
  SetPSRCZN(oldVal & 1,newVal==0,newVal & 128);
}
//
//	ARR:	AND+ROR
//
// 6B
// IMM
//
static void ARRi(int16 data)
{
	/* src= (A & #data)  A=(src>>1) */
  unsigned char oldVal,newVal;
  oldVal=Accumulator & data;
  newVal=((unsigned int)oldVal>>1) & 127;
  newVal+=GETCFLAG*128;
  Accumulator=newVal;
  SetPSRCZN(oldVal & 1,newVal==0,newVal & 128);
}
//
//	ANE:
//	A= (A | EE) & X & #data
//	8B
// IMM
//
static void ANEi(int16 data)
{
  Accumulator=(Accumulator | 0xEE) & XReg & data;
  SetPSRZN(Accumulator);
}

//
//	Store X and A
//	83,87,8f,97
//
static void SAXi(int16 address)
{
  	unsigned char oldVal,newVal;
	newVal=Accumulator & XReg;
  	BEEBWRITEMEM_FAST(address,newVal);
}
//
// 93,	9f
// INDY,	ABSY
// STORE A & X
//
static void SHAi(int16 address)
{
		int16 src = (AC & XR);
		u_stoshr (src, address, YR);;
}

//
// 9B
// SP = A & X
//
static void SHSi()
{
		int16 src = (AC & XR);
		SP = src; /* SHS */ ;
}

//
// 9C
//
static void SHYi(int16 p2)
{
		unsigned int src = YR;
		u_stoshr (src, p2, XR);;
}
//
// 9E
//
static void SHXi(int16 p2)
{
		unsigned int src = XR;
		u_stoshr (src, p2, YR);;
}
//
//	LOAD
// a3,a7,af,b3,b7,bf
//
static void LAXi(int16 src)
{

		SET_SIGN (src);
		SET_ZERO (src);

		AC = XR = (src);;
}
//
// LOAD
// bb
//
static void LASi(int16 p2)
{
		unsigned int src = (SP & p2);
		SET_SIGN (src);
		SET_ZERO (src);
		AC = XR = SP = (src);
}
//
//
//c3,c7,cf,d3,d7,db,df
//
static void DCPi(int16 p2)
{
		unsigned int src = LOAD (p2);

		/* cmp(--src & 0xff));  */

		src = (src - 1) & 0xff;		/* DEC+CMP */
		SET_CARRY (AC >= src);
		SET_SIGN (AC - src);
		SET_ZERO (AC != src);

		STORE (p2, (src));;
}
//
//	Load X and A with A & #data
// ab
//
static void LXAi(int16 p1)
{
	 	unsigned int src = (AC & p1);

		SET_SIGN (src);
		SET_ZERO (src);

		AC = XR = (src);;
}
//
//
// cb
// LOAD
static void SBXi(int16 src)
{

		src = (AC & XR) - src;	/* Carry is ignored (CMP) */
		/* Overflow flag may be affected */
		SET_CARRY (src < 0x100);

		src &= 0xff;	/* No decimal mode */
		SET_SIGN (src);
		SET_ZERO (src);

		XR = (src);;

}
//
// eb
//
static void SBCi(int16 data)
{
	SBCInstrHandler(data);
}
// ISB:
//
// INC + SBC
// e3,e7,ef,f3,f7,fb,ff
// RMW
//
static void ISBi(int16 p2)
{
		unsigned int src = LOAD (p2);
		unsigned int temp;


		/* src = ++src & 0xff; AC = sbc(src); */

		src = ((src + 1) & 0xff);	/* INC+SBC */

		temp = AC - src - (IF_CARRY ()? 0 : 1);

		SET_SIGN (temp);
		SET_ZERO (temp & 0xff);		/* Sign and Zero are invalid in decimal mode */

		SET_OVERFLOW (((AC ^ temp) & 0x80) && ((AC ^ src) & 0x80));

		if (IF_DECIMAL ())
		  {
		    if (((AC & 0xf) + (IF_CARRY ()? 1 : 0)) < (src & 0xf))
		      temp -= 6;
		    if (temp > 0x99)
		      temp -= 0x60;
		  }
		SET_CARRY (temp < 0x100);

		AC = temp;
		/* src saved */
		STORE (p2, (src));;
}


#define	IMPLIED   	0
#define	IMMEDIATE	WholeRam[ProgramCounter++]
#define	ZP				ZeroPgAddrModeHandler_Address()
#define	ZPX			ZeroPgXAddrModeHandler_Address()
#define	ZPY			ZeroPgXAddrModeHandler_Address()
#define	ABS			AbsAddrModeHandler_Address()
#define	ABSX			AbsXAddrModeHandler_Address()
#define	ABSY			AbsYAddrModeHandler_Address()
#define	INDX        IndXAddrModeHandler_Address()
#define	INDY      	IndYAddrModeHandler_Address()

/*-------------------------------------------------------------------------*/
/* Execute one 6502 instruction, move program counter on                   */
void Exec6502Instruction(void) {
  static int CurrentInstruction;
  static int tmpaddr;
  static int OldNMIStatus;

  int loop;
  for(loop=0;loop<512;loop++) {

  /* Read an instruction and post inc program couter */
  CurrentInstruction=WholeRam[ProgramCounter++];

  /*cout << "Fetch at " << hex << (ProgramCounter-1) << " giving 0x" << CurrentInstruction << dec << "\n"; */
  Cycles=CyclesTable[CurrentInstruction];

 // check_op(CurrentInstruction);
//  if (Cycles==0)
//  {
// 		printf("[%x]op 0x%x %d\n",ProgramCounter,CurrentInstruction,CurrentInstruction);
//		Cycles=4;
//  }

  /*Stats[CurrentInstruction]++; */
  switch (CurrentInstruction) {
//-------------------------------------------------------------------------------------------
    case 0x00:
      BRKInstrHandler();
      break;
    case 0x01:
      ORAInstrHandler(IndXAddrModeHandler_Data());
      break;
    case 0x02:  		//illegal
		STOPi();
      break;
	case 3:			// MHG
	   SLOi(INDX);
		break;
	case 4:			// MHG
	   NOPi(ZP);
		break;
   case 0x05:
      ORAInstrHandler(WholeRam[WholeRam[ProgramCounter++]]/*zp */);
      break;
    case 0x06:
      ASLInstrHandler(ZeroPgAddrModeHandler_Address());
      break;
    case 0x07: 	// MHG
		SLOi(ZP);
      break;
    case 0x08:
      Push(PSR); /* PHP */
      break;
    case 0x09:
      ORAInstrHandler(WholeRam[ProgramCounter++]); /* immediate */
      break;
    case 0x0a:
      ASLInstrHandler_Acc();
      break;
    case 0x0b:  	// MHG
		ANCi(IMMEDIATE);
		break;
    case 0x0c: 	// MHG
	  	NOPi(ABS);
		break;
    case 0x0d:
      ORAInstrHandler(AbsAddrModeHandler_Data());
      break;
    case 0x0e:
      ASLInstrHandler(AbsAddrModeHandler_Address());
      break;
    case 0x0f:		//MHG SLO  SLO $1234
      SLOi(ABS);
		break;
//-------------------------------------------------------------------------------------------
    case 0x10:
      BPLInstrHandler();
      break;
    case 0x11:
      ORAInstrHandler(IndYAddrModeHandler_Data());
      break;
    case 0x12:
		STOPi();
      break;
	case 0x13:	// MHG SLO
		SLOi(INDY);
		break;
	case 0x14:	// MHG NOP
		NOPi(ZPX);
		break;
    case 0x15:
      ORAInstrHandler(ZeroPgXAddrModeHandler_Data());
      break;
    case 0x16:
      ASLInstrHandler(ZeroPgXAddrModeHandler_Address());
      break;
    case 0x17: // MHG SLO
		SLOi(ZPX);
		break;
    case 0x18:
      PSR&=255-FlagC; /* CLC */
      break;
    case 0x19:
      ORAInstrHandler(AbsYAddrModeHandler_Data());
      break;
    case 0x1A:  // MHG NOP
		NOPi(IMPLIED);
		break;
    case 0x1b:  // MHG SLO
		SLOi(ABSY);
		break;
    case 0x1c:  // MHG NOP
		NOPi(ABSX);
		break;
    case 0x1d:
      ORAInstrHandler(AbsXAddrModeHandler_Data());
      break;
    case 0x1e:
      ASLInstrHandler(AbsXAddrModeHandler_Address());
      break;
    case 0x1f:  // MHG SLO
		SLOi(ABSX);
		break;
//-------------------------------------------------------------------------------------------
    case 0x20:
      JSRInstrHandler(AbsAddrModeHandler_Address());
      break;
    case 0x21:
      ANDInstrHandler(IndXAddrModeHandler_Data());
      break;
     case 0x22:  // MHG
	   STOPi();
		break;
     case 0x23:  // MHG
		RLAi(INDX);
		break;
    case 0x24:
      BITInstrHandler(WholeRam[WholeRam[ProgramCounter++]]/*zp */);
      break;
    case 0x25:
      ANDInstrHandler(WholeRam[WholeRam[ProgramCounter++]]/*zp */);
      break;
    case 0x26:
      ROLInstrHandler(ZeroPgAddrModeHandler_Address());
      break;
	case 0x27:
		RLAi(ZP);  	// MHG
		break;
    case 0x28:
      PSR=Pop(); /* PLP */
      break;
    case 0x29:
      ANDInstrHandler(WholeRam[ProgramCounter++]); /* immediate */
      break;
    case 0x2a:
      ROLInstrHandler_Acc();
      break;
   case 0x2b:  // MHG
		ANCi(IMMEDIATE);
		break;
    case 0x2c:
      BITInstrHandler(AbsAddrModeHandler_Data());
      break;
    case 0x2d:
      ANDInstrHandler(AbsAddrModeHandler_Data());
      break;
    case 0x2e:
      ROLInstrHandler(AbsAddrModeHandler_Address());
      break;
   case 0x2f:  // MHG
		RLAi(ABS);
		break;
//-------------------------------------------------------------------------------------------
    case 0x30:
      BMIInstrHandler();
      break;
    case 0x31:
      ANDInstrHandler(IndYAddrModeHandler_Data());
      break;
	 case 0x32:  // MHG
		STOPi();
		break;
	 case 0x33:  // MHG
		RLAi(INDY);
		break;
	 case 0x34:  // MHG
		NOPi(ZPX);
		break;
    case 0x35:
      ANDInstrHandler(ZeroPgXAddrModeHandler_Data());
      break;
    case 0x36:
      ROLInstrHandler(ZeroPgXAddrModeHandler_Address());
      break;
	 case 0x37:  // MHG
		RLAi(ZPX);
		break;
    case 0x38:
      PSR|=FlagC; /* SEC */
      break;
    case 0x39:
      ANDInstrHandler(AbsYAddrModeHandler_Data());
      break;
	 case 0x3a:  // MHG
		NOPi(IMPLIED);
		break;
	 case 0x3b:  // MHG
		RLAi(ABSY);
		break;
	case 0x3c:  // MHG
		NOPi(ABSX);
		break;
    case 0x3d:
      ANDInstrHandler(AbsXAddrModeHandler_Data());
      break;
    case 0x3e:
      ROLInstrHandler(AbsXAddrModeHandler_Address());
      break;
	 case 0x3f: 		///MHG
      RLAi(ABSX);
      break;
//-------------------------------------------------------------------------------------------
    case 0x40:
      PSR=Pop(); /* RTI */
      ProgramCounter=PopWord();
      NMILock=0;
      break;
    case 0x41:
      EORInstrHandler(IndXAddrModeHandler_Data());
      break;
	 case 0x42:  // MHG
		STOPi();
		break;
	 case 0x43:  // MHG
		SREi(INDX);
		break;
	 case 0x44:  // MHG
		NOPi(ZP);
		break;
    case 0x45:
      EORInstrHandler(WholeRam[WholeRam[ProgramCounter++]]/*zp */);
      break;
    case 0x46:
      LSRInstrHandler(ZeroPgAddrModeHandler_Address());
      break;
	 case 0x47:  // MHG
		SREi(ZP);
		break;
    case 0x48:
      Push(Accumulator); /* PHA */
      break;
    case 0x49:
      EORInstrHandler(WholeRam[ProgramCounter++]); /* immediate */
      break;
    case 0x4a:
      LSRInstrHandler_Acc();
      break;
    case 0x4b:  // MHG ASR     A= (A & #imm) >> 1
      ASRi(IMMEDIATE);
      break;
    case 0x4c:
      ProgramCounter=AbsAddrModeHandler_Address(); /* JMP */
      break;
    case 0x4d:
      EORInstrHandler(AbsAddrModeHandler_Data());
      break;
    case 0x4e:
      LSRInstrHandler(AbsAddrModeHandler_Address());
      break;
	 case 0x4f:  // MHG
		SREi(ABS);
		break;

//-------------------------------------------------------------------------------------------
    case 0x50:
      BVCInstrHandler();
      break;
     case 0x51:
      EORInstrHandler(IndYAddrModeHandler_Data());
      break;
	 case 0x52:  // MHG
		STOPi();
		break;
	 case 0x53:  // MHG
		SREi(INDY);
		break;
	 case 0x54:  // MHG
		NOPi(ZPX);
		break;
    case 0x55:
      EORInstrHandler(ZeroPgXAddrModeHandler_Data());
      break;
    case 0x56:
      LSRInstrHandler(ZeroPgXAddrModeHandler_Address());
      break;
	 case 0x57:  // MHG
		SREi(ZPX);
		break;
    case 0x58:
      PSR&=255-FlagI; /* CLI */
      break;
    case 0x59:
      EORInstrHandler(AbsYAddrModeHandler_Data());
      break;
	 case 0x5a:  // MHG
		NOPi(IMPLIED);
		break;
	 case 0x5b:  // MHG
		SREi(ABSY);
		break;
	 case 0x5c:  // MHG
		NOPi(ABSX);
		break;
    case 0x5d:
      EORInstrHandler(AbsXAddrModeHandler_Data());
      break;
    case 0x5e:
      LSRInstrHandler(AbsXAddrModeHandler_Address());
      break;
	 case 0x5f:  // MHG
		SREi(ABSX);
		break;
//-------------------------------------------------------------------------------------------
    case 0x60:
      ProgramCounter=PopWord()+1; /* RTS */
      break;
    case 0x61:
      ADCInstrHandler(IndXAddrModeHandler_Data());
      break;
	 case 0x62:  // MHG
		STOPi();
		break;
	 case 0x63:  // MHG
		RRAi(INDX);
		break;
	 case 0x64:  // MHG
		NOPi(ZPX);
		break;
    case 0x65:
      ADCInstrHandler(WholeRam[WholeRam[ProgramCounter++]]/*zp */);
      break;
    case 0x66:
      RORInstrHandler(ZeroPgAddrModeHandler_Address());
      break;
	 case 0x67:  // MHG
		RRAi(ZP);
		break;
    case 0x68:
      Accumulator=Pop(); /* PLA */
      PSR&=~(FlagZ | FlagN);
      PSR|=((Accumulator==0)<<1) | (Accumulator & 128);
      break;
    case 0x69:
      ADCInstrHandler(WholeRam[ProgramCounter++]); /* immediate */
      break;
    case 0x6a:
      RORInstrHandler_Acc();
      break;
    case 0x6b:
		ARRi(IMMEDIATE);
		break;
    case 0x6c:
      ProgramCounter=IndAddrModeHandler_Address(); /* JMP */
      break;
    case 0x6d:
      ADCInstrHandler(AbsAddrModeHandler_Data());
      break;
    case 0x6e:
      RORInstrHandler(AbsAddrModeHandler_Address());
      break;
	 case 0x6f:  // MHG
		RRAi(ABS);
		break;
//-------------------------------------------------------------------------------------------
   case 0x70:
      BVSInstrHandler();
      break;
    case 0x71:
      ADCInstrHandler(IndYAddrModeHandler_Data());
      break;
	 case 0x72:  // MHG
		STOPi();
		break;
	 case 0x73:  // MHG
		RRAi(INDY);
		break;
	 case 0x74:  // MHG
		NOPi(ZPX);
		break;
    case 0x75:
      ADCInstrHandler(ZeroPgXAddrModeHandler_Data());
      break;
    case 0x76:
      RORInstrHandler(ZeroPgXAddrModeHandler_Address());
      break;
	 case 0x77:  // MHG
		RRAi(ZPX);
		break;
    case 0x78:
      PSR|=FlagI; /* SEI */
      break;
    case 0x79:
      ADCInstrHandler(AbsYAddrModeHandler_Data());
      break;
    case 0x7a:
		NOPi(IMPLIED);
		break;
    case 0x7b:
		RRAi(ABSY);
		break;
    case 0x7c:
		NOPi(ABSX);
		break;
    case 0x7d:
      ADCInstrHandler(AbsXAddrModeHandler_Data());
      break;
    case 0x7e:
      RORInstrHandler(AbsXAddrModeHandler_Address());
      break;
	 case 0x7f:  // MHG
		RRAi(ABSX);
		break;
//-------------------------------------------------------------------------------------------
	 case 0x80:  // MHG
		NOPi(IMMEDIATE);
		break;
    case 0x81:
      FASTWRITE(IndXAddrModeHandler_Address(),Accumulator); /* STA */
      break;
	 case 0x82:  // MHG
		NOPSi(IMMEDIATE);
		break;
	 case 0x83:  // MHG
		SAXi(INDX);
		break;
    case 0x84:
      BEEBWRITEMEM_DIRECT(ZeroPgAddrModeHandler_Address(),YReg);
      break;
    case 0x85:
      BEEBWRITEMEM_DIRECT(ZeroPgAddrModeHandler_Address(),Accumulator); /* STA */
      break;
    case 0x86:
      BEEBWRITEMEM_DIRECT(ZeroPgAddrModeHandler_Address(),XReg);
      break;
    case 0x87: //MHG SAX  stote (a and x)
      SAXi(ZP);
      break;
    case 0x88:
      YReg=(YReg-1) & 255; /* DEY */
      PSR&=~(FlagZ | FlagN);
      PSR|=((YReg==0)<<1) | (YReg & 128);
      break;
    case 0x89:
		NOPi(IMMEDIATE);
		break;
    case 0x8a:
      Accumulator=XReg; /* TXA */
      PSR&=~(FlagZ | FlagN);
      PSR|=((Accumulator==0)<<1) | (Accumulator & 128);
      break;
	 case 0x8b:  // MHG
		ANEi(IMMEDIATE);
		break;
    case 0x8c:
      STYInstrHandler(AbsAddrModeHandler_Address());
      break;
    case 0x8d:
      FASTWRITE(AbsAddrModeHandler_Address(),Accumulator); /* STA */
      break;
    case 0x8e:
      STXInstrHandler(AbsAddrModeHandler_Address());
      break;
	 case 0x8f:  // MHG
		SAXi(ABS);
		break;
//-------------------------------------------------------------------------------------------
   case 0x90:
      BCCInstrHandler();
      break;
    case 0x91:
      FASTWRITE(IndYAddrModeHandler_Address(),Accumulator); /* STA */
      break;
	 case 0x92:  // MHG
		STOPi();
		break;
	 case 0x93:  // MHG
		SHAi(INDY);
		break;
    case 0x94:
      STYInstrHandler(ZeroPgXAddrModeHandler_Address());
      break;
    case 0x95:
      FASTWRITE(ZeroPgXAddrModeHandler_Address(),Accumulator); /* STA */
      break;
    case 0x96:
      STXInstrHandler(ZeroPgYAddrModeHandler_Address());
      break;
	 case 0x97:  // MHG
		SAXi(ZPY);
		break;
    case 0x98:
      Accumulator=YReg; /* TYA */
      PSR&=~(FlagZ | FlagN);
      PSR|=((Accumulator==0)<<1) | (Accumulator & 128);
      break;
    case 0x99:
      FASTWRITE(AbsYAddrModeHandler_Address(),Accumulator); /* STA */
      break;
    case 0x9a:
      StackReg=XReg; /* TXS */
      break;
	 case 0x9b:  // MHG
		SHSi();
		break;
	 case 0x9c:  // MHG
		SHYi(ABSX);
		break;
    case 0x9d:
      FASTWRITE(AbsXAddrModeHandler_Address(),Accumulator); /* STA */
      break;
	 case 0x9e:  // MHG
		SHXi(ABSY);
		break;
 	 case 0x9f:  // MHG
		SHAi(ABSY);
		break;
//-------------------------------------------------------------------------------------------
    case 0xa0:
      LDYInstrHandler(WholeRam[ProgramCounter++]); /* immediate */
      break;
    case 0xa1:
      LDAInstrHandler(IndXAddrModeHandler_Data());
      break;
    case 0xa2:
      LDXInstrHandler(WholeRam[ProgramCounter++]); /* immediate */
      break;
	 case 0xa3:  // MHG
		LAXi(INDX);
		break;
    case 0xa4:
      LDYInstrHandler(WholeRam[WholeRam[ProgramCounter++]]/*zp */);
      break;
    case 0xa5:
      LDAInstrHandler(WholeRam[WholeRam[ProgramCounter++]]/*zp */);
      break;
    case 0xa6:
      LDXInstrHandler(WholeRam[WholeRam[ProgramCounter++]]/*zp */);
      break;
	 case 0xa7:  // MHG
		LAXi(ZP);
		break;
    case 0xa8:
      YReg=Accumulator; /* TAY */
      PSR&=~(FlagZ | FlagN);
      PSR|=((Accumulator==0)<<1) | (Accumulator & 128);
      break;
    case 0xa9:
      LDAInstrHandler(WholeRam[ProgramCounter++]); /* immediate */
      break;
    case 0xaa:
      XReg=Accumulator; /* TXA */
      PSR&=~(FlagZ | FlagN);
      PSR|=((Accumulator==0)<<1) | (Accumulator & 128);
      break;
	 case 0xab:  // MHG
		LXAi(IMMEDIATE);
		break;
    case 0xac:
      LDYInstrHandler(AbsAddrModeHandler_Data());
      break;
    case 0xad:
      LDAInstrHandler(AbsAddrModeHandler_Data());
      break;
    case 0xae:
      LDXInstrHandler(AbsAddrModeHandler_Data());
      break;
	 case 0xaf:  // MHG
		LAXi(ABS);
		break;
//-------------------------------------------------------------------------------------------
    case 0xb0:
      BCSInstrHandler();
      break;
     case 0xb1:
      LDAInstrHandler(IndYAddrModeHandler_Data());
      break;
	 case 0xb2:  // MHG
		STOPi();
		break;
	 case 0xb3:  // MHG
		LAXi(INDY);
		break;
    case 0xb4:
      LDYInstrHandler(ZeroPgXAddrModeHandler_Data());
      break;
    case 0xb5:
      LDAInstrHandler(ZeroPgXAddrModeHandler_Data());
      break;
    case 0xb6:
      LDXInstrHandler(ZeroPgYAddrModeHandler_Data());
      break;
	 case 0xb7:  // MHG
		LAXi(ZPY);
		break;
    case 0xb8:
      PSR&=255-FlagV; /* CLV */
      break;
    case 0xb9:
      LDAInstrHandler(AbsYAddrModeHandler_Data());
      break;
    case 0xba:
      XReg=StackReg; /* TSX */
      PSR&=~(FlagZ | FlagN);
      PSR|=((XReg==0)<<1) | (XReg & 128);
      break;
	case	0xbb:
		LASi(ABSY);
		break;
    case 0xbc:
      LDYInstrHandler(AbsXAddrModeHandler_Data());
      break;
    case 0xbd:
      LDAInstrHandler(AbsXAddrModeHandler_Data());
      break;
    case 0xbe:
      LDXInstrHandler(AbsYAddrModeHandler_Data());
      break;
	 case 0xbf:  // MHG
		LAXi(ABSY);
		break;
//-------------------------------------------------------------------------------------------
    case 0xc0:
      CPYInstrHandler(WholeRam[ProgramCounter++]); /* immediate */
      break;
    case 0xc1:
      CMPInstrHandler(IndXAddrModeHandler_Data());
      break;
	 case 0xc2:  // MHG
		NOPSi(IMMEDIATE);
		break;
	 case 0xc3:  // MHG
		DCPi(INDX);
		break;
    case 0xc4:
      CPYInstrHandler(WholeRam[WholeRam[ProgramCounter++]]/*zp */);
      break;
    case 0xc5:
      CMPInstrHandler(WholeRam[WholeRam[ProgramCounter++]]/*zp */);
      break;
    case 0xc6:
      DECInstrHandler(ZeroPgAddrModeHandler_Address());
      break;
	 case 0xc7:  // MHG
		DCPi(ZP);
		break;
    case 0xc8:
      YReg+=1; /* INY */
      YReg&=255;
      PSR&=~(FlagZ | FlagN);
      PSR|=((YReg==0)<<1) | (YReg & 128);
      break;
    case 0xc9:
      CMPInstrHandler(WholeRam[ProgramCounter++]); /* immediate */
      break;
    case 0xca:
      DEXInstrHandler();
      break;
	 case 0xcb:  // MHG
		SBXi(IMMEDIATE);
		break;
    case 0xcc:
      CPYInstrHandler(AbsAddrModeHandler_Data());
      break;
    case 0xcd:
      CMPInstrHandler(AbsAddrModeHandler_Data());
      break;
    case 0xce:
      DECInstrHandler(AbsAddrModeHandler_Address());
      break;
	 case 0xcf:  // MHG
		DCPi(ABS);
		break;
//-------------------------------------------------------------------------------------------
   case 0xd0:
      BNEInstrHandler();
      break;
    case 0xd1:
      CMPInstrHandler(IndYAddrModeHandler_Data());
      break;
	 case 0xd2:  // MHG
		STOPi();
		break;
	 case 0xd3:  // MHG
		DCPi(INDY);
		break;
 	 case 0xd4:  // MHG
		NOPi(ZPX);
		break;
    case 0xd5:
      CMPInstrHandler(ZeroPgXAddrModeHandler_Data());
      break;
    case 0xd6:
      DECInstrHandler(ZeroPgXAddrModeHandler_Address());
      break;
	 case 0xd7:  // MHG
		DCPi(ZPY);
		break;
    case 0xd8:
      PSR&=255-FlagD; /* CLD */
      break;
    case 0xd9:
      CMPInstrHandler(AbsYAddrModeHandler_Data());
      break;
	 case 0xda:  // MHG
		NOPi(IMPLIED);
		break;
	 case 0xdb:  // MHG
		DCPi(ABSY);
		break;
    case 0xDC: 		// MHG
		NOPi(ABSX);
      break;
    case 0xdd:
      CMPInstrHandler(AbsXAddrModeHandler_Data());
      break;
    case 0xde:
      DECInstrHandler(AbsXAddrModeHandler_Address());
      break;
 	 case 0xdf:  // MHG
		DCPi(ABSX);
		break;
//-------------------------------------------------------------------------------------------
    case 0xe0:
      CPXInstrHandler(WholeRam[ProgramCounter++]); /* immediate */
      break;
    case 0xe1:
      SBCInstrHandler(IndXAddrModeHandler_Data());
      break;
  	 case 0xe2:  // MHG
		NOPSi(IMMEDIATE);
		break;
  	 case 0xe3:  // MHG
		ISBi(INDX);
		break;
    case 0xe4:
      CPXInstrHandler(WholeRam[WholeRam[ProgramCounter++]]/*zp */);
      break;
    case 0xe5:
      SBCInstrHandler(WholeRam[WholeRam[ProgramCounter++]]/*zp */);
      break;
    case 0xe6:
      INCInstrHandler(ZeroPgAddrModeHandler_Address());
      break;
	 case 0xe7:  // MHG
		ISBi(ZP);
		break;
    case 0xe8:
      INXInstrHandler();
      break;
    case 0xe9:
      SBCInstrHandler(WholeRam[ProgramCounter++]); /* immediate */
      break;
    case 0xea: 	// MHG
      break;
	 case 0xeb:  	// MHG
		SBCi(IMMEDIATE);
		break;
    case 0xec:
      CPXInstrHandler(AbsAddrModeHandler_Data());
      break;
    case 0xed:
      SBCInstrHandler(AbsAddrModeHandler_Data());
      break;
    case 0xee:
      INCInstrHandler(AbsAddrModeHandler_Address());
      break;
	 case 0xef:  	// MHG
		ISBi(ABS);
		break;
//-------------------------------------------------------------------------------------------
    case 0xf0:
      BEQInstrHandler();
      break;
    case 0xf1:
      SBCInstrHandler(IndYAddrModeHandler_Data());
      break;
	 case 0xf2:  	// MHG
		STOPi();
		break;
	 case 0xf3:  	// MHG
		ISBi(INDY);
		break;
  	 case 0xf4:  	// MHG
		NOPi(ZPX);
		break;
    case 0xf5:
      SBCInstrHandler(ZeroPgXAddrModeHandler_Data());
      break;
    case 0xf6:
      INCInstrHandler(ZeroPgXAddrModeHandler_Address());
      break;
	 case 0xf7:  	// MHG
		ISBi(ZPX);
		break;
    case 0xf8:
      PSR|=FlagD; /* SED */
      break;
    case 0xf9:
      SBCInstrHandler(AbsYAddrModeHandler_Data());
      break;
 	 case 0xfa:  	// MHG
		NOPi(IMPLIED);
		break;
 	 case 0xfb:  	// MHG
		ISBi(ABSY);
		break;
    case 0xFC: 	// MHG
		NOPi(ABSX);
      break;
    case 0xfd:
      SBCInstrHandler(AbsXAddrModeHandler_Data());
      break;
    case 0xfe:
      INCInstrHandler(AbsXAddrModeHandler_Address());
      break;
	 case 0xff:  	// MHG
		ISBi(ABSX);
		break;
//-------------------------------------------------------------------------------------------
    default:
      BadInstrHandler(CurrentInstruction);
      break;
  }; /* OpCode switch */

  OldNMIStatus=NMIStatus;
  /* NOTE: Check IRQ status before polling hardware - this is essential for
     Rocket Raid to work since it polls the IFR in the sys via for start of
     frame - but with interrupts enabled.  If you do the interrupt check later
     then the interrupt handler will always be entered and rocket raid will
     never see it */
  if ((intStatus) && (!GETIFLAG)) DoInterrupt();

  TotalCycles+=Cycles;

  VideoPoll(Cycles);
  SysVIA_poll(Cycles);
  UserVIA_poll(Cycles);
  Disc8271_poll(Cycles);

  Sound_Trigger(Cycles);  ///THIS IT IT

  if ((NMIStatus) && (!OldNMIStatus)) DoNMI();
  };
} /* Exec6502Instruction */

/*-------------------------------------------------------------------------*/
/* Dump state                                                              */
void core_dumpstate(void) {
  cerr << "core:\n";
  DumpRegs();
}; /* core_dumpstate */

char	bad[]=
{
0x02,
0x03,
0x04,
0x07,
0x0b,
0x0c,
0x0f,
0x12,
0x13,
0x14,
0x17,
0x1a,
0x1b,
0x1c,
0x1f,
0x22,
0x23,
0x27,
0x2b,
0x2f,
0x32,
0x33,
0x34,
0x37,
0x3a,
0x3b,
0x3c,
0x3f,
0x42,
0x43,
0x44,
0x47,
0x4b,
0x4f,
0x52,
0x53,
0x54,
0x57,
0x5a,
0x5b,
0x5c,
0x5f,
0x62,
0x63,
0x64,
0x67,
0x6b,
0x6f,
0x72,
0x73,
0x74,
0x77,
0x7a,
0x7b,
0x7c,
0x7f,
0x80,
0x82,
0x83,
0x87,
0x8b,
0x8f,
0x92,
0x93,
0x97,
0x9b,
0x9c,
0x9e,
0x9f,
0xa3,
0xa7,
0xab,
0xaf,
0xb2,
0xb3,
0xb7,
0xbb,
0xbf,
0xc2,
0xc3,
0xc7,
0xcb,
0xcf,
0xd2,
0xd3,
0xd4,
0xd7,
0xda,
0xdb,
0xdc,
0xdf,
0xe2,
0xe3,
0xe7,
0xeb,
0xef,
0xf2,
0xf3,
0xf4,
0xf7,
0xfa,
0xfb,
0xfc,
0xff
};





void	check_op(int a)
{
  int i=0;

	while(1)
	{
	  if (bad[i]==a)
  			printf("op 0x%x %d\n",a,a);
	  i++;
	  if (i>=256) break;
	  if (bad[i]==255) break;
	}
}






