#include #include #include #include "mnemonics.h" #include "nqasm.h" #include "lexer.h" #include "parser.h" #include "vector.h" struct label { const char *name; uint16_t addr; }; uint16_t addr; static int cmp_label(const void *a, const void *b) { const struct label *la = a, *lb = b; return strcmp(la->name, lb->name); } #define DEFINE_VECTOR(name, arraytype, arrayname, initsize) \ static struct name { \ struct vector v; \ arraytype arrayname[]; \ } *name; \ \ static int name ## _init(void) \ { \ return !(name = vector_init(initsize, sizeof (arraytype), sizeof *name)); \ } \ \ static arraytype *name ## _append(void) \ { \ struct vector *v = &name->v; \ arraytype *e = vector_append(&v); \ name = (struct name *)v; \ return e; \ } DEFINE_VECTOR(labels, struct label, l, 8) DEFINE_VECTOR(instrs, struct instruction, i, 256) void add_instruction(const struct instruction *inst) { struct instruction *i = instrs_append(); if (!i) { fprintf(stderr, "unable to allocate instruction\n"); exit(1); } *i = *inst; addr += 2; } struct argument *argdup(const struct argument *arg) { struct argument *ret = malloc(sizeof *ret); if (!ret) { fprintf(stderr, "unable to allocate argument\n"); exit(1); } *ret = *arg; return ret; } static long eval_argument(const struct argument *arg, uint16_t pc) { struct label *l; switch (arg->type) { case ARG_INTEGER: return arg->value; case ARG_PC: return pc; case ARG_UNARY_ADD: return eval_argument(arg->children[0], pc); case ARG_UNARY_SUB: return -eval_argument(arg->children[0], pc); case ARG_UNARY_NOT: return !eval_argument(arg->children[0], pc); case ARG_UNARY_INV: return ~eval_argument(arg->children[0], pc); case ARG_LABEL: l = vector_search(&labels->v, &(struct label) { .name = arg->label }, cmp_label); if (l) return l->addr; fprintf(stderr, "unknown label '%s'\n", arg->label); exit(1); default: assert(0); } } static void assemble_instruction(const struct instruction *inst, uint16_t pc) { const struct mnemonic *mnem = &mnemonics[inst->mnem]; uint16_t bits = mnem->bits; const struct operand *ops = mnem->operands; const struct argument *args = inst->args.args; for (int i = 0; i < 3 && ops[i].type; i++) { long value = eval_argument(args + i, pc); switch (ops[i].type) { case REG: case REGPTR: if (0 > value || value >= 8) { fprintf(stderr, "invalid register\n"); exit(1); } break; case IMM: if (-0x80 > value || value > 0xff) { fprintf(stderr, "immediate operand out of range\n"); exit(1); } break; case PCOFF: value -= pc; if (-0x80 > value || value > 0x7f) { fprintf(stderr, "pc offset operand out of range\n"); exit(1); } break; default: assert(0); } bits |= (value & 255) << ops[i].shift; } printf("%04x\n", bits); } void add_label(const char *name) { struct label *l = labels_append(); if (!l) { fprintf(stderr, "unable to allocate label\n"); exit(1); } *l = (struct label) { .name = name, .addr = addr }; } int main(int argc, char **argv) { labels_init(); instrs_init(); yyparse(); vector_sort(&labels->v, cmp_label); for (size_t i = 0; i < instrs->v.count; i++) { assemble_instruction(instrs->i + i, 2 * i); } return 0; }