M65C02.h

00001 // Welcome to the official first version of the OpenEm M6502-variant emulator.
00002 // This emulator was written with portability and ease of use in mind.
00003 
00004 //  It was originally meant just to host two varieties: M6502 and M65C02. However, it was decided
00005 // that it made sense to expand it to cover the ENTIRE 6500 family including 65816.
00006 
00007 //  The overall structure is based around a jump table: When an instruction is read, we jump
00008 // from a table of function pointers immediatly to its emulating function. Thus, there is
00009 // no need for up to 255 compares to find which opcode we're using and jump to it, nor is
00010 // there a need for expensive binary decoding. This is about as close to dynarec or static
00011 // translation speed as you can get in an interperater without using a state machine.
00012 //  Unfortunately, this approach is only useable on older processors: variable instruction
00013 // lengths can be handled with multiple jump tables, but as soon as you start introducing 16-bit
00014 // instructions, we're talking about 1meg+ jump tables that have no hope of ever fitting in
00015 // cache. In such a situation, it is far faster to simply bit-decode the instructions. (Unless, 
00016 // of course, you're working on something like an ARM processor where memory speed matches
00017 // processor speed. But this is relatively very rae.)
00018 
00019 //  When you first call the M65C02's init() function, it just zeroes things. Then, when you
00020 // call its set_mode() function, it fills in the jump table based on what processor you're
00021 // emulating.
00022 
00023 //  If you actually use this in an emulator, it is advisable to modify it slightly to your
00024 // needs. For instance, for an Atari 2600 emulator, you may wish to add in the HALT-TIL-END-
00025 // OF-SCANLINE functionality.
00026 
00027 //  This code is released under the LGPL. You can find what that means in the file 'LICENSE'
00028 // in the root directory of the LGPL.
00029 
00030 #ifndef __CPU_M65C02_H__
00031 #define __CPU_M65C02_H__
00032 
00033 #include "mempage.h"
00034 #include "cpu/cycle.h"
00035 
00036 #define M65C02_MODE_M6502       0   // Regular old M6502
00037 #define M65C02_MODE_M65C02      1   // M65C02. More opcodes, mostly. Used in commodore64, etc.
00038 #define M65C02_MODE_M65C02E     2   // Rockwell and CDP, more instructions
00039 #define M65C02_MODE_M6507       3   // Atari 2600 processor. Only 13 external address lines. For the purpose of speed, all 16 address lines are emulated as in a normal M6502. It's up to you to ignore the top 3 in your emulator.
00040 #define M65C02_MODE_M6508       4   // 8-bit I/O port, and 256 bytes built-in RAM. Both of which are emulated externally. See docs for more info.
00041 #define M65C02_MODE_M6509       5   // Built-in bank switching for up to 1mb of RAM. Other than that, a generic 6502.
00042 #define M65C02_MODE_M6510       6   // Regular M6502, with built-in 8-bit I/O port - supports undocumented opcodes
00043 #define M65C02_MODE_M6510T      7   // Same as M6510, no NMI/RDY inputs
00044 #define M65C02_MODE_SALLY       8   // Regular M6502, but with a HALT input. All but the earliest Atari 8-bit computers used this.
00045 #define M65C02_MODE_M6501       M65C02_MODE_M6502
00046 #define M65C02_MODE_2A03        9   // The NES's variant of the M6502. No Decimal mode, and memory mapped registers (which are emulated externally).
00047 #define M65C02_MODE_M65816      10  // 16-bit "upgrade". Boots up in M6502 emulation mode, has 16-bit mode.
00048 
00049 // State of the processor. Everything it needs to resume where it was.
00050 struct CPU_M65C02_STATE {
00051     byte X;     // X index register
00052     byte Y;     // Y index register
00053     byte A;     // Accumulator
00054     byte S;     // Status register
00055     word PC;    // Program counter
00056     byte SP;    // Stack pointer
00057     word procmode;  // Processor mode
00058     //dword cyclsleft;  // Cycles left
00059     uint32 NMI;         // NMI
00060     uint32 IRQ;         // IRQ
00061     uint32 HLT;         // HLT
00062     CPU_CYCLE_COUNT cycles;
00063 };
00064 
00065 // Struct that holds the information for each instruction, such as timing, etc.
00066 struct CPU_M65C02_ins {
00067     int amode;          // Addressing mode
00068     int cycl;           // # of cycles
00069     int size;           // Size of the instruction including addressing, in bytes
00070     int badd;           // How many cycles this will take extra if it branches
00071     int pbadd;          // How many cycles this will take extra of the branch crosses a page boundary
00072 };
00073 
00074 struct CPU_M65C02_DEBUG_STATE {
00075     uint32 flag;
00076     byte nextmem[3];
00077     CPU_M65C02_STATE s;
00078 };
00079 
00080 class CPU_M65C02 {
00081   public:
00082     void init();                            // 1) Call this on init
00083     void set_mode(int mode, int support);   // 2) Then call this to set the mode. Arguments 1: M65C02_MODE_xxxx for processor type. Argument 2 should be 0 to turn off nonstandard (undocumented) opcode support, anything else to turn it on.
00084                                             // 3) Make sure your memory is setup before you do step 4!
00085     void reset();                           // 4) Then call this to start the emulator. It will jump to the location contained at RESETVEC (0xFFFC)
00086                                             // Note that you MUST do all this before you use the processor, even restoring a state!
00087 
00088     CPU_CYCLE_COUNT cycles;
00089     void cycle(dword numleft);              // Do cycles!
00090 
00091     void save_state(CPU_M65C02_STATE *foo);     // Save the state!
00092     void restore_state(CPU_M65C02_STATE *foo);  // Restore the state!
00093 
00094     uint32 IRQ;                             // IRQ logic
00095     uint32 NMI;                             // NMI logic
00096     uint32 HLT;                             // Halt logic. Not implemented.
00097 
00098     // Debug support
00099     void set_debug_mode(uint16 mode);       // Set the debug mode!
00100     char *debug_str(CPU_M65C02_DEBUG_STATE *s); // Returns a string containing debug info dump
00101     CPU_DBGINF dbg;
00102     CPU_M65C02_DEBUG_STATE dbg_iop_state;   // Holds the debug state on illegal op
00103 
00104     // Memory system
00105     oe_pagetable mem;
00106 
00107   private:
00108     word atabl[256];
00109     
00110 //  void debugme(char *p);  // Debug output
00111     byte curins;    // internal use (current instruction)
00112 
00113     //dword cyclovr;    // This variable holds how many cycles are remaining on the current instruction
00114       
00115     byte X;     // X index register
00116     byte Y;     // Y index register
00117     byte A;     // Accumulator
00118     byte S;     // Status register
00119     word PC;    // Program counter
00120     byte SP;    // Stack pointer    
00121 
00122     int pb;     // Page boundary cross notifier
00123     int pba;    // Page boundary cross adder
00124     int r;      // If this is TRUE, the PC has been modified by the instruction and should not be touched by the main loop
00125     int pmode;  // Processor mode
00126     int bra;    // Branch add cycles #
00127 
00128     void setjumptable(int ins, int mode);   // Sets instruction jump table info
00129     CPU_M65C02_ins iinf[2][256];    // Various timing, addressing, etc. information for the instructions
00130 
00131     void (CPU_M65C02::*inst[2][256])(void);     // Instruction jump table
00132 
00133     dword mem_addr(int mode);               // Memory addressing thingy
00134 
00135     int procmode;   // The processor mode
00136 
00137     int support_undoc;              // Do we support undocumented opcodes?. NOT DONE YET
00138     int support_M65C;               // Do we support M65C02 opcodes? NOT DONE YET
00139     int support_M65CE;              // 65C02 extended instructions
00140     int support_M658;               // Do we support 16-bit M65816 opcodes? NOT DONE YET
00141     int support_HLT;                // Do we support the HLT instruction (SALLY)? NOT DONE YET
00142     int support_dec;                // Do we support decimal mode? NOT DONE YET
00143     int decmode;                    // Is decimal mode currently set?
00144     int support_irq;                // Do we support IRQs? IRQS WORK, FLAG NOT
00145     int support_nmi;                // Do we support NMIs? NMIS WORK, FLAG NOT
00146     int support_banks;              // Do we support 6509 bankswitching? NOT DONE YET
00147     int support_indjumpbug;         // Do we support the indirect jump bug? DONE
00148     int jumpbugmode;                // What is the jump bug mode?
00149 
00150     // Vectors
00151     dword IRQVEC;                   // IRQ
00152     dword RESETVEC;                 // RESET
00153     dword NMIVEC;                   // NMI
00154     dword ABORTVEC;                 // ABORT
00155     dword COPVEC;                   // COP
00156 
00157     // Debug stuff
00158     void IllegalOpcode();           // Illegal operation.
00159     
00160     // Regular M6502 Instructions
00161     void ADC();                     // Add memory to accumulator with carry
00162     void AND();                     // And memory with accumulator
00163     void ASL();                     // Shift left one bit (memory or accumulator)
00164     void ASLA();                    // Arithmetic shift left A-variant
00165     void BCC();                     // Branch on carry clear
00166     void BCS();                     // Branch on carry set
00167     void BEQ();                     // Branch on result 0
00168     void BIT();                     // Test bits in memory with accumulator
00169     void BMI();                     // Branch on result minus
00170     void BNE();                     // Branch on result not zero
00171     void BPL();                     // Branch on result plus
00172     void BRK();                     // Force break
00173     void BVC();                     // Branch on overflow clear
00174     void BVS();                     // Branch on overflow set
00175     void CLC();                     // Clear carry flag
00176     void CLD();                     // Clear decimal mode flag
00177     void CLI();                     // Clear interrupt disable bit
00178     void CLV();                     // Clear overflow flag
00179     void CMP();                     // Compare memory and accumulator
00180     void CPX();                     // Compare memory and Index X
00181     void CPY();                     // Compare memory and Index Y
00182     void DEC();                     // Decrement memory by 1
00183     void DEX();                     // Decrement X by 1
00184     void DEY();                     // Decrement Y by 1
00185     void EOR();                     // XOR memory with accumulator
00186     void INC();                     // Increment memory by 1
00187     void INX();                     // Increment X by 1
00188     void INY();                     // Increment Y by 1
00189     void JMP();                     // Jump to new location
00190     void JSR();                     // Jump to new location saving return address
00191     void LDA();                     // Load accumulator with memory
00192     void LDX();                     // Load X with memory
00193     void LDY();                     // Load Y with memory
00194     void LSR();                     // Shift right one bit accumulator or memory
00195     void LSRA();                    // Shift right one bit A
00196     void NOP();                     // No operation
00197     void ORA();                     // OR memory with accumulator
00198     void PHA();                     // Push A onto stack
00199     void PHP();                     // Push S onto stack
00200     void PLA();                     // Pop A
00201     void PLP();                     // Pop P
00202     void ROL();                     // Rotate one bit left (A or mem)
00203     void ROLA();                    // Rotate one bit left (A)
00204     void ROR();                     // Rotate one bit right (A or mem)
00205     void RORA();                    // Rotate one bit right (A)
00206     void RTI();                     // Return from interrupt
00207     void RTS();                     // Return from subroutine
00208     void SBC();                     // Subtract memory from accumulator with borrow
00209     void SEC();                     // Set Carry Flag
00210     void SED();                     // Set Decimal Mode
00211     void SEI();                     // Set Interrupt Disable status
00212     void STA();                     // Store Accumulator in memory
00213     void STX();                     // Store X in mem
00214     void STY();                     // Store Y in mem
00215     void TAX();                     // Transfer A to X
00216     void TAY();                     // Transfer A to Y
00217     void TSX();                     // Transfer SP(Stack Pointer) to X
00218     void TXA();                     // Transfer X to A
00219     void TXS();                     // Transfer X to SP
00220     void TYA();                     // Transfer Y to A
00221 
00222     // Undocumented opcodes
00223     void AAC(void);                 // AAC      AND byte with accumulator, set carry by N
00224     void AAX(void);                 // AAX      AND X with accumulator, set memory
00225     void ARR(void);                 //*ARR      AND byte with accumulator, local rotate accumulator 1 bit right, set V/C complexly
00226     void ASR(void);                 // ASR      AND byte with accumulator, then shift A right 1
00227     void ATX(void);                 // ATX      AND byte with accumulator, and TXA
00228     void AXA(void);                 // AXA      AND X with accumulator, then AND with 7, then store in memory
00229     void AXS(void);                 // AXS      AND X with accumulator, store result in X, subtract byte from X w/o borrow
00230     void DCP(void);                 // DCP      Decrement memory without borrow
00231     void DOP(void);                 // DOP      Double NO-OP, argument = no significance
00232     void ISC(void);                 // ISC      INC memory, then A - M with borrow
00233     void KIL(void);                 //*KIL      KIL a.k.a. HLT (halt)
00234     void LAX(void);
00235     void LAR(void);                 // LAR      Load accumulator and X with memory
00236     //void NOP(void);               // NOP      Other NOP's
00237     void RLA(void);                 //*RLA      Rotate memory one bit left, then AND accumulator with memory
00238     void RRA(void);                 //*RRA      Rotate memory one bit right, then ADC
00239     //void SBC(void);               // SBC      extra SBC
00240     void SLO(void);                 //*SLO      Shift memory left one bit, then ORA
00241     void SRE(void);                 //*SRE      Shift memory right one bit, then EOR
00242     void SXA(void);                 // SXA      AND X reg with (high byte of target addr)+1, store result in memory
00243     void SYA(void);                 // SYA      Same as SXA, but with Y
00244     void TOP(void);                 // TOP      Tripple NOP, arguments have no significance
00245     void XAA(void);                 //.XAA      Unknown
00246     void XAS(void);                 //*XAS      SP = X & A, M = SP & (high byte of target addr)+1};
00247     //* = Unsure of correctness
00248     //. = not implemented.
00249 };
00250 
00251 #endif

Generated on Sat Sep 9 03:50:43 2006 for Openem APIs by  doxygen 1.4.7