From 756c606af68be8ccca7aced3b9c3d56fb2d5087f Mon Sep 17 00:00:00 2001 From: mrb0nk500 Date: Mon, 6 Jul 2020 20:04:41 -0400 Subject: - Implemented a new opcode table. - Added a new preifx called the OF prefix, which adds the contents of a specific register to the current operand. - Added a table generator, which parses opcode table csv files. --- opcode-gen.c | 505 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 505 insertions(+) create mode 100644 opcode-gen.c (limited to 'opcode-gen.c') 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 +#include +#include +#include + +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; +} -- cgit v1.2.3-13-gbd6f