From 4512575eb0dcc4a844a134d0c51a651b492c8f3b Mon Sep 17 00:00:00 2001 From: mrb0nk500 Date: Fri, 14 Jan 2022 13:17:18 -0400 Subject: Add a bitmask generator for the new instruction handler macro. This program will help with generating the bitmasks for the instruction handler macro. --- opcode-bitmask-gen.c | 565 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 565 insertions(+) create mode 100644 opcode-bitmask-gen.c (limited to 'opcode-bitmask-gen.c') 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 +#include +#include +#include +#include + +#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 [, ...] -i [, ...] -e \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; +} -- cgit v1.2.3-13-gbd6f