diff options
-rw-r--r-- | opcode-bitmask-gen.c | 565 | ||||
-rw-r--r-- | opcode-bitmask-gen.h | 552 |
2 files changed, 1117 insertions, 0 deletions
diff --git a/opcode-bitmask-gen.c b/opcode-bitmask-gen.c new file mode 100644 index 0000000..304809c --- /dev/null +++ b/opcode-bitmask-gen.c @@ -0,0 +1,565 @@ +#include "opcode-bitmask-gen.h" +#include <ctype.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define AM_ORTHO (AM_ORTHO | AM_ORTHO2) +#define AM_ADDR (AM_ZM | AM_ZMX | AM_ZMY | \ + AM_IND | AM_INDX | AM_INDY | \ + AM_ABS | AM_ABX | AM_ABY | \ + AM_AIND | AM_AINDX | AM_AINDY | \ + AM_INDX2 | AM_ZM2) + +void vprint_reason(const char *reason, va_list ap) { + if (reason != NULL && isprint(reason[0])) { + printf("Reason: "); + vprintf(reason, ap); + } +} + +void print_reason(const char *reason, ...) { + va_list ap; + va_start(ap, reason); + vprint_reason(reason, ap); + va_end(ap); +} + +void failed(const char *name, const char *reason, ...) { + va_list ap; + va_start(ap, reason); + printf("%s failed. ", name); + vprint_reason(reason, ap); + putchar('\n'); + va_end(ap); +} + +int vformat_len(const char *fmt, va_list ap) { + return vsnprintf(NULL, 0, fmt, ap); +} + +int format_len(const char *fmt, ...) { + int len = 0; + va_list ap; + va_start(ap, fmt); + len = vformat_len(fmt, ap); + va_end(ap); + return len; +} + +#if 0 +int log2_int(uint32_t n) { + int j = 0; + + for (int i = 4; i >= 0; i--) { + int tmp = 1 << i; + j |= ((n >> j) >= (uint32_t)1 << tmp) ? tmp : 0; + } + return j; +} +#else +int log2_int(uint32_t n) { + return (n > 1) ? 1+log2_int(n/2) : 0; +} +#endif + +uint32_t get_msb(uint32_t n) { + return 1 << log2_int(n); +} + +int get_addr_mode_type(uint32_t addr_mode) { + return addr_mode_type[log2_int(addr_mode)]; +} + +uint8_t get_ind(int instr, int addr_mode) { + uint8_t base_idx = 0; + uint8_t offset = 0; + switch (instr) { + case CMP: base_idx = CMP_IND; break; + case CPB: base_idx = CPB_IND; break; + case JMP: base_idx = JMP_IND; break; + case JSR: base_idx = JSR_IND; break; + case LDA: base_idx = LDA_IND; break; + case LDB: base_idx = LDB_IND; break; + case LDX: base_idx = LDX_IND; break; + case LDY: base_idx = LDY_IND; break; + case STA: base_idx = STA_IND; break; + case STB: base_idx = STB_IND; break; + case STX: base_idx = STX_IND; break; + case STY: base_idx = STY_IND; break; + } + switch (addr_mode) { + case IND : offset = 0; break; + case INDY: offset += 1; break; + case INDX: offset += 2; break; + } + return base_idx + offset; +} + +uint8_t get_eind(int instr) { + switch (instr) { + case DEC: return DEC_EIND; + case INC: return INC_EIND; + case STY: return STY_EIND; + case STA: return STA_EIND; + case STB: return STB_EIND; + case LDX: return LDX_EIND; + case STX: return STX_EIND; + case CPB: return CPB_EIND; + case CPX: return CPX_EIND; + case CPY: return CPY_EIND; + } + return 0xFF; +} + +uint8_t get_ext_ortho(int instr) { + switch (instr) { + case LEA: return OP_LEA; + case PEA: return OP_PEA; + case ADD: return OP_ADD; + case SUB: return OP_SUB; + case NOT: return OP_NOT; + case CLZ: return OP_CLZ; + case CLO: return OP_CLO; + case SWP: return OP_SWP; + case PCN: return OP_PCN; + } + return 0xFF; +} + +uint8_t get_opcode(const instruction *instr, int addr_mode, int inst_ext, int ext, int inst_id) { + const uint8_t opcode = instr->op; + const uint32_t addr_mode_mask = instr->am; + addr_mode = (ext == ORTHO) ? ORTHO_EXT : addr_mode; + if (inst_ext < ext) { + switch (ext) { + case EXT: + if (addr_mode != EIND) { + return 0xFF; + } + break; + case ORTHO: + if (addr_mode != ORTHO_EXT) { + return 0xFF; + } + break; + } + } + switch (addr_mode) { + case ZM: + if (addr_mode_mask & AM_ZM) { + return opcode + 0x04; + } else if (addr_mode_mask & AM_ZM2) { + /* Add 0x20 to opcode if this is JMP zm, or JSR zm. */ + return opcode + 0x20; + } + break; + case ZMX: + if (addr_mode_mask & AM_ZMX) { + /* Add 0x06 to opcode if we're using the base ISA, and 0x54 if we're using the base extension. */ + return opcode + ((ext == BASE) ? 0x06 : 0x54); + } + break; + case ZMY: + if (addr_mode_mask & AM_ZMY) { + return opcode + 0x14; + } + break; + case INDX: + if (addr_mode_mask & AM_INDX) { + /* Add 0x16 to opcode if we're using the base ISA, and 0x94 if we're using the base extension. */ + return opcode + ((ext == BASE) ? 0x16 : 0x94); + } + /* Falls Through. */ + case IND: + case INDY: + /* Are we using the base ISA? */ + if (ext == BASE && (addr_mode_mask & AM_IND|AM_INDY|AM_INDX2)) { + /* Get opcode from lookup table. */ + return ind_ops[get_ind(inst_id, addr_mode)]; + /* Are we using the base extension? */ + } else if (ext == 1) { + /* Add 0x44 to opcode if addressing mode is just indirect, and 0x84 otherwise. */ + return opcode + ((addr_mode == IND) ? 0x44 : 0x84); + } + break; + case ABS: + if (addr_mode_mask & AM_ABS) { + return opcode + 0x10; + } + break; + case ABSX: + if (addr_mode_mask & AM_ABX) { + return opcode + 0x50; + } + break; + case ABSY: + if (addr_mode_mask & AM_ABY) { + return opcode; + } + break; + case AIND: + if (addr_mode_mask & AM_AIND) { + return opcode + 0x40; + } + break; + case AINDX: + if (addr_mode_mask & AM_AINDX) { + return opcode + 0x90; + } + break; + case AINDY: + if (addr_mode_mask & AM_AINDY) { + return opcode + 0x80; + } + break; + case EIND: + if (ext < ORTHO && (addr_mode_mask & AM_EIND|AM_EIND2)) { + const int eind_type = ((addr_mode_mask & AM_EIND2) != 0); + switch (eind_type) { + case 0: return (ext == EXT) ? opcode+0x14 : opcode+0x10; + case 1: return (ext == EXT) ? opcode+0x01 : eind_base_ops[get_eind(inst_id)]; + } + } + break; + case ORTHO_EXT: + if (addr_mode_mask & AM_ORTHO|AM_ORTHO2) { + return (inst_ext == EXT) ? ext_ortho_ops[get_ext_ortho(inst_id)] : opcode; + } + break; + case IMM: + if (addr_mode_mask & AM_IMM) { + return opcode; + } + break; + case IMPL: + if (addr_mode_mask & AM_IMPL) { + return opcode; + } + break; + case BREG: + if (addr_mode_mask & AM_BREG) { + return opcode + 0x14; + } + break; + default: break; + } + return 0xFF; +} + +void set_opcode_bit(uint32_t *mask, int opcode) { + const uint32_t o8 = opcode / 32, o8m = 1 << (opcode % 32); + mask[o8] |= o8m; +} + +void set_ortho_opcode_bits(uint32_t *mask, int opcode, int is_1op, int is_cc) { + for (int i = 0; i < ((is_cc) ? 8 : 1); ++i, opcode += (is_cc) ? 0x20 : 0) { + for (int j = 0; j < 4-is_1op; j += 1+is_1op) { + set_opcode_bit(mask, opcode | (j << 3)); + } + } +} + +void search_inst_table_entry(const instruction *inst, uint32_t *mask, uint32_t addr_modes, int inst_ext, int ext, uint8_t inst_id) { + addr_modes &= inst->am; + switch (ext) { + case BASE: addr_modes &= ~(AM_ORTHO|AM_ORTHO2|AM_EIND|AM_EIND2); break; + case EXT : addr_modes &= (inst_ext == BASE) ? (AM_EIND|AM_EIND2) : ~(AM_ORTHO|AM_ORTHO2); break; + } + for (uint32_t i = addr_modes; i; i &= ~get_msb(i)) { + const uint8_t opcode = get_opcode(inst, get_addr_mode_type(i), inst_ext, ext, inst_id); + const uint32_t o8 = opcode / 32, o8m = 1 << (opcode % 32); + if (opcode == 0xFF) { + continue; + } + + if (ext == ORTHO) { + const int is_1op = (inst->am & AM_ORTHO2) == AM_ORTHO2; + const int is_cc = (inst_ext == ORTHO && inst_id == SET); + set_ortho_opcode_bits(mask, opcode, is_1op, is_cc); + } else { + set_opcode_bit(mask, opcode); + } + + /*printf("table: %i, i: %2i, j: 0x%08X, mask: {", table, i, j); + for (int k = mask_size-1; k >= 0; --k) { + printf("0x%08X%s", mask[k], (k) ? ", " : "}\n"); + }*/ + } +} + +int print_mask(uint32_t addr_modes, instruction_id *inst_ids, int ext) { + char *str = calloc(format_len("t(0, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X)\n", 0, 1, 2, 3, 4, 5, 6, 7) + 1, sizeof(char)); + char *tmp = str; + uint32_t mask[8] = {}; + const size_t mask_size = sizeof(mask) / sizeof(uint32_t); + const uint32_t max_addr_mode_mask = -(uint32_t)1 >> (32-AMT_LEN); + addr_modes = (addr_modes & ~max_addr_mode_mask) ? max_addr_mode_mask : addr_modes; + + if (ext > ORTHO) { + failed("print_mask()", "Supplied extension is invalid, because it's out of the intended bounds."); + free(str); + tmp = NULL; + str = NULL; + return 0; + } + + if (inst_ids == NULL) { + for (int table = 0; table <= ext; ++table) { + int max_ops = 0; + const uint32_t addr_mode_mask = (ext && table < ext) ? ((ext == EXT) ? AM_EIND|AM_EIND2 : AM_ORTHO|AM_ORTHO2) : addr_modes; + const instruction *inst_table; + + switch (ext) { + case BASE: inst_table = inst, max_ops = OPNUM; break; + case EXT: inst_table = ext_inst, max_ops = EXT_OPNUM; break; + case ORTHO: inst_table = ortho_inst, max_ops = ORTHO_OPNUM; break; + } + + for (int i = 0; i < max_ops; ++i) { + if (inst_table[i].am & addr_mode_mask) { + search_inst_table_entry(&inst_table[i], mask, addr_modes, table, ext, i); + #if 0 + for (uint32_t j = addr_modes; j; j &= ~get_msb(j)) { + const uint8_t opcode = get_opcode(&inst_table[i], get_addr_mode_type(j), table, ext, i); + const uint32_t o8 = opcode / 32, o8m = 1 << (opcode % 32); + if (opcode == 0xFF) { + continue; + } + + if (ext == 2) { + const int is_1op = (inst[i].am & AM_ORTHO2) == AM_ORTHO2; + const int is_cc = (table == ORTHO && i == SET); + set_ortho_opcode_bits(mask, opcode, is_1op, is_cc); + } else { + set_opcode_bit(mask, opcode); + } + + /*printf("table: %i, i: %2i, j: 0x%08X, mask: {", table, i, j); + for (int k = mask_size-1; k >= 0; --k) { + printf("0x%08X%s", mask[k], (k) ? ", " : "}\n"); + }*/ + } + #endif + } + } + } + } else { + for (int i = 0; inst_ids[i].ext >= BASE; ++i) { + const uint32_t addr_mode_mask = (ext && inst_ids[i].ext < ext) ? ((ext == EXT) ? AM_EIND|AM_EIND2 : AM_ORTHO|AM_ORTHO2) : addr_modes; + const instruction *inst_entry; + switch (inst_ids[i].ext) { + case BASE : inst_entry = &inst[inst_ids[i].id]; break; + case EXT : inst_entry = &ext_inst[inst_ids[i].id]; break; + case ORTHO: inst_entry = &ortho_inst[inst_ids[i].id]; break; + } + + if (inst->am & addr_mode_mask) { + search_inst_table_entry(inst_entry, mask, addr_modes, inst_ids[i].ext, ext, inst_ids[i].id); + } + } + } + + tmp += sprintf(tmp, "t(0, "); + for (int i = mask_size-1; i >= 0; --i) { + tmp += sprintf(tmp, "0x%08X%s", mask[i], (i) ? ", " : ")\n"); + } + + printf("%s", str); + + free(str); + tmp = NULL; + str = NULL; + return 1; +} + +int get_delm_span(const char *str, const char *delm) { + const int inv_span_len = strcspn(str, delm); + return inv_span_len + strspn(&str[inv_span_len], delm); +} + +int get_csv_len(const char *str) { + int ret = 0; + for (int i = 0; str[i] != '\0'; i += get_delm_span(&str[i], ", "), ++ret); + return ret; +} + +void free_csv_list(char **list) { + for (int i = 0; list[i] != NULL; ++i) { + free(list[i]); + list[i] = NULL; + } +} + +char **parse_csv_list(const char *str) { + const char *delm = ", "; + char **list = calloc(get_csv_len(str)+1, sizeof(char *)); + for (int i = 0, j = 0; str[i] != '\0'; i += get_delm_span(&str[i], delm), ++j) { + const int len = strcspn(&str[i], delm); + list[j] = calloc(len+1, sizeof(char)); + memcpy(list[j], &str[i], len); + } + return list; +} + +void set_extension(int *ext, int ext2, int force, const char *reason, ...) { + int dummy = -1; + ext = (ext != NULL) ? ext : &dummy; + if (*ext < ext2 || *ext < BASE || force) { + va_list ap; + printf("Switching extension from %s, to %s. ", (*ext < BASE || *ext >= EXT_LEN) ? ext_names[*ext] : "auto", ext_names[ext2]); + va_start(ap, reason); + vprint_reason(reason, ap); + va_end(ap); + *ext = ext2; + } +} + +uint32_t get_addr_mode_bits(const char **list, int *ext) { + uint32_t addr_modes = 0; + for (int i = 0; list[i] != NULL; ++i) { + const char *str = list[i]; + for (int j = 0; j < AMT_LEN; ++j) { + if (!strcasecmp(str, adrmode[j])) { + //printf("i: %i, str: %s, adrmode: %s\n", i, str, adrmode[i]); + addr_modes |= (1 << j); + } + } + } + if (addr_modes & (AM_ORTHO|AM_ORTHO2|AM_EIND|AM_EIND2|AM_AIND|AM_AINDX|AM_AINDY)) { + const int ext2 = (addr_modes & AM_ORTHO) ? ORTHO : EXT; + const char *addr_mode_reason = (ext2 == ORTHO) ? "was set to ortho" : "is a base extension addressing mode"; + set_extension(ext, ext2, 1, "The addressing mode %s.\n", addr_mode_reason); + } + return addr_modes; +} + +instruction_id *get_instruction_ids(const char **list, int *ext) { + int has_failed = 0; + char *fail_reason = NULL; + instruction_id *inst_ids = NULL; + int list_len = 0; + if (list != NULL) { + for (list_len = 0; list[list_len] != NULL; ++list_len); + + if (list_len == 0) { + has_failed = 1; + fail_reason = "Instruction list length is zero."; + } else { + inst_ids = calloc(list_len+1, sizeof(instruction_id)); + memset(inst_ids, -1, sizeof(instruction_id)*(list_len+1)); + } + } else { + has_failed = 1; + fail_reason = "Instruction list is NULL."; + } + + if (has_failed) { + failed("get_instruction_ids()", "%s", fail_reason); + return NULL; + } + + for (int i = 0; list[i] != NULL; ++i) { + for (int j = 0; j < EXT_LEN && inst_ids[i].ext < 0; ++j) { + const char **table; + switch (j) { + case BASE : table = mne; break; + case EXT : table = ext_mne; break; + case ORTHO: table = ortho_mne; break; + } + + for (int k = 0; table[k] != NULL; ++k) { + if (!strcasecmp(list[i], table[k])) { + char *ext_str = NULL; + inst_ids[i] = (instruction_id){.ext = j, .id = k}; + switch (j) { + case BASE : ext_str = "Base ISA"; break; + case EXT : ext_str = "Base Extension"; break; + case ORTHO: ext_str = "Ortho Extension"; break; + } + set_extension(ext, j, 0, "The instruction is from the %s.\n", ext_str); + break; + } + } + } + } + return inst_ids; +} + +int get_extension_id(const char *str) { + for (int i = 0; i < EXT_LEN; ++i) { + if (!strcasecmp(str, ext_names[i])) { + return i; + } + } + return -1; +} + +void usage(const char *name) { + printf("Usage: %s -a <addr_mode>[,<addr_mode> ...] -i <instruction>[,<instruction> ...] -e <isa_extension>\n", name); +} + +options *get_options(int argc, char **argv) { + options *opts = calloc(1, sizeof(options)); + for (int i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + const char option = argv[i++][1]; + if (option == 'a' || option == 'i') { + const char **list = (const char **)parse_csv_list(argv[i]); + switch (option) { + case 'a': opts->addr_modes = get_addr_mode_bits(list, &opts->ext); break; + case 'i': opts->instr = get_instruction_ids(list, &opts->ext); break; + } + opts->addr_modes = (opts->instr != NULL && opts->addr_modes == 0) ? -1 : opts->addr_modes; + free_csv_list((char **)list); + } else if (option == 'e') { + const int ext = get_extension_id(argv[i]); + opts->ext = (opts->ext < ext) ? ext : opts->ext; + opts->addr_modes = (opts->addr_modes == 0) ? -1 : opts->addr_modes; + } else { + failed(argv[0], "Invalid option \"-%c\".", option); + usage(argv[0]); + free(opts); + return NULL; + } + } + } + return opts; +} + +options *parse_args(int argc, char **argv) { + if (argc == 1) { + failed(argv[0], "No arguments."); + usage(argv[0]); + return NULL; + } + + return get_options(argc, argv); +} + +int main(int argc, char **argv) { + int ret; + char *reason = NULL; + options *opts = parse_args(argc, argv); + if (opts == NULL) { + return 1; + } + if (!opts->addr_modes) { + reason = "Addressing mode mask is zero."; + ret = 1; + } else { + ret = !print_mask(opts->addr_modes, opts->instr, opts->ext); + } + + if (ret != 0) { + if (reason != NULL) { + failed(argv[0], reason); + usage(argv[0]); + } + } + + free(opts->instr); + free(opts); + return ret; +} diff --git a/opcode-bitmask-gen.h b/opcode-bitmask-gen.h new file mode 100644 index 0000000..e42c7f7 --- /dev/null +++ b/opcode-bitmask-gen.h @@ -0,0 +1,552 @@ +#include "enums.h" +#include <stdint.h> +#include <stdlib.h> + + +#define OPNUM 74 +#define EXT_OPNUM 49 +#define ORTHO_OPNUM 16 + +#define ORTHO_EXT EIND+1 + +typedef struct inst instruction; +typedef struct inst_id instruction_id; +typedef struct opts options; + +struct inst { + uint32_t am; /* Addressing modes. */ + uint8_t op; /* Base value used to get the actual opcode. */ +}; + +struct inst_id { + int ext; + int id; +}; + +struct opts { + uint32_t addr_modes; + instruction_id *instr; + int ext; +}; + +enum extensions { + BASE, + EXT, + ORTHO, + EXT_LEN +}; + +enum addrmode_type { + AMT_IMM, + AMT_ZM, + AMT_ZMX, + AMT_ZMY, + AMT_IND, + AMT_INDX, + AMT_INDY, + AMT_ABS, + AMT_REL, + AMT_BREG, + AMT_IMPL, + AMT_INDX2, + AMT_ZM2, + AMT_EIND, + AMT_EIND2, + AMT_ABY, + AMT_ABX, + AMT_AIND, + AMT_AINDY, + AMT_AINDX, + AMT_ORTHO, + AMT_ORTHO2, + AMT_LEN +}; + +enum addrmode { + AM_IMM = (1 << 0), + AM_ZM = (1 << 1), + AM_ZMX = (1 << 2), + AM_ZMY = (1 << 3), + AM_IND = (1 << 4), + AM_INDX = (1 << 5), + AM_INDY = (1 << 6), + AM_ABS = (1 << 7), + AM_REL = (1 << 8), + AM_BREG = (1 << 9), + AM_IMPL = (1 << 10), + AM_INDX2 = (1 << 11), + AM_ZM2 = (1 << 12), + AM_EIND = (1 << 13), + AM_EIND2 = (1 << 14), + AM_ABY = (1 << 15), + AM_ABX = (1 << 16), + AM_AIND = (1 << 17), + AM_AINDY = (1 << 18), + AM_AINDX = (1 << 19), + AM_ORTHO = (1 << 20), + AM_ORTHO2 = (1 << 21), + AM_LEN = (1 << 22) +}; + +enum ind { + CMP_IND = 0, + CMP_IDY = 1, + CMP_IDX = 2, + CPB_IND = 3, + CPB_IDY = 4, + CPB_IDX = 5, + JMP_IND = 6, + JSR_IND = 7, + LDA_IND = 8, + LDA_IDY = 9, + LDB_IND = 10, + LDB_IDY = 11, + LDX_IND = 12, + LDY_IND = 13, + STA_IND = 14, + STA_IDY = 15, + STB_IND = 16, + STB_IDY = 17, + STX_IND = 18, + STY_IND = 19 +}; + +enum eind { + DEC_EIND, + INC_EIND, + STY_EIND, + STA_EIND, + STB_EIND, + LDX_EIND, + STX_EIND, + CPB_EIND, + CPX_EIND, + CPY_EIND +}; + +enum baseext_ortho { + OP_LEA, + OP_PEA, + OP_ADD, + OP_SUB, + OP_NOT, + OP_CLZ, + OP_CLO, + OP_SWP, + OP_PCN +}; + +static const char *ext_names[EXT_LEN] = { + [BASE ] = "base", + [EXT ] = "ext", + [ORTHO] = "ortho" +}; + +static const char *adrmode[AMT_LEN] = { + [AMT_IMM ] = "IMM", + [AMT_ZM ] = "ZM", + [AMT_ZMX ] = "ZMX", + [AMT_ZMY ] = "ZMY", + [AMT_IND ] = "IND", + [AMT_INDX ] = "INDX", + [AMT_INDY ] = "INDY", + [AMT_ABS ] = "ABS", + [AMT_REL ] = "REL", + [AMT_BREG ] = "BREG", + [AMT_IMPL ] = "IMPL", + [AMT_INDX2 ] = "INDX", + [AMT_ZM2 ] = "ZM", + [AMT_EIND ] = "EIND", + [AMT_EIND2 ] = "EIND", + [AMT_ABY ] = "ABSY", + [AMT_ABX ] = "ABSX", + [AMT_AIND ] = "AIND", + [AMT_AINDY ] = "AINDY", + [AMT_AINDX ] = "AINDX", + [AMT_ORTHO ] = "ORTHO", + [AMT_ORTHO2] = "ORTHO" +}; + +static const char *mne[] = { + [ADC] = "ADC", + [AND] = "AND", + [ASR] = "ASR", + [BCC] = "BCC", + [BCS] = "BCS", + [BEQ] = "BEQ", + [BNE] = "BNE", + [BNG] = "BNG", + [BPO] = "BPO", + [BRA] = "BRA", + [BRK] = "BRK", + [BVC] = "BVC", + [BVS] = "BVS", + [CLC] = "CLC", + [CLI] = "CLI", + [CLV] = "CLV", + [CMP] = "CMP", + [CPB] = "CPB", + [CPS] = "CPS", + [CPX] = "CPX", + [CPY] = "CPY", + [DEB] = "DEB", + [DEC] = "DEC", + [DEX] = "DEX", + [DEY] = "DEY", + [DIV] = "DIV", + [INB] = "INB", + [INC] = "INC", + [INX] = "INX", + [INY] = "INY", + [JMP] = "JMP", + [JSR] = "JSR", + [LDA] = "LDA", + [LDB] = "LDB", + [LDX] = "LDX", + [LDY] = "LDY", + [LSL] = "LSL", + [LSR] = "LSR", + [MUL] = "MUL", + [NOP] = "NOP", + [ORA] = "ORA", + [PHA] = "PHA", + [PHB] = "PHB", + [PHP] = "PHP", + [PHX] = "PHX", + [PHY] = "PHY", + [PLA] = "PLA", + [PLB] = "PLB", + [PLP] = "PLP", + [PLX] = "PLX", + [PLY] = "PLY", + [ROL] = "ROL", + [ROR] = "ROR", + [RTI] = "RTI", + [RTS] = "RTS", + [SBC] = "SBC", + [SEC] = "SEC", + [SEI] = "SEI", + [STA] = "STA", + [STB] = "STB", + [STX] = "STX", + [STY] = "STY", + [TAB] = "TAB", + [TAX] = "TAX", + [TAY] = "TAY", + [TBA] = "TBA", + [TSX] = "TSX", + [TXA] = "TXA", + [TXS] = "TXS", + [TXY] = "TXY", + [TYA] = "TYA", + [TYX] = "TYX", + [WAI] = "WAI", + [XOR] = "XOR", + NULL +}; + +static const char *ext_mne[] = { + [LEA] = "LEA", + [PEA] = "PEA", + [ADD] = "ADD", + [SUB] = "SUB", + [ADE] = "ADE", + [SBE] = "SBE", + [ADS] = "ADS", + [SBS] = "SBS", + [NOT] = "NOT", + [LLM] = "LLM", + [LRM] = "LRM", + [RLM] = "RLM", + [RRM] = "RRM", + [ARM] = "ARM", + [PHE] = "PHE", + [PLE] = "PLE", + [CPE] = "CPE", + [ICE] = "ICE", + [LDS] = "LDS", + [DEE] = "DEE", + [INE] = "INE", + [DES] = "DES", + [INS] = "INS", + [STS] = "STS", + [STE] = "STE", + [STZ] = "STZ", + [SCO] = "SCO", + [ECO] = "ECO", + [CLZ] = "CLZ", + [CLO] = "CLO", + [BIT] = "BIT", + [MMV] = "MMV", + [SWP] = "SWP", + [PCN] = "PCN", + [REP] = "REP", + [REQ] = "REQ", + [RNE] = "RNE", + [LNG] = "LNG", + [LPO] = "LPO", + [LCS] = "LCS", + [LCC] = "LCC", + [LEQ] = "LEQ", + [LNE] = "LNE", + [SNG] = "SNG", + [SPO] = "SPO", + [SCS] = "SCS", + [SCC] = "SCC", + [SEQ] = "SEQ", + [SNE] = "SNE", + NULL +}; + +static const char *ortho_mne[] = { + [MNG] = "MNG", + [MPO] = "MPO", + [MCS] = "MCS", + [MCC] = "MCC", + [MEQ] = "MEQ", + [MNE] = "MNE", + [MVS] = "MVS", + [MVC] = "MVC", + [OR ] = "OR", + [MOV] = "MOV", + [IML] = "IML", + [IDV] = "IDV", + [PSH] = "PSH", + [PUL] = "PUL", + [NEG] = "NEG", + [SET] = "SET", + NULL +}; + +static const char *set_cc[] = { + "NG", + "PO", + "CS", + "CC", + "EQ", + "NE", + "VS", + "VC", + NULL +}; + +static const int addr_mode_type[AMT_LEN] = { + [AMT_IMM ] = IMM, + [AMT_ZM ] = ZM, + [AMT_ZMX ] = ZMX, + [AMT_ZMY ] = ZMY, + [AMT_IND ] = IND, + [AMT_INDX ] = INDX, + [AMT_INDY ] = INDY, + [AMT_ABS ] = ABS, + [AMT_REL ] = REL, + [AMT_BREG ] = BREG, + [AMT_IMPL ] = IMPL, + [AMT_INDX2 ] = INDX, + [AMT_ZM2 ] = ZM, + [AMT_EIND ] = EIND, + [AMT_EIND2 ] = EIND, + [AMT_ABY ] = ABSY, + [AMT_ABX ] = ABSX, + [AMT_AIND ] = AIND, + [AMT_AINDY ] = AINDY, + [AMT_AINDX ] = AINDX, + [AMT_ORTHO ] = ORTHO_EXT, + [AMT_ORTHO2] = ORTHO_EXT +}; + +static const uint8_t ext_ortho_ops[9] = { + [OP_LEA] = 0x63, + [OP_PEA] = 0x4C, + [OP_ADD] = 0x03, + [OP_SUB] = 0x23, + [OP_NOT] = 0x44, + [OP_CLZ] = 0xC4, + [OP_CLO] = 0xE4, + [OP_SWP] = 0x6C, + [OP_PCN] = 0x43 +}; + +static const uint8_t ind_ops[20] = { + [CMP_IND] = CMP_IN, + [CMP_IDY] = CMP_IY, + [CMP_IDX] = CMP_IX, + [CPB_IND] = CPB_IN, + [CPB_IDY] = CPB_IY, + [CPB_IDX] = CPB_IX, + [JMP_IND] = JMP_IN, + [JSR_IND] = JSR_IN, + [LDA_IND] = LDA_IN, + [LDA_IDY] = LDA_IY, + [LDB_IND] = LDB_IN, + [LDB_IDY] = LDB_IY, + [LDX_IND] = LDX_IN, + [LDY_IND] = LDY_IN, + [STA_IND] = STA_IN, + [STA_IDY] = STA_IY, + [STB_IND] = STB_IN, + [STB_IDY] = STB_IY, + [STX_IND] = STX_IN, + [STY_IND] = STY_IN +}; + +static const uint8_t eind_base_ops[10] = { + [DEC_EIND] = DEC_E, + [INC_EIND] = INC_E, + [STY_EIND] = STY_E, + [STA_EIND] = STA_E, + [STB_EIND] = STB_E, + [LDX_EIND] = LDX_E, + [STX_EIND] = STX_E, + [CPB_EIND] = CPB_E, + [CPX_EIND] = CPX_E, + [CPY_EIND] = CPY_E +}; + +static const instruction inst[OPNUM] = { + [ADC] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND|AM_ORTHO), 0x01}, + [AND] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND|AM_ORTHO), 0x41}, + [ASR] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND|AM_ORTHO), 0x62}, + [BCC] = {(AM_REL), 0xA0}, + [BCS] = {(AM_REL), 0x90}, + [BEQ] = {(AM_REL), 0xB0}, + [BNE] = {(AM_REL), 0xC0}, + [BNG] = {(AM_REL), 0x80}, + [BPO] = {(AM_REL), 0x70}, + [BRA] = {(AM_REL), 0xF0}, + [BRK] = {(AM_IMPL), 0x69}, + [BVC] = {(AM_REL), 0xE0}, + [BVS] = {(AM_REL), 0xD0}, + [CLC] = {(AM_IMPL), 0x09}, + [CLI] = {(AM_IMPL), 0x29}, + [CLV] = {(AM_IMPL), 0x49}, + [CMP] = {(AM_IMM|AM_ZM|AM_IND|AM_INDY|AM_ABS|AM_BREG|AM_INDX2|AM_EIND|AM_ORTHO), 0x82}, + [CPB] = {(AM_IMM|AM_ZM|AM_IND|AM_INDY|AM_ABS|AM_INDX2|AM_EIND2), 0x04}, + [CPS] = {(AM_IMPL), 0x00}, + [CPX] = {(AM_IMM|AM_ZM|AM_IND|AM_ABS|AM_EIND2), 0x24}, + [CPY] = {(AM_IMM|AM_ZM|AM_IND|AM_ABS|AM_EIND2), 0x44}, + [DEB] = {(AM_IMPL), 0x99}, + [DEC] = {(AM_IMPL|AM_ZM|AM_ABS|AM_EIND2|AM_ORTHO2), 0x84}, + [DEX] = {(AM_IMPL), 0xB9}, + [DEY] = {(AM_IMPL), 0x79}, + [DIV] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND|AM_ORTHO), 0x42}, + [INB] = {(AM_IMPL), 0xA9}, + [INC] = {(AM_IMPL|AM_ZM|AM_ABS|AM_EIND2|AM_ORTHO2), 0xA4}, + [INX] = {(AM_IMPL), 0xC9}, + [INY] = {(AM_IMPL), 0x89}, + [JMP] = {(AM_ABS|AM_IND|AM_ZM2|AM_EIND|AM_ORTHO|AM_ORTHO2), 0x00}, + [JSR] = {(AM_ABS|AM_IND|AM_ZM2|AM_EIND|AM_ORTHO|AM_ORTHO2), 0x20}, + [LDA] = {(AM_IMM|AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_EIND), 0xC2}, + [LDB] = {(AM_IMM|AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_EIND), 0xE2}, + [LDX] = {(AM_IMM|AM_ZM|AM_IND|AM_ABS|AM_EIND2), 0x64}, + [LDY] = {(AM_IMM|AM_ZM|AM_IND|AM_ABS|AM_EIND), 0xA2}, + [LSL] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND|AM_ORTHO), 0xA1}, + [LSR] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND|AM_ORTHO), 0xC1}, + [MUL] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND|AM_ORTHO), 0x22}, + [NOP] = {(AM_IMPL), 0xEA}, + [ORA] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0x61}, + [PHA] = {(AM_IMPL), 0x8E}, + [PHB] = {(AM_IMPL), 0xAE}, + [PHP] = {(AM_IMPL), 0x6E}, + [PHX] = {(AM_IMPL), 0xEE}, + [PHY] = {(AM_IMPL), 0xCE}, + [PLA] = {(AM_IMPL), 0x9E}, + [PLB] = {(AM_IMPL), 0xBE}, + [PLP] = {(AM_IMPL), 0x7E}, + [PLX] = {(AM_IMPL), 0xFE}, + [PLY] = {(AM_IMPL), 0xDE}, + [ROL] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND|AM_ORTHO), 0xE1}, + [ROR] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND|AM_ORTHO), 0x02}, + [RTI] = {(AM_IMPL), 0x60}, + [RTS] = {(AM_IMPL), 0x50}, + [SBC] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND|AM_ORTHO), 0x21}, + [SEC] = {(AM_IMPL), 0x19}, + [SEI] = {(AM_IMPL), 0x39}, + [STA] = {(AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_EIND2), 0x28}, + [STB] = {(AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_EIND2), 0x48}, + [STX] = {(AM_ZM|AM_IND|AM_ABS|AM_EIND2), 0x68}, + [STY] = {(AM_ZM|AM_IND|AM_ABS|AM_EIND2), 0x08}, + [TAB] = {(AM_IMPL), 0x0A}, + [TAX] = {(AM_IMPL), 0x4A}, + [TAY] = {(AM_IMPL), 0x2A}, + [TBA] = {(AM_IMPL), 0x1A}, + [TSX] = {(AM_IMPL), 0x8A}, + [TXA] = {(AM_IMPL), 0x5A}, + [TXS] = {(AM_IMPL), 0x9A}, + [TXY] = {(AM_IMPL), 0x7A}, + [TYA] = {(AM_IMPL), 0x3A}, + [TYX] = {(AM_IMPL), 0x6A}, + [WAI] = {(AM_IMPL), 0x59}, + [XOR] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND|AM_ORTHO), 0x81} +}; + +static const instruction ext_inst[EXT_OPNUM] = { + [LEA] = {(AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_ABX|AM_ABY|AM_AIND|AM_AINDX|AM_AINDY|AM_ORTHO), 0x03}, + [PEA] = {(AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_ABX|AM_ABY|AM_AIND|AM_AINDX|AM_AINDY|AM_ORTHO2), 0x23}, + [ADD] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND|AM_ORTHO), 0x06}, + [SUB] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND|AM_ORTHO), 0x26}, + [ADE] = {(AM_IMM|AM_ZM|AM_ABS), 0x46}, + [SBE] = {(AM_IMM|AM_ZM|AM_ABS), 0x66}, + [ADS] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND), 0x86}, + [SBS] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND), 0xA6}, + [NOT] = {(AM_IMPL|AM_ZM|AM_ABS|AM_EIND|AM_ORTHO2), 0xC6}, + [LLM] = {(AM_ZM|AM_ABS|AM_EIND), 0x48}, + [LRM] = {(AM_ZM|AM_ABS|AM_EIND), 0x68}, + [RLM] = {(AM_ZM|AM_ABS|AM_EIND), 0x88}, + [RRM] = {(AM_ZM|AM_ABS|AM_EIND), 0xA8}, + [ARM] = {(AM_ZM|AM_ABS|AM_EIND), 0xC8}, + [PHE] = {(AM_IMPL), 0x6B}, + [PLE] = {(AM_IMPL), 0x7B}, + [CPE] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND), 0x08}, + [ICE] = {(AM_ZM|AM_ABS|AM_EIND), 0x28}, + [LDS] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND), 0x40}, + [DEE] = {(AM_IMPL), 0x8B}, + [INE] = {(AM_IMPL), 0x9B}, + [DES] = {(AM_IMPL), 0xAB}, + [INS] = {(AM_IMPL), 0xBB}, + [STS] = {(AM_ZM|AM_ABS|AM_EIND), 0xA0}, + [STE] = {(AM_ZM|AM_ABS), 0xC0}, + [STZ] = {(AM_ZM|AM_ABS|AM_EIND), 0xE0}, + [SCO] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND), 0x60}, + [ECO] = {(AM_ZM|AM_ABS|AM_EIND), 0x80}, + [CLZ] = {(AM_ZM|AM_ABS|AM_EIND|AM_ORTHO2), 0x05}, + [CLO] = {(AM_ZM|AM_ABS|AM_EIND|AM_ORTHO2), 0x25}, + [BIT] = {(AM_ZM|AM_ABS|AM_EIND), 0x45}, + [MMV] = {(AM_IMPL), 0xCB}, + [SWP] = {(AM_IMPL|AM_ZM|AM_ABS|AM_EIND|AM_ORTHO2), 0xE6}, + [PCN] = {(AM_ZM|AM_ABS|AM_EIND|AM_ORTHO), 0xE8}, + [REP] = {(AM_REL), 0xBD}, + [REQ] = {(AM_REL), 0xCD}, + [RNE] = {(AM_REL), 0xDD}, + [LNG] = {(AM_IMM|AM_EIND2), 0x0D}, + [LPO] = {(AM_IMM|AM_EIND2), 0x2D}, + [LCS] = {(AM_IMM|AM_EIND2), 0x4D}, + [LCC] = {(AM_IMM|AM_EIND2), 0x6D}, + [LEQ] = {(AM_IMM|AM_EIND2), 0x8D}, + [LNE] = {(AM_IMM|AM_EIND2), 0xAD}, + [SNG] = {(AM_EIND2), 0x1D}, + [SPO] = {(AM_EIND2), 0x3D}, + [SCS] = {(AM_EIND2), 0x5D}, + [SCC] = {(AM_EIND2), 0x7D}, + [SEQ] = {(AM_EIND2), 0x9D}, + [SNE] = {(AM_EIND2), 0xBD} +}; + +static const instruction ortho_inst[ORTHO_OPNUM] = { + [MNG] = {(AM_ORTHO), 0x00}, + [MPO] = {(AM_ORTHO), 0x20}, + [MCS] = {(AM_ORTHO), 0x40}, + [MCC] = {(AM_ORTHO), 0x60}, + [MEQ] = {(AM_ORTHO), 0x80}, + [MNE] = {(AM_ORTHO), 0xA0}, + [MVS] = {(AM_ORTHO), 0xC0}, + [MVC] = {(AM_ORTHO), 0xE0}, + [OR ] = {(AM_ORTHO), 0x61}, + [MOV] = {(AM_ORTHO), 0xA2}, + [IML] = {(AM_ORTHO), 0xC2}, + [IDV] = {(AM_ORTHO), 0xE2}, + [PSH] = {(AM_ORTHO2), 0x04}, + [PUL] = {(AM_ORTHO2), 0x24}, + [NEG] = {(AM_ORTHO2), 0x64}, + [SET] = {(AM_ORTHO2), 0x05} +}; |