summaryrefslogtreecommitdiff
path: root/opcode-gen.c
diff options
context:
space:
mode:
Diffstat (limited to 'opcode-gen.c')
-rw-r--r--opcode-gen.c505
1 files changed, 505 insertions, 0 deletions
diff --git a/opcode-gen.c b/opcode-gen.c
new file mode 100644
index 0000000..3091e05
--- /dev/null
+++ b/opcode-gen.c
@@ -0,0 +1,505 @@
+#include "csv-parse.h"
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <unistd.h>
+
+struct instruction {
+ char *mne; /* Mnemonic. */
+ char *desc; /* Description */
+ char *com; /* Comment. */
+ uint8_t op[10]; /* Opcodes. */
+};
+
+struct opcode {
+ char *mne; /* Mnemonic. */
+ uint8_t am; /* Addressing Mode. */
+ uint8_t op; /* opcode. */
+ struct opcode *next;
+};
+
+typedef struct instruction inst;
+typedef struct opcode opcode;
+
+struct list {
+ struct list *next;
+ inst *inst;
+};
+
+typedef struct list list;
+
+list *lists = 0;
+list *last_list = 0;
+
+opcode *opcodes = 0;
+opcode *last_opcode = 0;
+
+const char *ams[] = { /* Addressing modes. */
+ "IMM ",
+ "Z ",
+ "ZX ",
+ "ZY ",
+ "IN ",
+ "IX ",
+ "IY ",
+ "AB ",
+ "REL ",
+ "IMP "
+};
+
+enum am {
+ /* Part of Base ISA. */
+ IMM, /* Immediate Data. */
+ ZM, /* Zero Matrix. */
+ ZMX, /* Zero Matrix, indexed with X. */
+ ZMY, /* Zero Matrix, indexed with Y. */
+ IND, /* Indirect. */
+ INDX, /* Indexed Indirect. */
+ INDY, /* Indirect Indexed. */
+ ABS, /* Absolute. */
+ REL, /* Relative to Program Counter. */
+ IMPL, /* Implied. */
+ /* Part of Base Extension. */
+ ABSX, /* Absolute, Indexed with X. */
+ ABSY, /* Absolute, Indexed with Y. */
+ SPI, /* Stack Pointer, Immediate Offset. */
+ SPX, /* Stack Pointer, Offset with X. */
+ SPY, /* Stack Pointer, Offset with Y. */
+ INA, /* Absolute Indirect. */
+ INAX, /* Absolute Indexed Indirect. */
+ INAY, /* Absolute Indirect Indexed. */
+ EIND, /* Effective Address Register, Indirect. */
+};
+
+static const char *addrmodes[10] = {
+ [IMM ] = "IMM",
+ [ZM ] = "ZM",
+ [ZMX ] = "ZMX",
+ [ZMY ] = "ZMY",
+ [IND ] = "IND",
+ [INDX] = "INDX",
+ [INDY] = "INDY",
+ [ABS ] = "ABS",
+ [REL ] = "REL",
+ [IMPL] = "IMPL"
+};
+
+static const char *amcom[10] = {
+ [IMM ] = "Immediate.",
+ [ZM ] = "Zero Matrix.",
+ [ZMX ] = "Zero Marrix, Indexed with X.",
+ [ZMY ] = "Zero Marrix, Indexed with Y.",
+ [IND ] = "Indirect",
+ [INDX] = "Indexed Indirect.",
+ [INDY] = "Indirect Indexed.",
+ [ABS ] = "Absolute.",
+ [REL ] = "Relative.",
+ [IMPL] = "Implied."
+};
+
+static const char *am_tok[10] = {
+ [IMM ] = "#",
+ [ZM ] = "zm",
+ [ZMX ] = "zmx",
+ [ZMY ] = "zmy",
+ [IND ] = "ind",
+ [INDX] = "indx",
+ [INDY] = "indy",
+ [ABS ] = "a",
+ [REL ] = "rel",
+};
+
+int get_instcount(list *l) {
+ int i = 0;
+ for (; l != NULL; l = l->next, i++);
+ return i;
+}
+
+inst *make_inst(opcode *opc, char *mne, char *desc, char *com) {
+ inst *ins = malloc(sizeof(inst));
+ ins->mne = mne;
+ ins->desc = desc;
+ ins->com = com;
+
+ for (int i = 0; i < 10; i++) {
+ ins->op[i] = 0xFF;
+ }
+
+ while (opc != NULL) {
+ if (!strcasecmp(opc->mne, mne)) {
+ ins->op[opc->am] = opc->op;
+ }
+ opc = opc->next;
+ }
+ return ins;
+}
+
+list *make_list(char *mne, char *desc, char *com) {
+ list *l = malloc(sizeof(list));
+ (last_list) ? (last_list->next = l) : (lists = l);
+ l->inst = make_inst(opcodes, mne, desc, com);
+ l->next = NULL;
+ last_list = l;
+ return l;
+}
+
+void free_lists() {
+ list *l = lists;
+ list *nl;
+ while (l != NULL) {
+ nl = l;
+ l = l->next;
+ /*free(nl->inst->mne);*/
+ free(nl->inst);
+ free(nl);
+ }
+}
+
+void free_opcodes() {
+ opcode *opc = opcodes;
+ opcode *op;
+ while (opc != NULL) {
+ op = opc;
+ opc = opc->next;
+ /*if (op->mne == NULL) {
+ free(op->mne);
+ }*/
+ free(op);
+ }
+}
+
+void print_optable(list *l, int maxop) {
+ int i = 0;
+ puts("static const uint8_t opcodes[OPNUM][10] = {");
+ puts("\t/*\t IMM\t ZM ZMX ZMY IND INDX INDY ABS REL IMPL*/");
+ while (l) {
+ inst *ins = l->inst;
+ printf("\t[%s] = {", ins->mne);
+ for (int j = 0; j < 10; j++) {
+ printf("0x%02X%s", ins->op[j], (j < 9) ? ", " : "}");
+ }
+ putchar((l->next) ? ',' : ' ');
+ printf(" /* %s */\n", ins->mne);
+ i++;
+ l = l->next;
+ }
+ puts("};");
+}
+
+opcode *lex_value(char *str, int op) {
+ opcode *opc = malloc(sizeof(opcode));
+ (last_opcode) ? (last_opcode->next = opc) : (opcodes = opc);
+ int i = 0;
+ char *mnemonic;
+
+ for (;str[i] != ' ' && !iseol(str[i]); i++);
+ mnemonic = malloc(i+1);
+ memcpy(mnemonic, str, i);
+ mnemonic[i] = '\0';
+ opc->mne = mnemonic;
+ opc->op = op;
+
+ if (iseol(str[i])) {
+ opc->am = IMPL;
+ } else {
+ i++;
+ }
+
+ while (!iseol(str[i])) {
+ int ismulti = 0; /* Is this a multi character token? */
+ switch(str[i]) {
+ default : ismulti = 1;
+ case 'A': opc->am = IMPL; break;
+ case '#': opc->am = IMM ; break;
+ case 'a': opc->am = ABS ; break;
+ case 'r': opc->am = REL ; i += 2; break;
+ case 'z':
+ switch (str[i+2]) {
+ case 'x': opc->am = ZMX; break;
+ case 'y': opc->am = ZMY; break;
+ default : opc->am = ZM ; break;
+ }
+ i += 2;
+ break;
+ case 'i':
+ switch (str[i+2]) {
+ case 'x': opc->am = INDX; break;
+ case 'y': opc->am = INDY; break;
+ default : opc->am = IND ; break;
+ }
+ i += 2;
+ break;
+ }
+ /*if (ismulti) {
+ if (!strcmp(str, "zm")) {
+ switch (i+2) {
+ case 'x': ins->op[ZMX] = opcode; break;
+ case 'y': ins->op[ZMY] = opcode; break;
+ default : ins->op[ZM ] = opcode; break;
+ }
+ i += 2;
+ } else if (!strcmp(str, "in")) {
+ switch (i+2) {
+ case 'x': ins->op[INDX] = opcode; break;
+ case 'y': ins->op[INDY] = opcode; break;
+ default : ins->op[IND ] = opcode; break;
+ }
+ i += 2;
+ } else if (!strcmp(str, "rel")) {
+ ins->op[REL] = opcode;
+ }
+ }*/
+ i++;
+ }
+ opc->next = NULL;
+ last_opcode = opc;
+ return opc;
+}
+
+int get_lownibble(line *l, int col) {
+ token *t = l->tok;
+ int i = 0;
+ while (t != NULL) {
+ i += t->skip;
+ if (i == col) {
+ return strtol(t->value, NULL, 16);
+ }
+ i++;
+ t = t->next;
+ }
+ return 0xFF;
+}
+
+uint8_t get_optotal(opcode *opc) {
+ uint8_t i = 0;
+ for (; opc != NULL; opc = opc->next, i++);
+ return i;
+}
+
+inst *find_inst(char *mne) {
+ list *l = lists;
+ while (l != NULL) {
+ inst *ins = l->inst;
+ if (!strcasecmp(mne, ins->mne)) {
+ return ins;
+ }
+ l = l->next;
+ }
+ return NULL;
+}
+
+void print_openum(opcode *opc, char *name) {
+ printf("enum %s {\n", name);
+ while (opc != NULL) {
+ inst *ins = find_inst(opc->mne);
+ if (ins == NULL) {
+ opc = opc->next;
+ continue;
+ }
+ uint8_t i = 0;
+ for (; ins->op[i] == 0xFF; i++);
+ putchar('\t');
+ /*if (i == opc->am || opc->am == IMPL) {
+ printf("%s ", opc->mne);
+ } else {
+ printf("%s_%s", opc->mne, ams[opc->am]);
+ }*/
+ printf("%s_%s", opc->mne, ams[opc->am]);
+ printf("= 0x%02X", opc->op);
+ putchar((opc->next != NULL) ? ',' : ' ');
+ if ((opc->am == IMPL && ins->op[IMPL] != 0xFF) || (i == opc->am && ins->op[IMPL] == 0xFF)) {
+ printf(" /* %s */", ins->com);
+ } else {
+ printf(" /* %s %s */", opc->mne, amcom[opc->am]);
+ }
+ putchar('\n');
+ opc = opc->next;
+ }
+ puts("};");
+}
+
+void print_mneenum(list *l, char *name) {
+ int i = 0;
+ int inst_count = get_instcount(l);
+ printf("enum %s {\n", name);
+ while (l) {
+ inst *ins = l->inst;
+ putchar('\t');
+ printf("%s = ", ins->mne);
+ if (i < 100 && inst_count >= 100) {
+ putchar(' ');
+ }
+ if (i < 10 && inst_count >= 10) {
+ putchar(' ');
+ }
+ printf("%i", i);
+ putchar((l->next) ? ',' : ' ');
+ putchar('\n');
+ i++;
+ l = l->next;
+ }
+ puts("};");
+}
+
+void print_optype(opcode *opc) {
+ uint8_t optotal = get_optotal(opc);
+ puts("static const uint8_t optype[0x100] = {");
+ while (opc != NULL) {
+ inst *ins = find_inst(opc->mne);
+ if (ins == NULL) {
+ opc = opc->next;
+ continue;
+ }
+ uint8_t i = 0;
+ for (; ins->op[i] == 0xFF; i++);
+ putchar('\t');
+ putchar('[');
+ printf("%s_%s", opc->mne, ams[opc->am]);
+ printf("] = %s", addrmodes[opc->am]);
+ putchar((opc->next != NULL) ? ',' : ' ');
+ putchar('\n');
+ opc = opc->next;
+ }
+ puts("};");
+}
+
+void print_mne(list *l) {
+ puts("static const char *mne[OPNUM] = {");
+ while (l != NULL) {
+ inst *ins = l->inst;
+ printf("\t[%s] = \"%s\"", ins->mne, ins->mne);
+ putchar((l->next) ? ',' : ' ');
+ putchar('\n');
+ l = l->next;
+ }
+ puts("};");
+}
+
+void print_instdesc(list *l) {
+ puts("static const char *instdesc[OPNUM] = {");
+ while (l != NULL) {
+ inst *ins = l->inst;
+ printf("\t[%s] = \"%s\"", ins->mne, ins->desc);
+ putchar((l->next) ? ',' : ' ');
+ putchar('\n');
+ l = l->next;
+ }
+ puts("};");
+}
+
+void print_opname(opcode *opc) {
+ puts("static const char *opname[0x100] = {");
+ while (opc != NULL) {
+ inst *ins = find_inst(opc->mne);
+ if (ins == NULL) {
+ opc = opc->next;
+ continue;
+ }
+ uint8_t i = 0;
+ for (; ins->op[i] == 0xFF; i++);
+ putchar('\t');
+ printf("[%s_%s", opc->mne, ams[opc->am]);
+ printf("] = \"%s", opc->mne);
+ if (opc->am != IMPL) {
+ printf(" %s", am_tok[opc->am]);
+ }
+ putchar('\"');
+ putchar((opc->next != NULL) ? ',' : ' ');
+ putchar('\n');
+ opc = opc->next;
+ }
+ puts("};");
+}
+
+int main(int argc, char **argv) {
+ FILE *fp;
+ char *fn = (argc) ? argv[1] : NULL;
+ int i = 0;
+ int j = 0;
+ int maxop = 0;
+ fp = (fn) ? fopen(fn, "r") : stdin;
+ if (fp == NULL) {
+ return 1;
+ }
+
+ parse_csv(fp);
+
+ line *l = lines;
+ line *lns = l; /* Low nibbles. */
+ list *ls;
+ opcode *opc;
+ l = l->next;
+ i = 0;
+ int done = 0;
+ int isdesc = 0;
+ while (l != NULL) {
+ token *t = l->tok;
+ j = 0;
+ i += l->skip;
+ if (!done) {
+ int size = strlen(t->value);
+ int high_nibble = 0xFF;
+ if (isxdigit(t->value[0]) && !l->skip) {
+ high_nibble = strtol(t->value, NULL, 16);
+ t = t->next;
+ j++;
+ }
+ while (t != NULL) {
+ j += t->skip;
+ int low_nibble = get_lownibble(lns, j);
+ int op = (high_nibble << 4) | low_nibble;
+ if (op > 0xFF) {
+ done = 1;
+ break;
+ }
+
+ opc = lex_value(t->value, op);
+
+ /*printf("opcode: $%02X, Row %i, Column %i: %s\n", op, i, j, t->value);*/
+ t = t->next;
+ j++;
+ }
+ } else {
+ while (t != NULL) {
+ if (!strcasecmp(t->value, "mnemonic")) {
+ isdesc = 1;
+ break;
+ }
+ if (isdesc) {
+ char *mne;
+ char *desc;
+ char *com;
+
+ mne = t->value;
+ t = t->next;
+ desc = t->value;
+ t = t->next;
+ com = t->value;
+
+ ls = make_list(mne, desc, com);
+ }
+ t = t->next;
+ }
+ }
+ l = l->next;
+ i++;
+ }
+
+ i = 0;
+ int inst_count = get_instcount(lists);
+ printf("#define OPNUM %i\n", inst_count);
+ print_mneenum(lists, "mne");
+ print_optable(lists, inst_count);
+ print_openum(opcodes, "base_isa");
+ print_optype(opcodes);
+ print_opname(opcodes);
+ print_mne(lists);
+ print_instdesc(lists);
+
+ free_lines();
+ free_lists();
+ free_opcodes();
+
+ fclose(fp);
+ return 0;
+}