1
0
mirror of https://github.com/makarcz/vm6502.git synced 2024-11-18 18:10:43 +00:00
vm6502/MKCpu.h
Marek Karcz 67f1a62596 Version 2.0
Version 2.0, full emulation of 6502 op-codes, fully tested and functional. Extended description in ReadMe file. Bin2Hex tool to convert binary images to memory definition format. Microchess, EhBasic added.
2016-03-13 19:12:14 -04:00

463 lines
28 KiB
C++

#ifndef MKCPU_H
#define MKCPU_H
#include <string>
#include <map>
#include <queue>
#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<eOpCodes,OpCode> 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<string> 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<string> 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