#include "csv-parse.h" #include #include #include #include struct instruction { char *mne; /* Mnemonic. */ char *desc; /* Description */ char *com; /* Comment. */ uint8_t op[11]; /* 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 ", "B ", "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. */ BREG, /* B Register. */ 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[11] = { [IMM ] = "IMM", [ZM ] = "ZM", [ZMX ] = "ZMX", [ZMY ] = "ZMY", [IND ] = "IND", [INDX] = "INDX", [INDY] = "INDY", [ABS ] = "ABS", [REL ] = "REL", [BREG] = "BREG", [IMPL] = "IMPL" }; static const char *amcom[11] = { [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.", [BREG] = "B Register.", [IMPL] = "Implied." }; static const char *am_tok[11] = { [IMM ] = "#", [ZM ] = "zm", [ZMX ] = "zmx", [ZMY ] = "zmy", [IND ] = "ind", [INDX] = "indx", [INDY] = "indy", [ABS ] = "a", [REL ] = "rel", [BREG] = "B" }; 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 < 11; 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][11] = {"); puts("\t/*\t IMM\t ZM ZMX ZMY IND INDX INDY ABS REL B IMPL*/"); while (l) { inst *ins = l->inst; printf("\t[%s] = {", ins->mne); for (int j = 0; j < 11; j++) { printf("0x%02X%s", ins->op[j], (j < 10) ? ", " : "}"); } 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 'B': opc->am = BREG; 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("%3i", 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; }