#ifndef MKCPU_H #define MKCPU_H #include #include #include #include "system.h" #include "Memory.h" using namespace std; namespace MKBasic { #define DISS_BUF_SIZE 60 // disassembled instruction buffer size struct Regs { unsigned char Acc; // 8-bit accumulator unsigned short Acc16; // 16-bit accumulator unsigned char IndX; // 8-bit index register X unsigned char IndY; // 8-bit index register Y unsigned short Ptr16; // general purpose 16-bit register unsigned short PtrAddr; // cpu code counter (PC) - current read/write address unsigned char PtrStack; // 8-bit stack pointer (0-255). unsigned char Flags; // CPU flags bool SoftIrq; // true when interrupted with BRK or trapped opcode bool LastRTS; // true if RTS encountered and stack empty. unsigned short LastAddr; // PC at the time of previous op-code string LastInstr; // instruction and argument executed in previous step int LastOpCode; // op-code of last instruction unsigned short LastArg; // argument to the last instruction int LastAddrMode; // addressing mode of last instruction }; /* * Virtual CPU, 6502 addressing modes: +---------------------+--------------------------+ | mode | assembler format | +=====================+==========================+ | Immediate | #aa | | Absolute | aaaa | | Zero Page | aa | Note: | Implied | | | Indirect Absolute | (aaaa) | aa = 2 hex digits | Absolute Indexed,X | aaaa,X | as $FF | Absolute Indexed,Y | aaaa,Y | | Zero Page Indexed,X | aa,X | aaaa = 4 hex | Zero Page Indexed,Y | aa,Y | digits as | Indexed Indirect | (aa,X) | $FFFF | Indirect Indexed | (aa),Y | | Relative | aaaa | Can also be | Accumulator | A | assembler labels +---------------------+--------------------------+ Short notation: imm = #$00 zp = $00 zpx = $00,X zpy = $00,Y izx = ($00,X) izy = ($00),Y abs = $0000 abx = $0000,X aby = $0000,Y ind = ($0000) rel = $0000 (PC-relative) See: 6502AssemblyInOneStep.txt for details. */ enum eAddrModes { ADDRMODE_IMM = 0, ADDRMODE_ABS, ADDRMODE_ZP, ADDRMODE_IMP, ADDRMODE_IND, ADDRMODE_ABX, ADDRMODE_ABY, ADDRMODE_ZPX, ADDRMODE_ZPY, ADDRMODE_IZX, ADDRMODE_IZY, ADDRMODE_REL, ADDRMODE_ACC, ADDRMODE_UND, // undetermined (for some illegal codes) ADDRMODE_LENGTH // should be always last }; // assumed little-endian order of bytes (start with least significant) // MEM - memory location from where the value is read/written, // & - reference operator (e.g.: &addr means: value under addr memory location) // PC - program counter (PC+1 means - next memory location after opcode) enum eOpCodes { OPCODE_BRK = 0x00, // software interrupt, no arguments ($00 : BRK) /* full compatibility with 65C02 (illegal opcodes not supported, will be used for extended functions */ OPCODE_ORA_IZX = 0x01, // bitwise OR with Accumulator, Indexed Indirect ($01 arg : ORA (arg,X) ;arg=0..$FF), MEM=&(arg+X) OPCODE_ILL_02 = 0x02, // illegal opcode OPCODE_ILL_03 = 0x03, // illegal opcode OPCODE_ILL_04 = 0x04, // illegal opcode OPCODE_ORA_ZP = 0x05, // bitwise OR with Accumulator, Zero Page ($05 arg : ORA arg ;arg=0..$FF), MEM=arg OPCODE_ASL_ZP = 0x06, // Arithmetic Shift Left, Zero Page ($06 arg : ASL arg ;arg=0..$FF), MEM=arg OPCODE_ILL_07 = 0x07, // illegal opcode OPCODE_PHP = 0x08, // PusH Processor status on Stack, Implied ($08 : PHP) OPCODE_ORA_IMM = 0x09, // bitwise OR with Accumulator, Immediate ($09 arg : ORA #arg ;arg=0..$FF), MEM=PC+1 OPCODE_ASL = 0x0A, // Arithmetic Shift Left, Accumulator ($0A : ASL) OPCODE_ILL_0B = 0x0B, // illegal opcode OPCODE_ILL_0C = 0x0C, // illegal opcode OPCODE_ORA_ABS = 0x0D, // bitwise OR with Accumulator, Absolute ($0D addrlo addrhi : ORA addr ;addr=0..$FFFF), MEM=addr OPCODE_ASL_ABS = 0x0E, // Arithmetic Shift Left, Absolute ($0E addrlo addrhi : ASL addr ;addr=0..$FFFF), MEM=addr OPCODE_ILL_0F = 0x0F, // illegal opcode OPCODE_BPL_REL = 0x10, // Branch on PLus, Relative ($10 signoffs : BPL signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)]) OPCODE_ORA_IZY = 0x11, // bitwise OR with Accumulator, Indirect Indexed ($11 arg : ORA (arg),Y ;arg=0..$FF), MEM=&arg+Y OPCODE_ILL_12 = 0x12, // illegal opcode OPCODE_ILL_13 = 0x13, // illegal opcode OPCODE_ILL_14 = 0x14, // illegal opcode OPCODE_ORA_ZPX = 0x15, // bitwise OR with Accumulator, Zero Page Indexed, X ($15 arg : ORA arg,X ;arg=0..$FF), MEM=arg+X OPCODE_ASL_ZPX = 0x16, // Arithmetic Shift Left, Zero Page Indexed, X ($16 arg : ASL arg,X ;arg=0..$FF), MEM=arg+X OPCODE_ILL_17 = 0x17, // illegal opcode OPCODE_CLC = 0x18, // CLear Carry, Implied ($18 : CLC) OPCODE_ORA_ABY = 0x19, // bitwise OR with Accumulator, Absolute Indexed, Y ($19 addrlo addrhi : ORA addr,Y ;addr=0..$FFFF), MEM=addr+Y OPCODE_ILL_1A = 0x1A, // illegal opcode OPCODE_ILL_1B = 0x1B, // illegal opcode OPCODE_ILL_1C = 0x1C, // illegal opcode OPCODE_ORA_ABX = 0x1D, // bitwise OR with Accumulator, Absolute Indexed, X ($1D addrlo addrhi : ORA addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_ASL_ABX = 0x1E, // Arithmetic Shift Left, Absolute Indexed, X ($1E addrlo addrhi : ASL addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_ILL_1F = 0x1F, // illegal opcode OPCODE_JSR_ABS = 0x20, // Jump to SubRoutine, Absolute ($20 addrlo addrhi : JSR addr ;addr=0..$FFFF), MEM=addr OPCODE_AND_IZX = 0x21, // bitwise AND with accumulator, Indexed Indirect ($21 arg : AND (arg,X) ;arg=0..$FF), MEM=&(arg+X) OPCODE_ILL_22 = 0x22, // illegal opcode OPCODE_ILL_23 = 0x23, // illegal opcode OPCODE_BIT_ZP = 0x24, // test BITs, Zero Page ($24 arg : BIT arg ;arg=0..$FF), MEM=arg OPCODE_AND_ZP = 0x25, // bitwise AND with accumulator, Zero Page ($25 arg : AND arg ;arg=0..$FF), MEM=arg OPCODE_ROL_ZP = 0x26, // ROtate Left, Zero Page ($26 arg : ROL arg ;arg=0..$FF), MEM=arg OPCODE_ILL_27 = 0x27, // illegal opcode OPCODE_PLP = 0x28, // PuLl Processor status, Implied ($28 : PLP) OPCODE_AND_IMM = 0x29, // bitwise AND with accumulator, Immediate ($29 arg : AND #arg ;arg=0..$FF), MEM=PC+1 OPCODE_ROL = 0x2A, // ROtate Left, Accumulator ($2A : ROL) OPCODE_ILL_2B = 0x2B, // illegal opcode OPCODE_BIT_ABS = 0x2C, // test BITs, Absolute ($2C addrlo addrhi : BIT addr ;addr=0..$FFFF), MEM=addr OPCODE_AND_ABS = 0x2D, // bitwise AND with accumulator, Absolute ($2D addrlo addrhi : AND addr ;addr=0..$FFFF), MEM=addr OPCODE_ROL_ABS = 0x2E, // ROtate Left, Absolute ($2E addrlo addrhi : ROL addr ;addr=0..$FFFF), MEM=addr OPCODE_ILL_2F = 0x2F, // illegal opcode OPCODE_BMI_REL = 0x30, // Branch on MInus, Relative ($30 signoffs : BMI signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)]) OPCODE_AND_IZY = 0x31, // bitwise AND with accumulator, Indirect Indexed ($31 arg : AND (arg),Y ;arg=0..$FF), MEM=&arg+Y OPCODE_ILL_32 = 0x32, // illegal opcode OPCODE_ILL_33 = 0x33, // illegal opcode OPCODE_ILL_34 = 0x34, // illegal opcode OPCODE_AND_ZPX = 0x35, // bitwise AND with accumulator, Zero Page Indexed, X ($35 arg : AND arg,X ;arg=0..$FF), MEM=arg+X OPCODE_ROL_ZPX = 0x36, // ROtate Left, Zero Page Indexed, X ($36 arg : ROL arg,X ;arg=0..$FF), MEM=arg+X OPCODE_ILL_37 = 0x37, // illegal opcode OPCODE_SEC = 0x38, // SEt Carry, Implied ($38 : SEC) OPCODE_AND_ABY = 0x39, // bitwise AND with accumulator, Absolute Indexed, Y ($39 addrlo addrhi : AND addr,Y ;addr=0..$FFFF), MEM=addr+Y OPCODE_ILL_3A = 0x3A, // illegal opcode OPCODE_ILL_3B = 0x3B, // illegal opcode OPCODE_ILL_3C = 0x3C, // illegal opcode OPCODE_AND_ABX = 0x3D, // bitwise AND with accumulator, Absolute Indexed, X ($3D addrlo addrhi : AND addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_ROL_ABX = 0x3E, // ROtate Left, Absolute Indexed, X ($3E addrlo addrhi : ROL addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_ILL_3F = 0x3F, // illegal opcode OPCODE_RTI = 0x40, // ReTurn from Interrupt, Implied ($40 : RTI) OPCODE_EOR_IZX = 0x41, // bitwise Exclusive OR, Indexed Indirect ($41 arg : EOR (arg,X) ;arg=0..$FF), MEM=&(arg+X) OPCODE_ILL_42 = 0x42, // illegal opcode OPCODE_ILL_43 = 0x43, // illegal opcode OPCODE_ILL_44 = 0x44, // illegal opcode OPCODE_EOR_ZP = 0x45, // bitwise Exclusive OR, Zero Page ($45 arg : EOR arg ;arg=0..$FF), MEM=arg OPCODE_LSR_ZP = 0x46, // Logical Shift Right, Zero Page ($46 arg : LSR arg ;arg=0..$FF), MEM=arg OPCODE_ILL_47 = 0x47, // illegal opcode OPCODE_PHA = 0x48, // PusH Accumulator, Implied ($48 : PHA) OPCODE_EOR_IMM = 0x49, // bitwise Exclusive OR, Immediate ($49 arg : EOR #arg ;arg=0..$FF), MEM=PC+1 OPCODE_LSR = 0x4A, // Logical Shift Right, Accumulator ($4A : LSR) OPCODE_ILL_4B = 0x4B, // illegal opcode OPCODE_JMP_ABS = 0x4C, // JuMP, Absolute ($4C addrlo addrhi : JMP addr ;addr=0..$FFFF), MEM=addr OPCODE_EOR_ABS = 0x4D, // bitwise Exclusive OR, Absolute ($4D addrlo addrhi : EOR addr ;addr=0..$FFFF), MEM=addr OPCODE_LSR_ABS = 0x4E, // Logical Shift Right, Absolute ($4E addrlo addrhi : LSR addr ;addr=0..$FFFF), MEM=addr OPCODE_ILL_4F = 0x4F, // illegal opcode OPCODE_BVC_REL = 0x50, // Branch on oVerflow Clear, Relative ($50 signoffs : BVC signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)]) OPCODE_EOR_IZY = 0x51, // bitwise Exclusive OR, Indirect Indexed ($51 arg : EOR (arg),Y ;arg=0..$FF), MEM=&arg+Y OPCODE_ILL_52 = 0x52, // illegal opcode OPCODE_ILL_53 = 0x53, // illegal opcode OPCODE_ILL_54 = 0x54, // illegal opcode OPCODE_EOR_ZPX = 0x55, // bitwise Exclusive OR, Zero Page Indexed, X ($55 arg : EOR arg,X ;arg=0..$FF), MEM=arg+X OPCODE_LSR_ZPX = 0x56, // Logical Shift Right, Zero Page Indexed, X ($56 arg : LSR arg,X ;arg=0..$FF), MEM=arg+X OPCODE_ILL_57 = 0x57, // illegal opcode OPCODE_CLI = 0x58, // CLear Interrupt, Implied ($58 : CLI) OPCODE_EOR_ABY = 0x59, // bitwise Exclusive OR, Absolute Indexed, Y ($59 addrlo addrhi : EOR addr,Y ;addr=0..$FFFF), MEM=addr+Y OPCODE_ILL_5A = 0x5A, // illegal opcode OPCODE_ILL_5B = 0x5B, // illegal opcode OPCODE_ILL_5C = 0x5C, // illegal opcode OPCODE_EOR_ABX = 0x5D, // bitwise Exclusive OR, Absolute Indexed, X ($5D addrlo addrhi : EOR addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_LSR_ABX = 0x5E, // Logical Shift Right, Absolute Indexed, X ($5E addrlo addrhi : LSR addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_ILL_5F = 0x5F, // illegal opcode OPCODE_RTS = 0x60, // ReTurn from Subroutine, Implied ($60 : RTS) OPCODE_ADC_IZX = 0x61, // ADd with Carry, Indexed Indirect ($61 arg : ADC (arg,X) ;arg=0..$FF), MEM=&(arg+X) OPCODE_ILL_62 = 0x62, // illegal opcode OPCODE_ILL_63 = 0x63, // illegal opcode OPCODE_ILL_64 = 0x64, // illegal opcode OPCODE_ADC_ZP = 0x65, // ADd with Carry, Zero Page ($65 arg : ADC arg ;arg=0..$FF), MEM=arg OPCODE_ROR_ZP = 0x66, // ROtate Right, Zero Page ($66 arg : ROR arg ;arg=0..$FF), MEM=arg OPCODE_ILL_67 = 0x67, // illegal opcode OPCODE_PLA = 0x68, // PuLl Accumulator, Implied ($68 : PLA) OPCODE_ADC_IMM = 0x69, // ADd with Carry, Immediate ($69 arg : ADC #arg ;arg=0..$FF), MEM=PC+1 OPCODE_ROR = 0x6A, // ROtate Right, Accumulator ($6A : ROR) OPCODE_ILL_6B = 0x6B, // illegal opcode OPCODE_JMP_IND = 0x6C, // JuMP, Indirect Absolute ($6C addrlo addrhi : JMP (addr) ;addr=0..FFFF), MEM=&addr OPCODE_ADC_ABS = 0x6D, // ADd with Carry, Absolute ($6D addrlo addrhi : ADC addr ;addr=0..$FFFF), MEM=addr OPCODE_ROR_ABS = 0x6E, // ROtate Right, Absolute ($6E addrlo addrhi : ROR addr ;addr=0..$FFFF), MEM=addr OPCODE_ILL_6F = 0x6F, // illegal opcode OPCODE_BVS_REL = 0x70, // Branch on oVerflow Set, Relative ($70 signoffs : BVS signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)]) OPCODE_ADC_IZY = 0x71, // ADd with Carry, Indirect Indexed ($71 arg : ADC (arg),Y ;arg=0..$FF), MEM=&arg+Y OPCODE_ILL_72 = 0x72, // illegal opcode OPCODE_ILL_73 = 0x73, // illegal opcode OPCODE_ILL_74 = 0x74, // illegal opcode OPCODE_ADC_ZPX = 0x75, // ADd with Carry, Zero Page Indexed, X ($75 arg : ADC arg,X ;arg=0..$FF), MEM=arg+X OPCODE_ROR_ZPX = 0x76, // ROtate Right, Zero Page Indexed, X ($76 arg : ROR arg,X ;arg=0..$FF), MEM=arg+X OPCODE_ILL_77 = 0x77, // illegal opcode OPCODE_SEI = 0x78, // SEt Interrupt, Implied ($78 : SEI) OPCODE_ADC_ABY = 0x79, // ADd with Carry, Absolute Indexed, Y ($79 addrlo addrhi : ADC addr,Y ;addr=0..$FFFF), MEM=addr+Y OPCODE_ILL_7A = 0x7A, // illegal opcode OPCODE_ILL_7B = 0x7B, // illegal opcode OPCODE_ILL_7C = 0x7C, // illegal opcode OPCODE_ADC_ABX = 0x7D, // ADd with Carry, Absolute Indexed, X ($7D addrlo addrhi : ADC addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_ROR_ABX = 0x7E, // ROtate Right, Absolute Indexed, X ($7E addrlo addrhi : ROR addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_ILL_7F = 0x7F, // illegal opcode OPCODE_ILL_80 = 0x80, // illegal opcode OPCODE_STA_IZX = 0x81, // STore Accumulator, Indexed Indirect ($81 arg : STA (arg,X) ;arg=0..$FF), MEM=&(arg+X) OPCODE_ILL_82 = 0x82, // illegal opcode OPCODE_ILL_83 = 0x83, // illegal opcode OPCODE_STY_ZP = 0x84, // STore Y register, Zero Page ($84 arg : STY arg ;arg=0..$FF), MEM=arg OPCODE_STA_ZP = 0x85, // STore Accumulator, Zero Page ($85 arg : STA arg ;arg=0..$FF), MEM=arg OPCODE_STX_ZP = 0x86, // STore X register, Zero Page ($86 arg : STX arg ;arg=0..$FF), MEM=arg OPCODE_ILL_87 = 0x87, // illegal opcode OPCODE_DEY = 0x88, // DEcrement Y, Implied ($88 : DEY) OPCODE_ILL_89 = 0x89, // illegal opcode OPCODE_TXA = 0x8A, // Transfer X to A, Implied ($8A : TXA) OPCODE_ILL_8B = 0x8B, // illegal opcode OPCODE_STY_ABS = 0x8C, // STore Y register, Absolute ($8C addrlo addrhi : STY addr ;addr=0..$FFFF), MEM=addr OPCODE_STA_ABS = 0x8D, // STore Accumulator, Absolute ($8D addrlo addrhi : STA addr ;addr=0..$FFFF), MEM=addr OPCODE_STX_ABS = 0x8E, // STore X register, Absolute ($8E addrlo addrhi : STX addr ;addr=0..$FFFF), MEM=addr OPCODE_ILL_8F = 0x8F, // illegal opcode OPCODE_BCC_REL = 0x90, // Branch on Carry Clear, Relative ($90 signoffs : BCC signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)]) OPCODE_STA_IZY = 0x91, // STore Accumulator, Indirect Indexed ($91 arg : STA (arg),Y ;arg=0..$FF), MEM=&arg+Y OPCODE_ILL_92 = 0x92, // illegal opcode OPCODE_ILL_93 = 0x93, // illegal opcode OPCODE_STY_ZPX = 0x94, // STore Y register, Zero Page Indexed, X ($94 arg : STY arg,X ;arg=0..$FF), MEM=arg+X OPCODE_STA_ZPX = 0x95, // STore Accumulator, Zero Page Indexed, X ($95 arg : STA arg,X ;arg=0..$FF), MEM=arg+X OPCODE_STX_ZPY = 0x96, // STore X register, Zero Page Indexed, Y ($96 arg : STX arg,Y ;arg=0..$FF), MEM=arg+Y OPCODE_ILL_97 = 0x97, // illegal opcode OPCODE_TYA = 0x98, // Transfer Y to A, Implied ($98 : TYA) OPCODE_STA_ABY = 0x99, // STore Accumulator, Absolute Indexed, Y ($99 addrlo addrhi : STA addr,Y ;addr=0..$FFFF), MEM=addr+Y OPCODE_TXS = 0x9A, // Transfer X to Stack ptr, Implied ($9A : TXS) OPCODE_ILL_9B = 0x9B, // illegal opcode OPCODE_ILL_9C = 0x9C, // illegal opcode OPCODE_STA_ABX = 0x9D, // STore Accumulator, Absolute Indexed, X ($9D addrlo addrhi : STA addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_ILL_9E = 0x9E, // illegal opcode OPCODE_ILL_9F = 0x9F, // illegal opcode OPCODE_LDY_IMM = 0xA0, // LoaD Y register, Immediate ($A0 arg : LDY #arg ;arg=0..$FF), MEM=PC+1 OPCODE_LDA_IZX = 0xA1, // LoaD Accumulator, Indexed Indirect ($A1 arg : LDA (arg,X) ;arg=0..$FF), MEM=&(arg+X) OPCODE_LDX_IMM = 0xA2, // LoaD X register, Immediate ($A2 arg : LDX #arg ;arg=0..$FF), MEM=PC+1 OPCODE_ILL_A3 = 0xA3, // illegal opcode OPCODE_LDY_ZP = 0xA4, // LoaD Y register, Zero Page ($A4 arg : LDY arg ;arg=0..$FF), MEM=arg OPCODE_LDA_ZP = 0xA5, // LoaD Accumulator, Zero Page ($A5 arg : LDA arg ;arg=0..$FF), MEM=arg OPCODE_LDX_ZP = 0xA6, // LoaD X register, Zero Page ($A6 arg : LDX arg ;arg=0..$FF), MEM=arg OPCODE_ILL_A7 = 0xA7, // illegal opcode OPCODE_TAY = 0xA8, // Transfer A to Y, Implied ($A8 : TAY) OPCODE_LDA_IMM = 0xA9, // LoaD Accumulator, Immediate ($A9 arg : LDA #arg ;arg=0..$FF), MEM=PC+1 OPCODE_TAX = 0xAA, // Transfer A to X, Implied ($AA : TAX) OPCODE_ILL_AB = 0xAB, // illegal opcode OPCODE_LDY_ABS = 0xAC, // LoaD Y register, Absolute ($AC addrlo addrhi : LDY addr ;addr=0..$FFFF), MEM=addr OPCODE_LDA_ABS = 0xAD, // LoaD Accumulator, Absolute ($AD addrlo addrhi : LDA addr ;addr=0..$FFFF), MEM=addr OPCODE_LDX_ABS = 0xAE, // LoaD X register, Absolute ($AE addrlo addrhi : LDX addr ;addr=0..$FFFF), MEM=addr OPCODE_ILL_AF = 0xAF, // illegal opcode OPCODE_BCS_REL = 0xB0, // Branch on Carry Set, Relative ($B0 signoffs : BCS signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)]) OPCODE_LDA_IZY = 0xB1, // LoaD Accumulator, Indirect Indexed ($B1 arg : LDA (arg),Y ;arg=0..$FF), MEM=&arg+Y OPCODE_ILL_B2 = 0xB2, // illegal opcode OPCODE_ILL_B3 = 0xB3, // illegal opcode OPCODE_LDY_ZPX = 0xB4, // LoaD Y register, Zero Page Indexed, X ($B4 arg : LDY arg,X ;arg=0..$FF), MEM=arg+X OPCODE_LDA_ZPX = 0xB5, // LoaD Accumulator, Zero Page Indexed, X ($B5 arg : LDA arg,X ;arg=0..$FF), MEM=arg+X OPCODE_LDX_ZPY = 0xB6, // LoaD X register, Zero Page Indexed, Y ($B6 arg : LDX arg,Y ;arg=0..$FF), MEM=arg+Y OPCODE_ILL_B7 = 0xB7, // illegal opcode OPCODE_CLV = 0xB8, // CLear oVerflow, Implied ($B8 : CLV) OPCODE_LDA_ABY = 0xB9, // LoaD Accumulator, Absolute Indexed, Y ($B9 addrlo addrhi : LDA addr,Y ;addr=0..$FFFF), MEM=addr+Y OPCODE_TSX = 0xBA, // Transfer Stack ptr to X, Implied ($BA : TSX) OPCODE_ILL_BB = 0xBB, // illegal opcode OPCODE_LDY_ABX = 0xBC, // LoaD Y register, Absolute Indexed, X ($BC addrlo addrhi : LDY addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_LDA_ABX = 0xBD, // LoaD Accumulator, Absolute Indexed, X ($BD addrlo addrhi : LDA addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_LDX_ABY = 0xBE, // LoaD X register, Absolute Indexed, Y ($BE addrlo addrhi : LDX addr,Y ;addr=0..$FFFF), MEM=addr+Y OPCODE_ILL_BF = 0xBF, // illegal opcode OPCODE_CPY_IMM = 0xC0, // ComPare Y register, Immediate ($C0 arg : CPY #arg ;arg=0..$FF), MEM=PC+1 OPCODE_CMP_IZX = 0xC1, // CoMPare accumulator, Indexed Indirect ($A1 arg : LDA (arg,X) ;arg=0..$FF), MEM=&(arg+X) OPCODE_ILL_C2 = 0xC2, // illegal opcode OPCODE_ILL_C3 = 0xC3, // illegal opcode OPCODE_CPY_ZP = 0xC4, // ComPare Y register, Zero Page ($C4 arg : CPY arg ;arg=0..$FF), MEM=arg OPCODE_CMP_ZP = 0xC5, // CoMPare accumulator, Zero Page ($C5 arg : CMP arg ;arg=0..$FF), MEM=arg OPCODE_DEC_ZP = 0xC6, // DECrement memory, Zero Page ($C6 arg : DEC arg ;arg=0..$FF), MEM=arg OPCODE_ILL_C7 = 0xC7, // illegal opcode OPCODE_INY = 0xC8, // INcrement Y, Implied ($C8 : INY)OPCODE_INY = 0xC8, // INcrement Y, Implied ($C8 : INY) OPCODE_CMP_IMM = 0xC9, // CoMPare accumulator, Immediate ($C9 arg : CMP #arg ;arg=0..$FF), MEM=PC+1 OPCODE_DEX = 0xCA, // DEcrement X, Implied ($CA : DEX) OPCODE_ILL_CB = 0xCB, // illegal opcode OPCODE_CPY_ABS = 0xCC, // ComPare Y register, Absolute ($CC addrlo addrhi : CPY addr ;addr=0..$FFFF), MEM=addr OPCODE_CMP_ABS = 0xCD, // CoMPare accumulator, Absolute ($CD addrlo addrhi : CMP addr ;addr=0..$FFFF), MEM=addr OPCODE_DEC_ABS = 0xCE, // DECrement memory, Absolute ($CE addrlo addrhi : CMP addr ;addr=0..$FFFF), MEM=addr OPCODE_ILL_CF = 0xCF, // illegal opcode OPCODE_BNE_REL = 0xD0, // Branch on Not Equal, Relative ($D0 signoffs : BNE signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)]) OPCODE_CMP_IZY = 0xD1, // CoMPare accumulator, Indirect Indexed ($D1 arg : CMP (arg),Y ;arg=0..$FF), MEM=&arg+Y OPCODE_ILL_D2 = 0xD2, // illegal opcode OPCODE_ILL_D3 = 0xD3, // illegal opcode OPCODE_ILL_D4 = 0xD4, // illegal opcode OPCODE_CMP_ZPX = 0xD5, // CoMPare accumulator, Zero Page Indexed, X ($D5 arg : CMP arg,X ;arg=0..$FF), MEM=arg+X OPCODE_DEC_ZPX = 0xD6, // DECrement memory, Zero Page Indexed, X ($D6 arg : DEC arg,X ;arg=0..$FF), MEM=arg+X OPCODE_ILL_D7 = 0xD7, // illegal opcode OPCODE_CLD = 0xD8, // CLear Decimal, Implied ($D8 : CLD) OPCODE_CMP_ABY = 0xD9, // CoMPare accumulator, Absolute Indexed, Y ($D9 addrlo addrhi : CMP addr,Y ;addr=0..$FFFF), MEM=addr+Y OPCODE_ILL_DA = 0xDA, // illegal opcode OPCODE_ILL_DB = 0xDB, // illegal opcode OPCODE_ILL_DC = 0xDC, // illegal opcode OPCODE_CMP_ABX = 0xDD, // CoMPare accumulator, Absolute Indexed, X ($DD addrlo addrhi : CMP addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_DEC_ABX = 0xDE, // DECrement memory, Absolute Indexed, X ($DE addrlo addrhi : DEC addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_ILL_DF = 0xDF, // illegal opcode OPCODE_CPX_IMM = 0xE0, // ComPare X register, Immediate ($E0 arg : CPX #arg ;arg=0..$FF), MEM=PC+1 OPCODE_SBC_IZX = 0xE1, // SuBtract with Carry, Indexed Indirect ($E1 arg : SBC (arg,X) ;arg=0..$FF), MEM=&(arg+X) OPCODE_ILL_E2 = 0xE2, // illegal opcode OPCODE_ILL_E3 = 0xE3, // illegal opcode OPCODE_CPX_ZP = 0xE4, // ComPare X register, Zero Page ($E4 arg : CPX arg ;arg=0..$FF), MEM=arg OPCODE_SBC_ZP = 0xE5, // SuBtract with Carry, Zero Page ($E5 arg : SBC arg ;arg=0..$FF), MEM=arg OPCODE_INC_ZP = 0xE6, // INCrement memory, Zero Page ($E6 arg : INC arg ;arg=0..$FF), MEM=arg OPCODE_ILL_E7 = 0xE7, // illegal opcode OPCODE_INX = 0xE8, // INcrement X, Implied ($E8 : INX) OPCODE_SBC_IMM = 0xE9, // SuBtract with Carry, Immediate ($E9 arg : SBC #arg ;arg=0..$FF), MEM=PC+1 OPCODE_NOP = 0xEA, // NO oPeration, Implied ($EA : NOP) OPCODE_ILL_EB = 0xEB, // illegal opcode OPCODE_CPX_ABS = 0xEC, // ComPare X register, Absolute ($EC addrlo addrhi : CPX addr ;addr=0..$FFFF), MEM=addr OPCODE_SBC_ABS = 0xED, // SuBtract with Carry, Absolute ($ED addrlo addrhi : SBC addr ;addr=0..$FFFF), MEM=addr OPCODE_INC_ABS = 0xEE, // INCrement memory, Absolute ($EE addrlo addrhi : INC addr ;addr=0..$FFFF), MEM=addr OPCODE_ILL_EF = 0xEF, // illegal opcode OPCODE_BEQ_REL = 0xF0, // Branch on EQual, Relative ($F0 signoffs : BEQ signoffs ;signoffs=0..$FF [-128 ($80)..127 ($7F)]) OPCODE_SBC_IZY = 0xF1, // SuBtract with Carry, Indirect Indexed ($F1 arg : SBC (arg),Y ;arg=0..$FF), MEM=&arg+Y OPCODE_ILL_F2 = 0xF2, // illegal opcode OPCODE_ILL_F3 = 0xF3, // illegal opcode OPCODE_ILL_F4 = 0xF4, // illegal opcode OPCODE_SBC_ZPX = 0xF5, // SuBtract with Carry, Zero Page Indexed, X ($F5 arg : SBC arg,X ;arg=0..$FF), MEM=arg+X OPCODE_INC_ZPX = 0xF6, // INCrement memory, Zero Page Indexed, X ($F6 arg : INC arg,X ;arg=0..$FF), MEM=arg+X OPCODE_ILL_F7 = 0xF7, // illegal opcode OPCODE_SED = 0xF8, // SEt Decimal, Implied ($F8 : SED) OPCODE_SBC_ABY = 0xF9, // SuBtract with Carry, Absolute Indexed, Y ($F9 addrlo addrhi : SBC addr,Y ;addr=0..$FFFF), MEM=addr+Y OPCODE_ILL_FA = 0xFA, // illegal opcode OPCODE_ILL_FB = 0xFB, // illegal opcode OPCODE_ILL_FC = 0xFC, // illegal opcode OPCODE_SBC_ABX = 0xFD, // SuBtract with Carry, Absolute Indexed, X ($FD addrlo addrhi : SBC addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_INC_ABX = 0xFE, // INCrement memory, Absolute Indexed, X ($FE addrlo addrhi : INC addr,X ;addr=0..$FFFF), MEM=addr+X OPCODE_ILL_FF = 0xFF // illegal opcode }; struct OpCode { int code; // the byte value of the opcode int addrmode; // addressing mode (see eAddrModes) int time; // # of cycles string amf; // assembler mnemonic }; typedef map OpCodesMap; /* *------------------------------------------------------------------------------ bit -> 7 0 +---+---+---+---+---+---+---+---+ | N | V | | B | D | I | Z | C | <-- flag, 0/1 = reset/set +---+---+---+---+---+---+---+---+ N = NEGATIVE. Set if bit 7 of the accumulator is set. V = OVERFLOW. Set if the addition of two like-signed numbers or the subtraction of two unlike-signed numbers produces a result greater than +127 or less than -128. B = BRK COMMAND. Set if an interrupt caused by a BRK, reset if caused by an external interrupt. D = DECIMAL MODE. Set if decimal mode active. I = IRQ DISABLE. Set if maskable interrupts are disabled. Z = ZERO. Set if the result of the last operation (load/inc/dec/ add/sub) was zero. C = CARRY. Set if the add produced a carry, or if the subtraction produced a borrow. Also holds bits after a logical shift. *------------------------------------------------------------------------------ */ enum eCpuFlagMasks { FLAGS_CARRY = 0x01, // 0: C FLAGS_ZERO = 0x02, // 1: Z FLAGS_IRQ = 0x04, // 2: I FLAGS_DEC = 0x08, // 3: D FLAGS_BRK = 0x10, // 4: B (Clear if interrupt vectoring, set if BRK or PHP) FLAGS_UNUSED = 0x20, // 5: Unused flag (always set). FLAGS_OVERFLOW = 0x40, // 6: V FLAGS_SIGN = 0x80 // 7: N }; enum eLogicOps { LOGOP_OR, LOGOP_AND, LOGOP_EOR }; class MKCpu { public: MKCpu(); MKCpu(Memory *pmem); ~MKCpu(); Regs *ExecOpcode(unsigned short memaddr); Regs *GetRegs(); queue GetExecHistory(); unsigned short Disassemble(unsigned short addr, char *instrbuf); // Disassemble instruction in memory, return next instruction addr. protected: private: struct Regs mReg; // CPU registers Memory *mpMem; // pointer to memory object bool mLocalMem; // true - memory locally allocated OpCodesMap mOpCodesMap; // hash table of all opcodes int mAddrModesLen[ADDRMODE_LENGTH]; // array of instructions lengths per addressing mode string mArgFmtTbl[ADDRMODE_LENGTH]; // array of instructions assembly formats per addressing mode queue mExecHistory; // history of last 20 op-codes with arguments and registers statuses void InitCpu(); void SetFlags(unsigned char reg); // set CPU flags ZERO and SIGN based on Acc, X or Y unsigned char ShiftLeft(unsigned char arg8); // Arithmetic Shift Left, set Carry flag unsigned char ShiftRight(unsigned char arg8); // Logical Shift Right, update flags NZC. unsigned char RotateLeft(unsigned char arg8); // Rotate left, Carry to bit 0, bit 7 to Carry, update flags N and Z. unsigned char RotateRight(unsigned char arg8); // Rotate left, Carry to bit 7, bit 0 to Carry, update flags N and Z. unsigned short GetArg16(unsigned char offs); // Get 2-byte argument, add offset, increase PC. void LogicOpAcc(unsigned short addr, int logop); // Perform logical bitwise operation between memory location and Acc. // Result in Acc. Set flags. unsigned short ComputeRelJump(unsigned char offs); // Compute new PC based on relative offset. unsigned short ComputeRelJump(unsigned short addr, unsigned char offs); // Compute new address after branch based on relative offset. unsigned char Conv2Bcd(unsigned short v); // Convert number to BCD representation. unsigned short Bcd2Num(unsigned char v); // Convert BCD code to number. bool CheckFlag(unsigned char flag); // Return true if given CPU status flag is set, false otherwise. void SetFlag(bool set, unsigned char flag); // Set or unset processor status flag. unsigned char AddWithCarry(unsigned char mem8); // Add With Carry, update flags and Acc. unsigned char SubWithCarry(unsigned char mem8); // Subtract With Carry, update flags and Acc. unsigned short GetAddrWithMode(int mode); // Get address of the byte argument with specified addr. mode unsigned short GetArgWithMode(unsigned short opcaddr, int mode); // Get argument from address with specified addr. mode unsigned short Disassemble(); // Disassemble instruction and argument per addressing mode void Add2History(string s); // add entry to op-codes execute history }; } // namespace MKBasic #endif