#include <alloc.h>
#include <stdio.h>
#include "atari.h"

#define DEBUG 1

class m6502;

//define a new type
typedef void (m6502::*Pftype)(void);
extern Pftype func[];


//binary coded decimal notation to 2s complement
#define DEC(a) ((((a)>>4)*10) + ((a)&0xf))

//End of stack
#define SP 0x100


class m6502
{
   Byte a;			//accumulator;
   Byte y;			//index register
   Byte x;			//Index register
   Byte s;			//stack pointer
   Status n;			//negative
   Status v;			//overflow
   Status b;			//break
   Status d;			//decimal
   Status i_;			//interupt disable
   Status z;			//zero
   Status c;			//carry
   Pin nmi;			//external pin
   Pin irq;			//interrupt
   Pin rdy;                     //ready
   Pin sync;			//opcode fetch cycle
   Pin reset_;			//reset processor on low
public:
   Byte clock;			//number of clock ticks
   Byte far *ram;
   Byte opcode;			//current opcode
   Word address;		//used for memory address computation
   Byte operand;		//holds operand
   Byte far *rom;		//identifies rom or ram memory
			//users sets rom[1024] =1 if memory location
			//1024 is rom
   Word pc;			//program counter
   Word intr_addr;

   char far *ch_optab;
   Byte far *optab;

//constructor routines
   m6502(void);
   void power_up(void);  //called to simulate power-up sequence
   void reset(void);     //called to emulate reset sequence

//microcode instruction
   //these should be macros
   void fetch_opcode(void) {opcode = ram[pc++];}
   void fetch_address(void);

//I don't know what I am going to do with these yet
   void interrupt_(void);
   void nmi_(void);

   Byte peek(Word add) {return(ram[add]);}

// special fuctions for handling user defined hardware
//These functions must be implemented by the user

   //Simplest form:
   //   write_ram(Word ram_address, Byte value) {ram[ram_address] = value;}
   //you can also this function for any special routines
   //required when ram_address points to emulated hardware.
   void write_ram(Word ram_address, Byte value);

   //Same as above except we write accumulator to ram[address]
   void write_ram(void);

   //same as above except ram[address] = value
   void write_ram(Byte value);

   void read_ram(Word ram_address);

   //Used to update emulated hardware when needed
   void hardware_update(void);

   //Steal the jsr to perform your own routine.  Bypass the
   //6502 emulator to speed execution.  For example, all
   //OS calls can be written in 'C' rather than using the
   //6502 routines.
   //Always call frts() before returning.
   //If you don't want to steal the jsr just use:
   //            void steal_jsr(Word address) {};
   void steal_jsr(Word);

   //Can be called by write_ram() if the address points to a hardware
   //location.
   void hardware_write(Word,Byte);

//for debug
   void print_reg(void);
   void print_opcode(void);
   void setup_print(void);
//also should be a macro
   void copy_address(Word mem,Word addr)
   {
      ram[mem] = Byte((addr)&0xff);
      ram[mem+1] = Byte(addr>>8);
   }

   void copy_bytes(Word addr, Word num, Byte huge *mem);

//opcode is public.  Why is this here?
   Byte get_opcode(void) {return opcode;}

//OpCodes  for 6502
   void opcode_setup(void);
   void fBRK(void);
   void fORA_IND_X(void);
   void fNOP_(void);
   void fORA_ZP(void);
   void fASL_ZP(void);
   void fPHP(void);
   void fORA_IMM(void);
   void fASL_A(void);
   void fORA_ABS(void);
   void fASL_ABS(void);
   void fBPL(void);
   void fORA_IND_Y(void);
   void fORA_ZP_X(void);
   void fASL_ZP_X(void);
   void fCLC_(void);
   void fORA_ABS_Y(void);
   void fORA_ABS_X(void);
   void fASL_ABS_X(void);
   void fJSR(void);
   void fAND_IND_X(void);
   void fBIT_ZP(void);
   void fAND_ZP(void);
   void fROL_ZP(void);
   void fPLP(void);
   void fAND_IMM(void);
   void fROL_A(void);
   void fBIT_ABS(void);
   void fAND_ABS(void);
   void fROL_ABS(void);
   void fBMI(void);
   void fAND_IND_Y(void);
   void fAND_ZP_X(void);
   void fROL_ZP_X(void);
   void fSEC(void);
   void fAND_ABS_Y(void);
   void fAND_ABS_X(void);
   void fROL_ABS_X(void);
   void fRTI(void);
   void fEOR_IND_X(void);
   void fEOR_ZP(void);
   void fLSR_ZP(void);
   void fPHA(void);
   void fEOR_IMM(void);
   void fLSR_A(void);
   void fJMP_ABS(void);
   void fEOR_ABS(void);
   void fLSR_ABS(void);
   void fBVC(void);
   void fEOR_IND_Y(void);
   void fEOR_ZP_X(void);
   void fLSR_ZP_X(void);
   void fCLI_(void);
   void fEOR_ABS_Y(void);
   void fEOR_ABS_X(void);
   void fLSR_ABS_X(void);
   void fRTS(void);
   void fADC_IND_X(void);
   void fADC_ZP(void);
   void fROR_ZP(void);
   void fPLA(void);
   void fADC_IMM(void);
   void fROR_A(void);
   void fJMP_IND(void);
   void fADC_ABS(void);
   void fROR_ABS(void);
   void fBVS(void);
   void fADC_IND_Y(void);
   void fADC_ZP_X(void);
   void fROR_ZP_X(void);
   void fSEI(void);
   void fADC_ABS_Y(void);
   void fADC_ABS_X(void);
   void fROR_ABS_X(void);
   void fSTA_IND_X(void);
   void fSTY_ZP(void);
   void fSTA_ZP(void);
   void fSTX_ZP(void);
   void fDEY(void);
   void fTXA(void);
   void fSTY_ABS(void);
   void fSTA_ABS(void);
   void fSTX_ABS(void);
   void fBCC(void);
   void fSTA_IND_Y(void);
   void fSTY_ZP_X(void);
   void fSTA_ZP_X(void);
   void fSTX_ZP_Y(void);
   void fTYA(void);
   void fSTA_ABS_Y(void);
   void fTXS(void);
   void fSTA_ABS_X(void);
   void fLDY_IMM(void);
   void fLDA_IND_X(void);
   void fLDX_IMM(void);
   void fLDY_ZP(void);
   void fLDA_ZP(void);
   void fLDX_ZP(void);
   void fTAY(void);
   void fLDA_IMM(void);
   void fTAX(void);
   void fLDY_ABS(void);
   void fLDA_ABS(void);
   void fLDX_ABS(void);
   void fBCS(void);
   void fLDA_IND_Y(void);
   void fLDY_ZP_X(void);
   void fLDA_ZP_X(void);
   void fLDX_ZP_Y(void);
   void fCLV_(void);
   void fLDA_ABS_Y(void);
   void fTSX(void);
   void fLDY_ABS_X(void);
   void fLDA_ABS_X(void);
   void fLDX_ABS_Y(void);
   void fCPY_IMM(void);
   void fCMP_IND_X(void);
   void fCPY_ZP(void);
   void fCMP_ZP(void);
   void fDEC_ZP(void);
   void fINY(void);
   void fCMP_IMM(void);
   void fDEX(void);
   void fCPY_ABS(void);
   void fCMP_ABS(void);
   void fDEC_ABS(void);
   void fBNE(void);
   void fCMP_IND_Y(void);
   void fCMP_ZP_X(void);
   void fDEC_ZP_X(void);
   void fCLD_(void);
   void fCMP_ABS_Y(void);
   void fCMP_ABS_X(void);
   void fDEC_ABS_X(void);
   void fCPX_IMM(void);
   void fSBC_IND_X(void);
   void fCPX_ZP(void);
   void fSBC_ZP(void);
   void fINC_ZP(void);
   void fINX(void);
   void fSBC_IMM(void);
   void fCPX_ABS(void);
   void fSBC_ABS(void);
   void fINC_ABS(void);
   void fBEQ(void);
   void fSBC_IND_Y(void);
   void fSBC_ZP_X(void);
   void fINC_ZP_X(void);
   void fSED(void);
   void fSBC_ABS_Y(void);
   void fSBC_ABS_X(void);
   void fINC_ABS_X(void);
};
