summaryrefslogtreecommitdiff
path: root/opcode-bitmask-gen.c
diff options
context:
space:
mode:
authormrb0nk500 <b0nk@b0nk.xyz>2022-01-14 13:17:18 -0400
committermrb0nk500 <b0nk@b0nk.xyz>2022-01-14 13:17:18 -0400
commit4512575eb0dcc4a844a134d0c51a651b492c8f3b (patch)
treeaa9a0ef9d5cbf3ce734b63dabe8c98d9a87a0272 /opcode-bitmask-gen.c
parent794e602a99d0e082fe1df9e3b6df006832e52ba2 (diff)
Add a bitmask generator for the new instruction handler
macro. This program will help with generating the bitmasks for the instruction handler macro.
Diffstat (limited to 'opcode-bitmask-gen.c')
-rw-r--r--opcode-bitmask-gen.c565
1 files changed, 565 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;
+}