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} +}; | 
