#include "csv-parse.h"
#include <ctype.h>
#include <inttypes.h>
#include <stdint.h>
#include <unistd.h>
struct instruction {
char *mne;
char *desc;
char *com;
uint8_t op[11];
};
struct opcode {
char *mne;
uint8_t am;
uint8_t op;
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[] = {
"IMM ",
"Z ",
"ZX ",
"ZY ",
"IN ",
"IX ",
"IY ",
"AB ",
"REL ",
"B ",
"IMP "
};
enum am {
IMM,
ZM,
ZMX,
ZMY,
IND,
INDX,
INDY,
ABS,
REL,
BREG,
IMPL,
ABSX,
ABSY,
SPI,
SPX,
SPY,
INA,
INAX,
INAY,
EIND,
};
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);
free(nl);
}
}
void free_opcodes() {
opcode *opc = opcodes;
opcode *op;
while (opc != NULL) {
op = opc;
opc = opc->next;
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;
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;
}
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');
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);
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;
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);
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;
}