summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--opcode-bitmask-gen.c565
-rw-r--r--opcode-bitmask-gen.h552
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}
+};