#pragma once #include #include #include #include enum AddressingMode { NONE, ABS_A, ABS_I_IND_X, ABS_I_X, ABS_I_Y, ABS_IND_A, ACC, IMMEDIATE, IMPLIED, PC_REL, STACK, ZP, ZP_I_IND_X, ZP_I_X, ZP_I_Y, ZP_IND, ZP_I_IND_Y, ADDRESSING_MODE_COUNT }; constexpr std::array ADDRESSING_MODE_NAMES = { "-", // NONE "a", // ABS_A "(a,x)", // ABS_I_IND_X "a,x", // ABS_I_X "a,y", // ABS_I_Y "(a)", // ABS_IND_A "A", // ACC "#", // IMMEDIATE "i", // IMPLIED "r", // PC_REL "s", // STACK "zp", // ZP "(zp,x)", // ZP_I_IND_X "zp,x", // ZP_I_X "zp,y", // ZP_I_Y "(zp)", // ZP_IND "(zp),y" // ZP_I_IND_Y }; constexpr void strncpy_constexpr(char* dest, const char* src, size_t n) { for (size_t i = 0; i < n; i++) { dest[i] = src[i]; } } constexpr void strcpy_constexpr(char* dest, const char* src) { size_t i = 0; while (src[i] != '\0') { dest[i] = src[i]; i++; } } #define NAME_LENGTH 10 class OpCode { public: constexpr OpCode() : opName(""), mode(AddressingMode::NONE), name("") {}; OpCode(const char* opName_, const AddressingMode mode_) : mode(mode_) { strncpy_constexpr(opName, opName_, 3); opName[3] = '\0'; strncpy_constexpr(name, opName_, 3); name[3] = ' '; /* assert(ADDRESSING_MODE_NAMES.size() < mode); */ /* assert(strlen(ADDRESSING_MODE_NAMES.at(mode)) <= NAME_LENGTH - 4); // Mode name too long, 3 opcode name + 1 space */ strcpy_constexpr(&name[4], ADDRESSING_MODE_NAMES.at(mode)); } constexpr const char* getOpName() const { return opName; } constexpr AddressingMode getMode() const { return mode; } constexpr const char* getName() const { return name; } private: char opName[4] = " "; AddressingMode mode = AddressingMode::NONE; char name[10] = " "; }; // TODO: make constexpr inline std::array getOpCodesArray() { using am = AddressingMode; std::array opCodes{}; opCodes[0x00] = { "brk", am::STACK }; opCodes[0x10] = { "bpl", am::PC_REL }; opCodes[0x20] = { "jsr", am::ABS_IND_A }; opCodes[0x30] = { "bmi", am::PC_REL }; opCodes[0x40] = { "rti", am::STACK }; opCodes[0x50] = { "bvc", am::PC_REL }; opCodes[0x60] = { "rts", am::STACK }; opCodes[0x70] = { "bvs", am::PC_REL }; opCodes[0x80] = { "bra", am::PC_REL }; // WD opCodes[0x90] = { "bcc", am::PC_REL }; opCodes[0xa0] = { "ldy", am::IMMEDIATE }; opCodes[0xb0] = { "bcs", am::PC_REL }; opCodes[0xc0] = { "cpy", am::IMMEDIATE }; opCodes[0xd0] = { "bne", am::PC_REL }; opCodes[0xe0] = { "cpx", am::IMMEDIATE }; opCodes[0xf0] = { "beq", am::PC_REL }; opCodes[0x01] = { "ora", am::ZP_I_IND_X }; opCodes[0x11] = { "ora", am::ZP_I_IND_Y }; opCodes[0x21] = { "and", am::ZP_I_IND_X }; opCodes[0x31] = { "and", am::ZP_I_IND_Y }; opCodes[0x41] = { "eor", am::ZP_I_IND_X }; opCodes[0x51] = { "eor", am::ZP_I_IND_Y }; opCodes[0x61] = { "adc", am::ZP_I_IND_X }; opCodes[0x71] = { "adc", am::ZP_I_IND_Y }; opCodes[0x81] = { "sta", am::ZP_I_IND_X }; opCodes[0x91] = { "sta", am::ZP_I_IND_Y }; opCodes[0xa1] = { "lda", am::ZP_I_IND_X }; opCodes[0xb1] = { "lda", am::ZP_I_IND_Y }; opCodes[0xc1] = { "cmp", am::ZP_I_IND_X }; opCodes[0xd1] = { "cmp", am::ZP_I_IND_Y }; opCodes[0xe1] = { "sbc", am::ZP_I_IND_X }; opCodes[0xf1] = { "sbc", am::ZP_I_IND_Y }; /* opCodes[0x02] = { "", am:: }; */ opCodes[0x12] = { "ora", am::ZP_IND }; /* opCodes[0x22] = { "", am:: }; */ opCodes[0x32] = { "and", am::ZP_IND }; /* opCodes[0x42] = { "", am:: }; */ opCodes[0x52] = { "eor", am::ZP_IND }; /* opCodes[0x62] = { "", am:: }; */ opCodes[0x72] = { "adc", am::ZP_IND }; /* opCodes[0x82] = { "", am:: }; */ opCodes[0x92] = { "sta", am::ZP_IND }; opCodes[0xa2] = { "ldx", am::IMMEDIATE }; opCodes[0xb2] = { "lda", am::ZP_IND }; /* opCodes[0xc2] = { "", am:: }; */ opCodes[0xd2] = { "cmp", am::ZP_IND }; /* opCodes[0xe2] = { "brk", am:: }; */ opCodes[0xf2] = { "sbc", am::ZP_IND }; /* opCodes[0x03] = { "", am:: }; */ /* opCodes[0x13] = { "", am:: }; */ /* opCodes[0x23] = { "", am:: }; */ /* opCodes[0x33] = { "", am:: }; */ /* opCodes[0x43] = { "", am:: }; */ /* opCodes[0x53] = { "", am:: }; */ /* opCodes[0x63] = { "", am:: }; */ /* opCodes[0x73] = { "", am:: }; */ /* opCodes[0x83] = { "", am:: }; */ /* opCodes[0x93] = { "", am:: }; */ /* opCodes[0xa3] = { "", am:: }; */ /* opCodes[0xb3] = { "", am:: }; */ /* opCodes[0xc3] = { "", am:: }; */ /* opCodes[0xd3] = { "", am:: }; */ /* opCodes[0xe3] = { "", am:: }; */ /* opCodes[0xf3] = { "", am:: }; */ opCodes[0x04] = { "tsb", am::ZP }; // WD opCodes[0x14] = { "trb", am::ZP }; // WD opCodes[0x24] = { "bit", am::ZP }; opCodes[0x34] = { "bit", am::ZP_I_X }; // WD /* opCodes[0x44] = { "", am:: }; */ /* opCodes[0x54] = { "", am:: }; */ opCodes[0x64] = { "stz", am::ZP }; // WD opCodes[0x74] = { "stz", am::ZP_I_X }; // WD opCodes[0x84] = { "sty", am::ZP }; opCodes[0x94] = { "sty", am::ZP_I_X }; opCodes[0xa4] = { "ldy", am::ZP }; opCodes[0xb4] = { "ldy", am::ZP_I_X }; opCodes[0xc4] = { "cpy", am::ZP }; /* opCodes[0xd4] = { "", am:: }; */ opCodes[0xe4] = { "cpx", am::ZP }; /* opCodes[0xf4] = { "", am:: }; */ opCodes[0x05] = { "ora", am::ZP }; opCodes[0x15] = { "ora", am::ZP_I_X }; opCodes[0x25] = { "and", am::ZP }; opCodes[0x35] = { "and", am::ZP_I_X }; opCodes[0x45] = { "eor", am::ZP }; opCodes[0x55] = { "eor", am::ZP_I_X }; opCodes[0x65] = { "adc", am::ZP }; opCodes[0x75] = { "adc", am::ZP_I_X }; opCodes[0x85] = { "sta", am::ZP }; opCodes[0x95] = { "sta", am::ZP_I_X }; opCodes[0xa5] = { "lda", am::ZP }; opCodes[0xb5] = { "lda", am::ZP_I_X }; opCodes[0xc5] = { "cmp", am::ZP }; opCodes[0xd5] = { "cmp", am::ZP_I_X }; opCodes[0xe5] = { "sbc", am::ZP }; opCodes[0xf5] = { "sbc", am::ZP_I_X }; opCodes[0x06] = { "asl", am::ZP }; opCodes[0x16] = { "asl", am::ZP_I_X }; opCodes[0x26] = { "rol", am::ZP }; opCodes[0x36] = { "rol", am::ZP_I_X }; opCodes[0x46] = { "lsr", am::ZP }; opCodes[0x56] = { "lsr", am::ZP_I_X }; opCodes[0x66] = { "ror", am::ZP }; opCodes[0x76] = { "ror", am::ZP_I_X }; opCodes[0x86] = { "stx", am::ZP }; opCodes[0x96] = { "stx", am::ZP_I_X }; opCodes[0xa6] = { "ldx", am::ZP }; opCodes[0xb6] = { "ldx", am::ZP_I_X }; opCodes[0xc6] = { "dec", am::ZP }; opCodes[0xd6] = { "dec", am::ZP_I_X }; opCodes[0xe6] = { "inc", am::ZP }; opCodes[0xf6] = { "inc", am::ZP_I_X }; opCodes[0x07] = { "rmb0", am::ZP }; // WD opCodes[0x17] = { "rmb1", am::ZP }; // WD opCodes[0x27] = { "rmb2", am::ZP }; // WD opCodes[0x37] = { "rmb3", am::ZP }; // WD opCodes[0x47] = { "rmb4", am::ZP }; // WD opCodes[0x57] = { "rmb5", am::ZP }; // WD opCodes[0x67] = { "rmb6", am::ZP }; // WD opCodes[0x77] = { "rmb7", am::ZP }; // WD opCodes[0x87] = { "smb0", am::ZP }; // WD opCodes[0x97] = { "smb1", am::ZP }; // WD opCodes[0xa7] = { "smb2", am::ZP }; // WD opCodes[0xb7] = { "smb3", am::ZP }; // WD opCodes[0xc7] = { "smb4", am::ZP }; // WD opCodes[0xd7] = { "smb5", am::ZP }; // WD opCodes[0xe7] = { "smb6", am::ZP }; // WD opCodes[0xf7] = { "smb7", am::ZP }; // WD opCodes[0x08] = { "php", am::STACK }; opCodes[0x18] = { "clc", am::IMPLIED }; opCodes[0x28] = { "plp", am::STACK }; opCodes[0x38] = { "sec", am::IMPLIED }; opCodes[0x48] = { "pha", am::STACK }; opCodes[0x58] = { "cli", am::IMPLIED }; opCodes[0x68] = { "pla", am::STACK }; opCodes[0x78] = { "sei", am::IMPLIED }; opCodes[0x88] = { "dey", am::IMPLIED }; opCodes[0x98] = { "tya", am::IMPLIED }; opCodes[0xa8] = { "tay", am::IMPLIED }; opCodes[0xb8] = { "clv", am::IMPLIED }; opCodes[0xc8] = { "iny", am::IMPLIED }; opCodes[0xd8] = { "cld", am::IMPLIED }; opCodes[0xe8] = { "inx", am::IMPLIED }; opCodes[0xf8] = { "sed", am::IMPLIED }; opCodes[0x09] = { "ora", am::IMMEDIATE }; opCodes[0x19] = { "ora", am::ABS_I_Y }; opCodes[0x29] = { "and", am::IMMEDIATE }; opCodes[0x39] = { "and", am::ABS_I_Y }; opCodes[0x49] = { "eor", am::IMMEDIATE }; opCodes[0x59] = { "eor", am::ABS_I_Y }; opCodes[0x69] = { "adc", am::IMMEDIATE }; opCodes[0x79] = { "adc", am::ABS_I_Y }; opCodes[0x89] = { "bit", am::IMMEDIATE }; // WD opCodes[0x99] = { "sta", am::ABS_I_Y }; opCodes[0xa9] = { "lda", am::IMMEDIATE}; opCodes[0xb9] = { "lda", am::ABS_I_Y }; // TODO datasheet says A,y not a,y opCodes[0xc9] = { "cmp", am::IMMEDIATE }; opCodes[0xd9] = { "cmp", am::ABS_I_Y }; opCodes[0xe9] = { "sbc", am::IMMEDIATE }; opCodes[0xf9] = { "sbc", am::ABS_I_Y }; opCodes[0x0a] = { "asl", am::ACC }; opCodes[0x1a] = { "inc", am::ACC }; // WD opCodes[0x2a] = { "rol", am::ACC }; opCodes[0x3a] = { "dec", am::ACC }; // WD opCodes[0x4a] = { "lsr", am::ACC }; opCodes[0x5a] = { "phy", am::STACK }; // WD opCodes[0x6a] = { "ror", am::ACC }; opCodes[0x7a] = { "ply", am::STACK }; // WD opCodes[0x8a] = { "txa", am::IMPLIED }; opCodes[0x9a] = { "txs", am::IMPLIED }; opCodes[0xaa] = { "tax", am::IMPLIED }; opCodes[0xba] = { "tsx", am::IMPLIED }; opCodes[0xca] = { "dex", am::IMPLIED }; opCodes[0xda] = { "phx", am::IMPLIED }; // WD opCodes[0xea] = { "nop", am::IMPLIED }; opCodes[0xfa] = { "plx", am::IMPLIED }; // WD /* opCodes[0x0b] = { "", am:: }; */ /* opCodes[0x1b] = { "", am:: }; */ /* opCodes[0x2b] = { "", am:: }; */ /* opCodes[0x3b] = { "", am:: }; */ /* opCodes[0x4b] = { "", am:: }; */ /* opCodes[0x5b] = { "", am:: }; */ /* opCodes[0x6b] = { "", am:: }; */ /* opCodes[0x7b] = { "", am:: }; */ /* opCodes[0x8b] = { "", am:: }; */ /* opCodes[0x9b] = { "", am:: }; */ /* opCodes[0xab] = { "", am:: }; */ /* opCodes[0xbb] = { "", am:: }; */ opCodes[0xcb] = { "wai", am::IMPLIED }; opCodes[0xdb] = { "stp", am::IMPLIED }; /* opCodes[0xeb] = { "", am:: }; */ /* opCodes[0xfb] = { "", am:: }; */ opCodes[0x0c] = { "tsb", am::ABS_A }; // WD opCodes[0x1c] = { "trb", am::ABS_A }; // WD opCodes[0x2c] = { "bit", am::ABS_A }; opCodes[0x3c] = { "bit", am::ABS_I_X }; // WD opCodes[0x4c] = { "jmp", am::ABS_A }; /* opCodes[0x5c] = { "", am:: }; */ opCodes[0x6c] = { "jmp", am::ABS_IND_A }; opCodes[0x7c] = { "jmp", am::ABS_I_IND_X }; // WD opCodes[0x8c] = { "sty", am::ABS_A }; opCodes[0x9c] = { "stz", am::ABS_A }; // WD opCodes[0xac] = { "ldy", am::ACC }; opCodes[0xbc] = { "ldy", am::ABS_I_X }; opCodes[0xcc] = { "cpy", am::ABS_A }; /* opCodes[0xdc] = { "", am:: }; */ opCodes[0xec] = { "cpx", am::ABS_A }; /* opCodes[0xfc] = { "", am:: }; */ opCodes[0x0d] = { "ora", am::ABS_A }; opCodes[0x1d] = { "ora", am::ABS_I_X }; opCodes[0x2d] = { "and", am::ABS_A }; opCodes[0x3d] = { "and", am::ABS_I_X }; opCodes[0x4d] = { "eor", am::ABS_A }; opCodes[0x5d] = { "eor", am::ABS_I_X }; opCodes[0x6d] = { "adc", am::ABS_A }; opCodes[0x7d] = { "adc", am::ABS_I_X }; opCodes[0x8d] = { "sta", am::ABS_A }; opCodes[0x9d] = { "sta", am::ABS_I_X }; opCodes[0xad] = { "lda", am::ABS_A }; opCodes[0xbd] = { "lda", am::ABS_I_X }; opCodes[0xcd] = { "cmp", am::ABS_A }; opCodes[0xdd] = { "cmp", am::ABS_I_X }; opCodes[0xed] = { "sbc", am::ABS_A }; opCodes[0xfd] = { "sbc", am::ABS_I_X }; opCodes[0x0e] = { "asl", am::ABS_A }; opCodes[0x1e] = { "asl", am::ABS_I_X }; opCodes[0x2e] = { "rol", am::ABS_A }; opCodes[0x3e] = { "rol", am::ABS_I_X }; opCodes[0x4e] = { "lsr", am::ABS_A }; opCodes[0x5e] = { "lsr", am::ABS_I_X }; opCodes[0x6e] = { "ror", am::ABS_A }; opCodes[0x7e] = { "ror", am::ABS_I_X }; opCodes[0x8e] = { "stx", am::ABS_A }; opCodes[0x9e] = { "stz", am::ABS_I_X }; opCodes[0xae] = { "ldx", am::ABS_A }; opCodes[0xbe] = { "ldx", am::ABS_I_X }; opCodes[0xce] = { "dec", am::ABS_A }; opCodes[0xde] = { "dec", am::ABS_I_X }; opCodes[0xee] = { "inc", am::ABS_A }; opCodes[0xfe] = { "inc", am::ABS_I_X }; opCodes[0x0f] = { "bbr0", am::PC_REL }; // WD opCodes[0x1f] = { "bbr1", am::PC_REL }; // WD opCodes[0x2f] = { "bbr2", am::PC_REL }; // WD opCodes[0x3f] = { "bbr3", am::PC_REL }; // WD opCodes[0x4f] = { "bbr4", am::PC_REL }; // WD opCodes[0x5f] = { "bbr5", am::PC_REL }; // WD opCodes[0x6f] = { "bbr6", am::PC_REL }; // WD opCodes[0x7f] = { "bbr7", am::PC_REL }; // WD opCodes[0x8f] = { "bbs0", am::PC_REL }; // WD opCodes[0x9f] = { "bbs1", am::PC_REL }; // WD opCodes[0xaf] = { "bbs2", am::PC_REL }; // WD opCodes[0xbf] = { "bbs3", am::PC_REL }; // WD opCodes[0xcf] = { "bbs4", am::PC_REL }; // WD opCodes[0xdf] = { "bbs5", am::PC_REL }; // WD opCodes[0xef] = { "bbs6", am::PC_REL }; // WD opCodes[0xff] = { "bbs7", am::PC_REL }; // WD return opCodes; } // TODO fix constexpr const std::array opCodes = getOpCodesArray();