diff options
Diffstat (limited to 'nqasm.c')
-rw-r--r-- | nqasm.c | 60 |
1 files changed, 57 insertions, 3 deletions
@@ -1,3 +1,4 @@ +#include <assert.h> #include <stdint.h> #include <stdio.h> @@ -15,6 +16,12 @@ struct label { 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; \ @@ -49,7 +56,25 @@ void add_instruction(const struct instruction *inst) addr += 2; } -static void assemble_instruction(const struct instruction *inst) +static long eval_argument(const struct argument *arg) +{ + struct label *l; + switch (arg->type) { + case ARG_INTEGER: + return arg->value; + + 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; @@ -57,7 +82,34 @@ static void assemble_instruction(const struct instruction *inst) const struct operand *ops = mnem->operands; const struct argument *args = inst->args.args; for (int i = 0; i < 3 && ops[i].type; i++) { - bits |= args[i].value << ops[i].shift; + long value = eval_argument(args + i); + + 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); @@ -84,8 +136,10 @@ int main(int argc, char **argv) yyparse(); + vector_sort(&labels->v, cmp_label); + for (size_t i = 0; i < instrs->v.count; i++) { - assemble_instruction(instrs->i + i); + assemble_instruction(instrs->i + i, 2 * i); } return 0; |