/*
 * $Id: 6510_.cxx,v 1.5 1996/04/02 14:53:58 ms Exp $
 * 
 * 
 * MOS-6510 Interpreter
 *
 * Copyright (c) 1995,1996 Michael Schwendt
 * All rights reserved.
 * InterNet email: 3schwend@informatik.uni-hamburg.de
 *
 * Redistribution and use in source and binary forms, either unchanged or
 * modified, are permitted provided that the following conditions are met: 
 * 
 * (1) Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * (2) Redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the following disclaimer in the 
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *  known bugs (or missing features, compared to the DOS assembly version):
 *  - no detection of deadlocks
 *  - fake RTI
 *  - insufficient ROM emulation 
 *    (include the original images ?)
 *
 * $Log: 6510_.cxx,v $
 * Revision 1.5  1996/04/02 14:53:58  ms
 * Added ADC and SBC in decimal mode
 * Applied some Windows-specific patches
 *
 * Revision 1.4  1996/03/27 01:06:22  ms
 * TEST: Added ability to fake a plain C64 memory for PlaySID compatibility
 *
 * Revision 1.3  1996/03/25 05:06:15  ms
 * *** empty log message ***
 *
 * Revision 1.2  1996/02/26 00:54:13  ms
 * Replaced usage of malloc() by new()
 *
 * Revision 1.1  1996/02/09 19:35:50  ms
 * Fixed #includes for FreeBSD; thanks to <aagero@aage.aage.priv.no>
 * Changed JMP_() and JMP_vec() for bank-switching compatibility
 *
 * Revision 1.0  1996/01/05 15:30:10  ms
 * Initial revision
 *
 */
#if defined(_Windows) && !defined(__WIN32__)
  #include <windows.h>
  #include <windowsx.h>
#endif

#include "mytypes.h"
#include "m68k.h"
#include "reset.h"
#include "ramrom.h"

// 6510 processor registers
ubyte AC, XR, YR;                         
// program-counter, stack-pointer
uword PC, SP;			        

// possible data operands
ubyte dataop1, dataop2;                 

// key_off detection
ubyte sidkeys[32];                      

// 64KB C64-RAM
ubyte* c64mem1;                         
// Basic-ROM, VIC, SID, I/O, Kernal-ROM
ubyte* c64mem2;   	       		

//--------------------------------------------------

struct statusregister
{
  unsigned Carry     : 1;
  unsigned Zero      : 1;
  unsigned Interrupt : 1;
  unsigned Decimal   : 1;
  unsigned Break     : 1;
  unsigned NotUsed   : 1;
  unsigned oVerflow  : 1;
  unsigned Negative  : 1;
} SR;

// some handy defines to ease SR access
#define CF SR.Carry
#define ZF SR.Zero
#define IF SR.Interrupt
#define DF SR.Decimal
#define BF SR.Break
#define NU SR.NotUsed
#define VF SR.oVerflow
#define NF SR.Negative

inline void affectNZ(ubyte reg)
{
  ZF = ( reg == 0 );
  NF = (( reg & 128 ) != 0 );
}

inline void clearSR()
{
  CF = 0; ZF = 0; IF = 0; DF = 0; BF = 0; NU = 0; VF = 0; NF = 0;
}

//--------------------------------------------------

int MPU_memfree()
{
  if ( c64mem2 != 0 )
  {
#if defined(_Windows) && !defined(__WIN32__)
	GlobalFreePtr (c64mem2);
#else
	delete( c64mem2 );
#endif
	c64mem2 = 0;
  }
  if ( c64mem1 != 0 )
  {
#if defined(_Windows) && !defined(__WIN32__)
	GlobalFreePtr (c64mem1);
#else
	delete( c64mem1 );
#endif
	c64mem1 = 0;
  }
  return(TRUE);
}

int MPU_memalloc()
{
  MPU_memfree();
#if defined(_Windows) && !defined(__WIN32__)
  if ((c64mem1 = (ubyte*) GlobalAllocPtr (GPTR, 65536L)) == 0)
    return(FALSE);
  if ((c64mem2 = (ubyte*) GlobalAllocPtr (GPTR, 65536L)) == 0)
    return(FALSE);
#else
  if (( c64mem1 = new ubyte[65536] ) == 0 )  return(FALSE);
  if (( c64mem2 = new ubyte[65536] ) == 0 )  return(FALSE);
#endif
  return(TRUE);
}

//--------------------------------------------------
// handling conditional branches 

inline void branchifclear(ubyte flag)
{
  if ( flag == 0 )  PC += (byte)c64mem1[PC];
  PC++;
}

inline void branchifset(ubyte flag)
{
  if ( flag != 0 )  PC += (byte)c64mem1[PC];
  PC++;
}

//--------------------------------------------------
// addressing modes: calculating 8/16-bit effective 
// addresses out of the data operands

inline uword abs ()
{
  PC += 2;
  return( m68k( dataop2, dataop1 ));
}

inline uword absx ()
{
  PC += 2;
  return( m68k( dataop2, dataop1 ) + XR );
}

inline uword absy ()
{
  PC += 2;
  return( m68k( dataop2, dataop1 ) + YR );
}

inline uword indx ()
{
  PC++;
  return( m68k( c64mem1[dataop1 +1 +XR], c64mem1[dataop1 +XR] ));
}

inline uword indy ()
{
  PC++;
  return( YR + m68k( c64mem1[dataop1 +1], c64mem1[dataop1] ));
}

inline uword zp ()
{
  PC++;
  return( dataop1 );
}

inline uword zpx ()
{
  PC++;
  return( dataop1 +XR );
}

inline uword zpy ()
{
  PC++;
  return( dataop1 +YR );
}

//--------------------------------------------------

ubyte readdata_bs(uword addr)
{
  // $0000-$CFFF RAM
  if ( addr < 0xd000 )  return(c64mem1[addr]);
  // $E000-$FFFF RAM
  else if ( addr >= 0xe000 )  return(c64mem1[addr]);           
  // $D000-$DFFF RAM
  else if (( c64mem1[1] & 4 ) == 0 )  return(c64mem1[addr]);   
  // SID ?, mirrored SID
  uword tempaddr = (addr & 0xfc1f);   
  // $D000-$DFFF VIC, ...
  if (( tempaddr & 0xff00 ) != 0xd400 )  return(c64mem2[addr]);  
  // $D41D/1E/1F, $D43D/, ... SID not mirrored
  if (( tempaddr & 0x00ff ) >= 0x001d )  return(c64mem2[addr]); 
  // mirrored SID
  return (c64mem2[tempaddr]); 
}

ubyte readdata_plain(uword addr)
{
  return (c64mem1[addr]); 
}

void writedata_bs(uword addr, ubyte data)
{
  // SID ? und SID-Spiegelung ermitteln
  uword tempaddr = (addr & 0xfc1f);         
  // $0000-$CFFF RAM
  if ( addr < 0xd000 )  c64mem1[addr] = data;              
  // $E000-$FFFF RAM
  else if ( addr >= 0xe000 )  c64mem1[addr] = data;        
  // $D000-$DFFF RAM
  else if (( c64mem1[1] & 4 ) == 0 )  c64mem1[addr]=data;  
  // $D000-$DFFF VIC etc.
  else if (( tempaddr & 0xff00 ) != 0xd400 )  c64mem2[addr]=data; 
  // $D41D/1E/1F, $D43D/3E... SID ungespiegelt
  else if (( tempaddr & 0x00ff ) >= 0x001d )  c64mem2[addr]=data;    
  else
  {
	// mirrored SID
    c64mem2[tempaddr] = data;           
    tempaddr &= 0x001f;
	// handle key_offs
    sidkeys[tempaddr] |= (~(data & 1)); 
  }
}

void writedata_plain(uword addr, ubyte data)
{
  // SID ? und SID-Spiegelung ermitteln
  uword tempaddr = (addr & 0xfc1f);         
  if (( tempaddr & 0xff00 ) != 0xd400 )  
	c64mem1[addr] = data; 
  // $D41D/1E/1F, $D43D/3E... SID ungespiegelt
  else if (( tempaddr & 0x00ff ) >= 0x001d )  
	c64mem2[addr]=data;
  else  {
	// mirrored SID
    c64mem2[tempaddr] = data;           
	// handle key_offs
    sidkeys[tempaddr & 0x001f] |= (~(data & 1)); 
  }
}

ubyte (*readdata)(uword) = &readdata_bs;
void (*writedata)(uword, ubyte) = &writedata_bs;

//--------------------------------------------------
// legal instructions in alphabetical order 

inline void ADC_m(ubyte x)
{
  if ( DF == 1 )  {
	uword AC2 = AC +x +CF;                
	VF = ((( AC ^ x ^ AC2 ) & 128 ) != 0 );
	if ((( AC & 15 ) + ( x & 15 ) + CF ) > 9 )
	  AC2 += 6;
	if ( AC2 > 0x99 )
	  AC2 += 96;
	CF = ( AC2 > 0x99 );
	AC = ( AC2 & 255 );
	if ( AC != 0 )
	  ZF = 1;
	NF = (( AC & 128 ) != 0 );
  }
  else  {
	uword AC2 = AC +x +CF;                
	CF = ( AC2 > 255 );
	VF = ((( AC ^ x ^ AC2 ) & 128 ) != 0 );
	affectNZ( AC = ( AC2 & 255 ));
  }
}
void ADC_imm()
{ 
  ADC_m( dataop1 );                     
  PC++;
}
void ADC_abs()  { ADC_m( readdata(abs()) ); }
void ADC_absx()  { ADC_m( readdata(absx()) ); }
void ADC_absy()  { ADC_m( readdata(absy()) ); }
void ADC_indx()  { ADC_m( readdata(indx()) ); }
void ADC_indy()  { ADC_m( readdata(indy()) ); }
void ADC_zp()  { ADC_m( readdata(zp()) ); }
void ADC_zpx()  { ADC_m( readdata(zpx()) ); }


inline void AND_m(ubyte x)  { affectNZ( AC &= x ); }
void AND_imm()
{ 
  AND_m( dataop1 );                       
  PC++;
}
void AND_abs()  { AND_m( readdata(abs()) ); }
void AND_absx()  { AND_m( readdata(absx()) ); }
void AND_absy()  { AND_m( readdata(absy()) ); }
void AND_indx()  { AND_m( readdata(indx()) ); }
void AND_indy()  { AND_m( readdata(indy()) ); }
void AND_zp()  { AND_m( readdata(zp()) ); }
void AND_zpx()  { AND_m( readdata(zpx()) ); }


inline ubyte ASL_m(ubyte x)
{ 
  CF = (( x & 128 ) != 0 );                 
  affectNZ( x <<= 1);                     
  return(x);
}
void ASL_AC()
{ 
  AC = ASL_m(AC);                         
}
void ASL_abs()
{ 
  uword tempaddr = abs();
  writedata( tempaddr, ASL_m( readdata(tempaddr)) );
}
void ASL_absx()
{ 
  uword tempaddr = absx();
  writedata( tempaddr, ASL_m( readdata(tempaddr)) );
}
void ASL_zp()
{ 
  uword tempaddr = zp();
  writedata( tempaddr, ASL_m( readdata(tempaddr)) );
}
void ASL_zpx()
{ 
  uword tempaddr = zpx();
  writedata( tempaddr, ASL_m( readdata(tempaddr)) );
}


void BCC_()  { branchifclear(CF);}

void BCS_()  { branchifset(CF); }

void BEQ_()  { branchifset(ZF); }


inline void BIT_m(ubyte x)
{ 
  ZF = (( AC & x ) == 0 );                  
  VF = (( x & 64 ) != 0 );
  NF = (( x & 128 ) != 0 );
}
void BIT_abs()
{ 
  BIT_m( readdata(abs()) );             
}
void BIT_zp()
{ 
  BIT_m( readdata(zp()) );              
}


void BMI_()  { branchifset(NF); }

void BNE_()  { branchifclear(ZF); }

void BPL_()  { branchifclear(NF); }


void BRK_()
{ 
  BF = 1; IF = 1;
}

void BRK_plain()
{ 
  BF = 1; IF = 1;
  void RTS_();
  RTS_();
}

void BVC_()  { branchifclear(VF); }

void BVS_()  { branchifset(VF); }


void CLC_()  { CF = 0; }

void CLD_()  { DF = 0; }

void CLI_()  { IF = 0; }

void CLV_()  { VF = 0; }


inline void CMP_m(ubyte x)
{ 
  ZF = ( AC == x );                     
  CF = ( AC >= x );                         
  NF = (( (byte)AC - (byte)x ) < 0 );      
}
void CMP_abs()  { CMP_m( readdata(abs()) ); }
void CMP_absx()  { CMP_m( readdata(absx()) ); }
void CMP_absy()  { CMP_m( readdata(absy()) ); }
void CMP_imm()
{ 
  CMP_m( dataop1 );                     
  PC++;
}
void CMP_indx()  { CMP_m( readdata(indx()) ); }
void CMP_indy()  { CMP_m( readdata(indy()) ); }
void CMP_zp()  { CMP_m( readdata(zp()) ); }
void CMP_zpx()  { CMP_m( readdata(zpx()) ); }


inline void CPX_m(ubyte x)
{ 
  ZF = ( XR == x );                         
  CF = ( XR >= x );                         
  NF = (( (byte)XR - (byte)x ) < 0 );      
}
void CPX_abs()  { CPX_m( readdata(abs()) ); }
void CPX_imm()  
{ 
  CPX_m( dataop1 );                       
  PC++;
}
void CPX_zp()  { CPX_m( readdata(zp()) ); }


inline void CPY_m(ubyte x)
{ 
  ZF = ( YR == x );                         
  CF = ( YR >= x );                         
  NF = (( (byte)YR - (byte)x ) < 0 );      
}
void CPY_abs()  { CPY_m( readdata(abs()) ); }
void CPY_imm()  
{ 
  CPY_m( dataop1 );                     
  PC++;
}
void CPY_zp()  { CPY_m( readdata(zp()) ); }


inline void DEC_m(uword addr)
{ 
  ubyte x = readdata(addr);                   
  affectNZ(--x);
  writedata(addr, x);
}
void DEC_abs()  { DEC_m( abs() ); }
void DEC_absx()  { DEC_m( absx() ); }
void DEC_zp()  { DEC_m( zp() ); }
void DEC_zpx()  { DEC_m( zpx() ); }


void DEX_()  { affectNZ(--XR); }

void DEY_()  { affectNZ(--YR); }


inline void EOR_m(ubyte x)
{ 
  AC ^= x;                          
  affectNZ(AC);                         
}
void EOR_abs()  { EOR_m( readdata(abs()) ); }
void EOR_absx()  { EOR_m( readdata(absx()) ); }
void EOR_absy()  { EOR_m( readdata(absy()) ); }
void EOR_imm()
{ 
  EOR_m( dataop1 );                       
  PC++;
}
void EOR_indx()  { EOR_m( readdata(indx()) ); }
void EOR_indy()  { EOR_m( readdata(indy()) ); }
void EOR_zp()  { EOR_m( readdata(zp()) ); }
void EOR_zpx()  { EOR_m( readdata(zpx()) ); }


inline void INC_m(uword addr)
{ ubyte x = readdata(addr);                   
  affectNZ(++x);
  writedata(addr, x);
}
void INC_abs()  { INC_m( abs() ); }
void INC_absx()  { INC_m( absx() ); }
void INC_zp()  { INC_m( zp() ); }
void INC_zpx()  { INC_m( zpx() ); }


void INX_()  { affectNZ(++XR); }

void INY_()  { affectNZ(++YR); }



void JMP_()
{ 
  void RTS_();
  uword tempPC = abs();
  PC = tempPC;
  if ( ( PC >= 0xd000 ) && (( c64mem1[1] & 2 ) != 0 ) )  RTS_();
}


void JMP_vec()
{ 
  void RTS_();
  uword tempaddr = abs(); 
  PC = m68k( readdata(tempaddr +1), readdata(tempaddr) );
  if ( ( PC >= 0xd000 ) && (( c64mem1[1] & 2 ) != 0 ) )  RTS_();
}


void JSR_()
{ 
  uword tempPC = abs();
  PC--;                                 
  c64mem1[SP--] = (PC >> 8);             
  c64mem1[SP--] = (PC & 255);             
  PC = tempPC;                            
}


void LDA_abs()  { affectNZ( AC = readdata(abs()) ); }
void LDA_absx()  { affectNZ( AC = readdata( absx() )); }
void LDA_absy()  { affectNZ( AC = readdata( absy() ) ); }
void LDA_imm()
{ 
  affectNZ( AC = dataop1 );             
  PC++;
}
void LDA_indx()  { affectNZ( AC = readdata( indx() ) ); }
void LDA_indy()  { affectNZ( AC = readdata( indy() ) ); }
void LDA_zp()  { affectNZ( AC = readdata( zp() ) ); }
void LDA_zpx()  { affectNZ( AC = readdata( zpx() ) ); }


void LDX_abs()
{ 
  XR=readdata ( abs() );                
  affectNZ(XR);
}
void LDX_absy()
{ 
  XR=readdata ( absy() );               
  affectNZ(XR);
}
void LDX_imm()
{ 
  affectNZ( XR = dataop1 );             
  PC++;
}
void LDX_zp()
{ 
  XR=readdata ( zp() );                 
  affectNZ(XR);
}
void LDX_zpy()
{ 
  XR=readdata ( zpy() );                
  affectNZ(XR);
}


void LDY_abs()
{ 
  YR=readdata ( abs() );                
  affectNZ(YR);
}
void LDY_absx()
{ 
  YR=readdata ( absx() );               
  affectNZ(YR);
}
void LDY_imm()
{ 
  affectNZ(YR=dataop1);                 
  PC++;
}
void LDY_zp()
{ 
  YR=readdata ( zp() );                 
  affectNZ(YR);
}
void LDY_zpx()
{ 
  YR=readdata ( zpx() );                
  affectNZ(YR);
}


inline ubyte LSR_m(ubyte x)
{ 
  CF= x & 1;
  x >>= 1;
  NF = 0; ZF = ( x == 0 );
  return(x);
}
void LSR_AC()  { AC=LSR_m(AC); }
void LSR_abs()
{ 
  uword tempaddr=abs();
  writedata( tempaddr, (LSR_m( readdata(tempaddr))) );
}
void LSR_absx()
{ 
  uword tempaddr;                     
  tempaddr=absx();
  writedata( tempaddr, (LSR_m( readdata(tempaddr))) );
}
void LSR_zp()
{ 
  uword tempaddr;                     
  tempaddr=zp();
  writedata( tempaddr, (LSR_m( readdata(tempaddr))) );
}
void LSR_zpx()
{ 
  uword tempaddr;                     
  tempaddr=zpx();
  writedata( tempaddr, (LSR_m( readdata(tempaddr))) );
}


inline void ORA_m(ubyte x)  { affectNZ( AC |= x ); }
void ORA_abs()  { ORA_m( readdata(abs()) ); }
void ORA_absx()  { ORA_m( readdata(absx()) ); }
void ORA_absy()  { ORA_m( readdata(absy()) ); }
void ORA_imm()
{ 
  ORA_m( dataop1 );                       
  PC++;
}
void ORA_indx()  { ORA_m( readdata(indx()) ); }
void ORA_indy()  { ORA_m( readdata(indy()) ); }
void ORA_zp()  { ORA_m( readdata(zp()) ); }
void ORA_zpx()  { ORA_m( readdata(zpx()) ); }


void NOP_()  { }

void PHA_()  { c64mem1[SP--] = AC; }


void PHP_()
{ 
  register ubyte tempSR = CF;
  tempSR |= ZF << 1;
  tempSR |= IF << 2;
  tempSR |= DF << 3;
  tempSR |= BF << 4;
  tempSR |= NU << 5;
  tempSR |= VF << 6;
  tempSR |= NF << 7;
  c64mem1[SP--] = tempSR;
}


void PLA_()
{ 
  affectNZ(AC=c64mem1[++SP]);
}


void PLP_()
{ 
  register ubyte tempSR = c64mem1[++SP];                
  CF = tempSR & 1;               
  ZF = ((tempSR & 2) !=0 );
  IF = ((tempSR & 4) !=0 );
  DF = ((tempSR & 8) !=0 );
  BF = ((tempSR & 16) !=0 );
  NU = ((tempSR & 32) !=0 );
  VF = ((tempSR & 64) !=0 );
  NF = ((tempSR & 128) !=0 );
}

inline ubyte ROL_m(uword x)
{ 
  x = (x << 1) + CF;
  CF=( (x & 256) !=0 );
  affectNZ(x);
  return(x);
}
void ROL_AC()  { AC=ROL_m(AC); }
void ROL_abs()
{ 
  uword tempaddr = abs();
  writedata( tempaddr, ROL_m( readdata(tempaddr)) );
}
void ROL_absx()
{ 
  uword tempaddr = absx();
  writedata( tempaddr, ROL_m( readdata(tempaddr)) );
}
void ROL_zp()
{ 
  uword tempaddr = zp();
  writedata( tempaddr, ROL_m( readdata(tempaddr)) );
}
void ROL_zpx()
{ 
  uword tempaddr = zpx();
  writedata( tempaddr, ROL_m( readdata(tempaddr)) );
}

inline ubyte ROR_m(ubyte x)
{ 
  register ubyte tempCF = (x & 1);
  x=(x >> 1) | (128*CF);
  CF=tempCF;
  affectNZ(x);
  return(x);
}
void ROR_AC()  { AC=ROR_m(AC); }
void ROR_abs()
{ 
  uword tempaddr = abs();
  writedata( tempaddr, ROR_m( readdata(tempaddr)) );
}
void ROR_absx()
{ 
  uword tempaddr = absx();
  writedata( tempaddr, ROR_m( readdata(tempaddr)) );
}
void ROR_zp()
{ 
  uword tempaddr = zp();
  writedata( tempaddr, ROR_m( readdata(tempaddr)) );
}
void ROR_zpx()
{ 
  uword tempaddr = zpx();
  writedata( tempaddr, ROR_m( readdata(tempaddr)) );
}


void RTI_()	
{ 
  SP++;
  PC =m68k( c64mem1[SP +1], c64mem1[SP] ) +1;
  SP++;
}


void RTS_()
{ 
  SP++;
  PC =m68k( c64mem1[SP +1], c64mem1[SP] ) +1;
  SP++;
}


void SBC_m(ubyte s)
{ 
  s=(~s) & 255;
  if ( DF != 0 )  {
	uword AC2 = AC +s +CF;                
	VF = ((( AC ^ s ^ AC2 ) & 128 ) != 0 );
	if ((( AC & 15 ) + ( s & 15 ) + CF ) > 9 )
	  AC2 += 6;
	if ( AC2 > 0x99 )
	  AC2 += 96;
	CF = ( AC2 > 0x99 );
	AC = ( AC2 & 255 );
	if ( AC != 0 )
	  ZF = 1;
	NF = (( AC & 128 ) != 0 );
  }
  else  {
	uword AC2=AC+s+CF;       
	CF=( (AC2 & 256) !=0 );
	VF=( ((AC ^ s ^ AC2) & 128) != 0);
	AC=AC2 & 255;
	affectNZ(AC);
  }
}
void SBC_abs()  { SBC_m( readdata(abs()) ); }
void SBC_absx()  { SBC_m( readdata(absx()) ); }
void SBC_absy()  { SBC_m( readdata(absy()) ); }
void SBC_imm()  
{ 
  SBC_m( dataop1 );                       
  PC++;
}
void SBC_indx()  { SBC_m( readdata( indx()) ); }
void SBC_indy()  { SBC_m( readdata(indy()) ); }
void SBC_zp()  { SBC_m( readdata(zp()) ); }
void SBC_zpx()  { SBC_m( readdata(zpx()) ); }


void SEC_()  { CF=1; }

void SED_()  { DF=1; }

void SEI_()  { IF=1; }


void STA_abs()  { writedata( abs(), AC ); }
void STA_absx()  { writedata( absx(), AC ); }
void STA_absy()  { writedata( absy(), AC ); }
void STA_indx()  { writedata( indx(), AC ); }
void STA_indy()  { writedata( indy(), AC ); }
void STA_zp()  { writedata( zp(), AC ); }
void STA_zpx() { writedata( zpx(), AC ); }


void STX_abs()  { writedata( abs(), XR ); }
void STX_zp()  { writedata( zp(), XR ); }
void STX_zpy()  { writedata( zpy(), XR ); }


void STY_abs()  { writedata( abs(), YR ); }
void STY_zp()  { writedata( zp(), YR ); }
void STY_zpx()  { writedata( zpx(), YR ); }


void TAX_()  { affectNZ(XR=AC); }

void TAY_()  { affectNZ(YR=AC); }


void TSX_()
{ 
  XR = SP & 255;													
  affectNZ(XR);
}

void TXA_()  { affectNZ(AC=XR); }

void TXS_()  { SP = XR & 0x100; }

void TYA_()  { affectNZ(AC=YR); }


//--------------------------------------------------
// illegal codes/instructions (1)

void ILL_1()  { }

void ILL_2()  { PC++; }

void ILL_3()  { PC+=2; }


//--------------------------------------------------
// illegal codes/instructions (2)

inline void ASLORA_m( uword (*addrfunc)() )
{
  uword tempaddr = (*addrfunc)();
  ubyte x = ASL_m( readdata( tempaddr ));
  writedata( tempaddr, x );
  ORA_m( x );
}
void ASLORA_abs()  { ASLORA_m( &abs ); }
void ASLORA_absx()  { ASLORA_m( &absx ); }
void ASLORA_absy()  { ASLORA_m( &absy ); }
void ASLORA_indx()  { ASLORA_m( &indx ); }
void ASLORA_indy()  { ASLORA_m( &indy ); }
void ASLORA_zp()  { ASLORA_m( &zp ); } 
void ASLORA_zpx()  { ASLORA_m( &zpx ); }


inline void ROLAND_m( uword (*addrfunc)() )
{
  uword tempaddr = (*addrfunc)();
  uword x = ROL_m( readdata( tempaddr ));
  writedata( tempaddr, x );
  AND_m( x );
}
void ROLAND_abs()  { ROLAND_m( &abs ); }
void ROLAND_absx()  { ROLAND_m( &absx ); }
void ROLAND_absy()  { ROLAND_m( &absy ); }  
void ROLAND_indx()  { ROLAND_m( &indx ); }  
void ROLAND_indy()  { ROLAND_m( &indy ); } 
void ROLAND_zp()  { ROLAND_m( &zp ); } 
void ROLAND_zpx()  { ROLAND_m( &zpx ); } 


inline void LSREOR_m( uword (*addrfunc)() )
{
  uword tempaddr = (*addrfunc)();
  uword x = LSR_m( readdata( tempaddr ));
  writedata( tempaddr, x );
  EOR_m( x );
}
void LSREOR_abs()  { LSREOR_m( &abs ); }
void LSREOR_absx()  { LSREOR_m( &absx ); }  
void LSREOR_absy()  { LSREOR_m( &absy ); }  
void LSREOR_indx()  { LSREOR_m( &indx ); } 
void LSREOR_indy()  { LSREOR_m( &indy ); }  
void LSREOR_zp()  { LSREOR_m( &zp ); }  
void LSREOR_zpx()  { LSREOR_m( &zpx ); }  


inline void RORADC_m( uword (*addrfunc)() )
{
  uword tempaddr = (*addrfunc)();
  ubyte x = ROR_m( readdata( tempaddr ));
  writedata( tempaddr, x );
  ADC_m( x );
}
void RORADC_abs()  { RORADC_m( &abs ); } 
void RORADC_absx()  { RORADC_m( &absx ); } 
void RORADC_absy()  { RORADC_m( &absy ); }  
void RORADC_indx()  { RORADC_m( &indx ); }  
void RORADC_indy()  { RORADC_m( &indy ); } 
void RORADC_zp()  { RORADC_m( &zp ); }  
void RORADC_zpx()  { RORADC_m( &zpx ); }


inline void DECCMP_m( uword (*addrfunc)() )
{
  uword tempaddr = (*addrfunc)();
  ubyte x = readdata( tempaddr );
  writedata( tempaddr, --x );
  CMP_m( x );
}
void DECCMP_abs()  { DECCMP_m( &abs ); }  
void DECCMP_absx()  { DECCMP_m( &absx ); }  
void DECCMP_absy()  { DECCMP_m( &absy ); }  
void DECCMP_indx()  { DECCMP_m( &indx ); }  
void DECCMP_indy()  { DECCMP_m( &indy ); } 
void DECCMP_zp()  { DECCMP_m( &zp ); } 
void DECCMP_zpx()  { DECCMP_m( &zpx ); } 


inline void INCSBC_m( uword (*addrfunc)() )
{
  uword tempaddr = (*addrfunc)();
  ubyte x = readdata( tempaddr );
  writedata( tempaddr, ++x );
  SBC_m( x );
}
void INCSBC_abs()  { INCSBC_m( &abs ); } 
void INCSBC_absx()  { INCSBC_m( &absx ); }  
void INCSBC_absy()  { INCSBC_m( &absy ); }  
void INCSBC_indx()  { INCSBC_m( &indx ); }  
void INCSBC_indy()  { INCSBC_m( &indy ); } 
void INCSBC_zp()  { INCSBC_m( &zp ); } 
void INCSBC_zpx()  { INCSBC_m( &zpx ); }  


//--------------------------------------------------
// illegal codes/instructions (3)

void NDF_2()  { PC++; }

void NDF_3()  { PC += 2; }

//--------------------------------------------------

ptr2func instrlist[] =
{
  &BRK_, &ORA_indx, &ILL_1, &ASLORA_indx, &ILL_2, &ORA_zp, &ASL_zp, &ASLORA_zp,
  &PHP_, &ORA_imm, &ASL_AC, &NDF_2, &ILL_3, &ORA_abs, &ASL_abs, &ASLORA_abs,
  &BPL_, &ORA_indy, &ILL_1, &ASLORA_indy, &ILL_2, &ORA_zpx, &ASL_zpx, &ASLORA_zpx,
  &CLC_, &ORA_absy, &ILL_1, &ASLORA_absy, &ILL_3, &ORA_absx, &ASL_absx, &ASLORA_absx,
  &JSR_, &AND_indx, &ILL_1, &ROLAND_indx, &BIT_zp, &AND_zp, &ROL_zp, &ROLAND_zp,
  &PLP_, &AND_imm, &ROL_AC, &NDF_2, &BIT_abs, &AND_abs, &ROL_abs, &ROLAND_abs,
  &BMI_, &AND_indy, &ILL_1, &ROLAND_indy, &ILL_2, &AND_zpx, &ROL_zpx, &ROLAND_zpx,
  &SEC_, &AND_absy, &ILL_1, &ROLAND_absy, &ILL_3, &AND_absx, &ROL_absx, &ROLAND_absx,
  &RTI_, &EOR_indx, &ILL_1, &LSREOR_indx, &ILL_2, &EOR_zp, &LSR_zp, &LSREOR_zp,
  &PHA_, &EOR_imm, &LSR_AC, &NDF_2, &JMP_, &EOR_abs, &LSR_abs, &LSREOR_abs,
  &BVC_, &EOR_indy, &ILL_1, &LSREOR_indy, &ILL_2, &EOR_zpx, &LSR_zpx, &LSREOR_zpx,
  &CLI_, &EOR_absy, &ILL_1, &LSREOR_absy, &ILL_3, &EOR_absx, &LSR_absx, &LSREOR_absx,
  &RTS_, &ADC_indx, &ILL_1, &RORADC_indx, &ILL_2, &ADC_zp, &ROR_zp, &RORADC_zp,
  &PLA_, &ADC_imm, &ROR_AC, &NDF_2, &JMP_vec, &ADC_abs, &ROR_abs, &RORADC_abs,
  &BVS_, &ADC_indy, &ILL_1, &RORADC_indy, &ILL_2, &ADC_zpx, &ROR_zpx, &RORADC_zpx,
  &SEI_, &ADC_absy, &ILL_1, &RORADC_absy, &ILL_3, &ADC_absx, &ROR_absx, &RORADC_absx,
  &ILL_2, &STA_indx, &ILL_2, &NDF_2, &STY_zp, &STA_zp, &STX_zp, &NDF_2,
  &DEY_, &ILL_2, &TXA_, &NDF_2, &STY_abs, &STA_abs, &STX_abs, &NDF_3,
  &BCC_, &STA_indy, &ILL_1, &NDF_2, &STY_zpx, &STA_zpx, &STX_zpy, &NDF_2,
  &TYA_, &STA_absy, &TXS_, &NDF_3, &NDF_3, &STA_absx, &NDF_3, &NDF_3,
  &LDY_imm, &LDA_indx, &LDX_imm, &NDF_2, &LDY_zp, &LDA_zp, &LDX_zp, &NDF_2,
  &TAY_, &LDA_imm, &TAX_, &ILL_1, &LDY_abs, &LDA_abs, &LDX_abs, &NDF_3,
  &BCS_, &LDA_indy, &ILL_1, &NDF_2, &LDY_zpx, &LDA_zpx, &LDX_zpy, &NDF_2,
  &CLV_, &LDA_absy, &TSX_, &NDF_3, &LDY_absx, &LDA_absx, &LDX_absy, &NDF_3,
  &CPY_imm, &CMP_indx, &ILL_2, &DECCMP_indx, &CPY_zp, &CMP_zp, &DEC_zp, &DECCMP_zp,
  &INY_, &CMP_imm, &DEX_, &NDF_2, &CPY_abs, &CMP_abs, &DEC_abs, &DECCMP_abs,
  &BNE_, &CMP_indy, &ILL_1, &DECCMP_indy, &ILL_2, &CMP_zpx, &DEC_zpx, &DECCMP_zpx,
  &CLD_, &CMP_absy, &ILL_1, &DECCMP_absy, &ILL_3, &CMP_absx, &DEC_absx, &DECCMP_absx,
  &CPX_imm, &SBC_indx, &ILL_2, &INCSBC_indx, &CPX_zp, &SBC_zp, &INC_zp, &INCSBC_zp,
  &INX_, &SBC_imm,  &NOP_, &NDF_2, &CPX_abs, &SBC_abs, &INC_abs, &INCSBC_abs,
  &BEQ_, &SBC_indy, &ILL_1, &INCSBC_indy, &ILL_2, &SBC_zpx, &INC_zpx, &INCSBC_zpx,
  &SED_, &SBC_absy, &ILL_1, &INCSBC_absy, &ILL_3, &SBC_absx, &INC_absx, &INCSBC_absx
};

//--------------------------------------------------

int interpreter(uword p, ubyte ramrom, ubyte a, ubyte x, ubyte y, ubyte plainflag)
{  
  PC = p;                 
  
  c64mem1[1] = ramrom;
  if ( plainflag )  {
    readdata = &readdata_plain;
    writedata = &writedata_plain;
	instrlist[0] = &BRK_plain;
  }
  else  {
    readdata = &readdata_bs;
    writedata = &writedata_bs;
	instrlist[0] = &BRK_;
  }
	
  AC = a; 
  XR = x; 
  YR = y;
  // SP to top of stack
  SP = 0x1ff;          
  clearSR();            
  sidkeys[4] = 0; 
  sidkeys[4+7] = 0;
  sidkeys[4+14] = 0;

  do  { 
    ubyte code = c64mem1[PC++];
    dataop1 = c64mem1[PC];
    dataop2 = c64mem1[PC +1];
    (*instrlist[code])();
  } while (SP <= 0x1ff);

  return(TRUE);
}
