diff options
author | Bobby Bingham <koorogi@koorogi.info> | 2017-01-18 18:55:22 -0600 |
---|---|---|
committer | Bobby Bingham <koorogi@koorogi.info> | 2017-01-18 18:55:22 -0600 |
commit | 619c5cc4ab4bd94f9b270a9868bb5f08ffd76acb (patch) | |
tree | 5d58bf4f4cc66621f5327edb30ba593c72b4c5da | |
parent | 17d11b2e0af9cbbe9e2c02c4d1a3d2cb4509701e (diff) |
nqasm: allow specifying labels for operands
-rw-r--r-- | lexer.l | 1 | ||||
-rw-r--r-- | nqasm.c | 60 | ||||
-rw-r--r-- | nqasm.h | 7 | ||||
-rw-r--r-- | parser.y | 64 | ||||
-rw-r--r-- | vector.c | 10 | ||||
-rw-r--r-- | vector.h | 2 |
6 files changed, 100 insertions, 44 deletions
@@ -79,6 +79,7 @@ HEX [0-9a-f] <args>[-+]?{DEC}+ { return intlit(yytext, 10, &yylval.lval); } <args>0x{HEX}+ { return intlit(yytext+2, 16, &yylval.lval); } <args>{SP}*,{SP}* { return T_COMMA; } +<args>{LABEL} { SETSTR(yytext); return T_LABEL; } {SP}*{COMMENT}?\n { BEGIN(INITIAL); return T_EOL; } {SP}*{COMMENT} { BEGIN(INITIAL); return T_EOL; } @@ -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; @@ -1,9 +1,14 @@ #ifndef NQ_NQASM_H #define NQ_NQASM_H +#define ARG_INTEGER 0 +#define ARG_LABEL 1 + struct argument { + int type; union { - int value; + long value; + char *label; }; }; @@ -13,7 +13,8 @@ void yyerror(const char *msg) #define INSTRUCTION_ARGS(m,a) (struct instruction) { MNEM_ ## m, a } #define INSTRUCTION(m) (struct instruction) { MNEM_ ## m } #define MKARGS(...) (struct arguments) { { __VA_ARGS__ } } -#define MKARGVALUE(v) (struct argument) { .value = (v) } +#define MKARGVALUE(v) (struct argument) { .type = ARG_INTEGER, .value = (v) } +#define MKARGLABEL(l) (struct argument) { .type = ARG_LABEL, .label = (l) } %} @@ -84,16 +85,14 @@ void yyerror(const char *msg) %token T_COLON ":" %type <inst> inst -%type <arg> imm -%type <arg> pcoff +%type <arg> expr %type <args> a_reg2 %type <args> a_reg3 %type <args> a_regp %type <args> a_regp_reg %type <args> a_reg_regp -%type <args> a_reg_imm -%type <args> a_reg_pcoff -%type <args> a_pcoff +%type <args> a_reg_expr +%type <args> a_expr %type <lval> intlit %% @@ -136,17 +135,17 @@ inst: | T_LD_BL a_reg_regp { $$ = INSTRUCTION_ARGS(LD_BL, $2); } | T_LD_BH a_reg_regp { $$ = INSTRUCTION_ARGS(LD_BH, $2); } | T_LD_W a_reg_regp { $$ = INSTRUCTION_ARGS(LD_W, $2); } - | T_LDI_BL a_reg_imm { $$ = INSTRUCTION_ARGS(LDI_BL, $2); } - | T_LDI_BH a_reg_imm { $$ = INSTRUCTION_ARGS(LDI_BH, $2); } - | T_BEQ a_pcoff { $$ = INSTRUCTION_ARGS(BEQ, $2); } - | T_BNE a_pcoff { $$ = INSTRUCTION_ARGS(BNE, $2); } - | T_BGT a_pcoff { $$ = INSTRUCTION_ARGS(BGT, $2); } - | T_BGE a_pcoff { $$ = INSTRUCTION_ARGS(BGE, $2); } - | T_BLT a_pcoff { $$ = INSTRUCTION_ARGS(BLT, $2); } - | T_BLE a_pcoff { $$ = INSTRUCTION_ARGS(BLE, $2); } - | T_BRA a_pcoff { $$ = INSTRUCTION_ARGS(BRA, $2); } + | T_LDI_BL a_reg_expr { $$ = INSTRUCTION_ARGS(LDI_BL, $2); } + | T_LDI_BH a_reg_expr { $$ = INSTRUCTION_ARGS(LDI_BH, $2); } + | T_BEQ a_expr { $$ = INSTRUCTION_ARGS(BEQ, $2); } + | T_BNE a_expr { $$ = INSTRUCTION_ARGS(BNE, $2); } + | T_BGT a_expr { $$ = INSTRUCTION_ARGS(BGT, $2); } + | T_BGE a_expr { $$ = INSTRUCTION_ARGS(BGE, $2); } + | T_BLT a_expr { $$ = INSTRUCTION_ARGS(BLT, $2); } + | T_BLE a_expr { $$ = INSTRUCTION_ARGS(BLE, $2); } + | T_BRA a_expr { $$ = INSTRUCTION_ARGS(BRA, $2); } | T_JMP a_regp { $$ = INSTRUCTION_ARGS(JMP, $2); } - | T_ADDPC a_reg_pcoff { $$ = INSTRUCTION_ARGS(ADDPC, $2); } + | T_ADDPC a_reg_expr { $$ = INSTRUCTION_ARGS(ADDPC, $2); } | T_NOP { $$ = INSTRUCTION(NOP); } ; @@ -160,30 +159,15 @@ a_regp_reg: T_SPACE T_REGPTR "," T_REG { $$ = MKARGS($2, $4); } a_reg_regp: T_SPACE T_REG "," T_REGPTR { $$ = MKARGS($2, $4); } -a_reg_imm: - T_SPACE T_REG "," imm { $$ = MKARGS($2, $4); } -a_reg_pcoff: - T_SPACE T_REG "," pcoff { $$ = MKARGS($2, $4); } -a_pcoff: - T_SPACE pcoff { $$ = MKARGS($2); } - -pcoff: intlit { - if (-0x80 > $1 || $1 > 0x7f) { - yyerror("pc offset operand out of range"); - YYERROR; - } else { - $$ = MKARGVALUE((uint8_t) $1); - } - } - -imm: intlit { - if (-0x80 > $1 || $1 > 0xff) { - yyerror("immediate operand out of range"); - YYERROR; - } else { - $$ = MKARGVALUE((uint8_t) $1); - } - } +a_reg_expr: + T_SPACE T_REG "," expr { $$ = MKARGS($2, $4); } +a_expr: + T_SPACE expr { $$ = MKARGS($2); } + +expr: + intlit { $$ = MKARGVALUE($1); } + | T_LABEL { $$ = MKARGLABEL($1); } + ; intlit: T_INT | T_BADINT { @@ -35,3 +35,13 @@ void *vector_append(struct vector **vp) return (char*)v + v->arrayoff + v->count++ * v->elemsize; } +void vector_sort(struct vector *v, int (*cmp)(const void *, const void *)) +{ + qsort((char*)v + v->arrayoff, v->count, v->elemsize, cmp); +} + +void *vector_search(struct vector *v, const void *key, int (*cmp)(const void *, const void *)) +{ + return bsearch(key, (char*)v + v->arrayoff, v->count, v->elemsize, cmp); +} + @@ -9,5 +9,7 @@ struct vector { void *vector_init(size_t alloc, size_t elemsize, size_t arrayoff); void *vector_append(struct vector **vp); +void vector_sort(struct vector *v, int (*cmp)(const void *, const void *)); +void *vector_search(struct vector *v, const void *key, int (*cmp)(const void *, const void *)); #endif |