diff options
Diffstat (limited to 'tasm')
| -rw-r--r-- | tasm/gen/gen_parser.c | 74 | ||||
| -rw-r--r-- | tasm/include/tasm/assembler.h | 4 | ||||
| -rw-r--r-- | tasm/src/assembler.c | 216 | ||||
| -rw-r--r-- | tasm/src/bits.c | 22 | ||||
| -rw-r--r-- | tasm/src/parser.y | 26 | ||||
| -rw-r--r-- | tasm/tests/labels.t | 13 |
6 files changed, 284 insertions, 71 deletions
diff --git a/tasm/gen/gen_parser.c b/tasm/gen/gen_parser.c index 79b33b1..9e2a4cf 100644 --- a/tasm/gen/gen_parser.c +++ b/tasm/gen/gen_parser.c @@ -929,8 +929,8 @@ static const yytype_int16 yyrline[] = 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 240, 243, 246, 249, 252, 255, 258, 261, 264, 267, 270, 273, 276, 279, 282, - 285, 288, 291, 295, 298, 302, 306, 310, 314, 317, - 320, 323, 326, 329, 332, 335, 339, 342, 348, 355, + 285, 288, 291, 295, 298, 302, 306, 311, 315, 318, + 321, 324, 327, 330, 333, 336, 340, 343, 348, 355, 358, 361, 365, 368, 371, 374, 378, 381, 384, 388, 391, 392, 393, 394, 397, 398, 401, 402, 403, 406, 407, 410, 411 @@ -2695,8 +2695,8 @@ yyreduce: case 102: /* i: jal gpr "," addr */ #line 292 "src/parser.y" - {emit_u(ctx, OPCODE_JAL, (yyvsp[-2].gpr), 0); - emit_reloc(ctx, RELOC_J, (yyvsp[0].str));} + {emit_reloc(ctx, RELOC_J, (yyvsp[0].str)); + emit_u(ctx, OPCODE_JAL, (yyvsp[-2].gpr), 0);} #line 2701 "gen/gen_parser.c" break; @@ -2708,91 +2708,91 @@ yyreduce: case 104: /* i: beq gpr "," gpr "," addr */ #line 299 "src/parser.y" - {emit_s(ctx, OPCODE_BRANCH, BRANCH_BEQ, (yyvsp[-4].gpr), (yyvsp[-2].gpr), 0); - emit_reloc(ctx, RELOC_B, (yyvsp[0].str));} + {emit_reloc(ctx, RELOC_B, (yyvsp[0].str)); + emit_s(ctx, OPCODE_BRANCH, BRANCH_BEQ, (yyvsp[-4].gpr), (yyvsp[-2].gpr), 0);} #line 2714 "gen/gen_parser.c" break; case 105: /* i: bne gpr "," gpr "," addr */ #line 303 "src/parser.y" - {emit_s(ctx, OPCODE_BRANCH, BRANCH_BNE, (yyvsp[-4].gpr), (yyvsp[-2].gpr), 0); - emit_reloc(ctx, RELOC_B, (yyvsp[0].str));} + {emit_reloc(ctx, RELOC_B, (yyvsp[0].str)); + emit_s(ctx, OPCODE_BRANCH, BRANCH_BNE, (yyvsp[-4].gpr), (yyvsp[-2].gpr), 0);} #line 2721 "gen/gen_parser.c" break; case 106: /* i: blt gpr "," gpr "," addr */ #line 307 "src/parser.y" - {emit_s(ctx, OPCODE_BRANCH, BRANCH_BLT, (yyvsp[-4].gpr), (yyvsp[-2].gpr), 0); - emit_reloc(ctx, RELOC_B, (yyvsp[0].str));} -#line 2728 "gen/gen_parser.c" + {emit_reloc(ctx, RELOC_B, (yyvsp[0].str)); + emit_s(ctx, OPCODE_BRANCH, BRANCH_BLT, (yyvsp[-4].gpr), (yyvsp[-2].gpr), 0); + } +#line 2729 "gen/gen_parser.c" break; case 107: /* i: bge gpr "," gpr "," addr */ -#line 311 "src/parser.y" - {emit_s(ctx, OPCODE_BRANCH, BRANCH_BGE, (yyvsp[-4].gpr), (yyvsp[-2].gpr), 0); - emit_reloc(ctx, RELOC_B, (yyvsp[0].str));} -#line 2735 "gen/gen_parser.c" +#line 312 "src/parser.y" + {emit_reloc(ctx, RELOC_B, (yyvsp[0].str)); + emit_s(ctx, OPCODE_BRANCH, BRANCH_BGE, (yyvsp[-4].gpr), (yyvsp[-2].gpr), 0);} +#line 2736 "gen/gen_parser.c" break; case 108: /* i: ld width "," gpr "," imm "(" gpr ")" */ -#line 315 "src/parser.y" +#line 316 "src/parser.y" {emit_i(ctx, OPCODE_LOAD, check_width((yyvsp[-7].str)), (yyvsp[-5].gpr), (yyvsp[-1].gpr), (yyvsp[-3].tri));} -#line 2741 "gen/gen_parser.c" +#line 2742 "gen/gen_parser.c" break; case 109: /* i: st width "," gpr "," imm "(" gpr ")" */ -#line 318 "src/parser.y" +#line 319 "src/parser.y" {emit_s(ctx, OPCODE_STORE, check_width((yyvsp[-7].str)), (yyvsp[-5].gpr), (yyvsp[-1].gpr), (yyvsp[-3].tri));} -#line 2747 "gen/gen_parser.c" +#line 2748 "gen/gen_parser.c" break; case 110: /* i: ecall */ -#line 321 "src/parser.y" +#line 322 "src/parser.y" {emit_i(ctx, OPCODE_SYSTEM, X0_NUM, SYSTEM_ECALL, X0_NUM, 0);} -#line 2753 "gen/gen_parser.c" +#line 2754 "gen/gen_parser.c" break; case 111: /* i: ebreak */ -#line 324 "src/parser.y" +#line 325 "src/parser.y" {emit_i(ctx, OPCODE_SYSTEM, X0_NUM, SYSTEM_EBREAK, X0_NUM, 0);} -#line 2759 "gen/gen_parser.c" +#line 2760 "gen/gen_parser.c" break; case 112: /* i: pcall */ -#line 327 "src/parser.y" +#line 328 "src/parser.y" {emit_i(ctx, OPCODE_SYSTEM, X0_NUM, SYSTEM_PCALL, X0_NUM, 0);} -#line 2765 "gen/gen_parser.c" +#line 2766 "gen/gen_parser.c" break; case 113: /* i: fence */ -#line 330 "src/parser.y" +#line 331 "src/parser.y" {emit_i(ctx, OPCODE_MEM, X0_NUM, MEM_FENCE, X0_NUM, 0); /* still todo */} -#line 2771 "gen/gen_parser.c" +#line 2772 "gen/gen_parser.c" break; case 114: /* i: unop gpr "," gpr "," str */ -#line 333 "src/parser.y" +#line 334 "src/parser.y" {emit_i(ctx, OPCODE_OP_IMM, (yyvsp[-4].gpr), OP_IMM_UNOP, (yyvsp[-2].gpr), check_nop((yyvsp[0].str)));} -#line 2777 "gen/gen_parser.c" +#line 2778 "gen/gen_parser.c" break; case 115: /* i: diop gpr "," gpr "," gpr "," str */ -#line 336 "src/parser.y" +#line 337 "src/parser.y" {emit_d(ctx, OPCODE_DIOP, (yyvsp[-6].gpr), (yyvsp[-4].gpr), (yyvsp[-2].gpr), check_nop3((yyvsp[0].str)));} -#line 2783 "gen/gen_parser.c" +#line 2784 "gen/gen_parser.c" break; case 116: /* i: nop */ -#line 340 "src/parser.y" +#line 341 "src/parser.y" {emit_i(ctx, OPCODE_OP_IMM, X0_NUM, OP_IMM_ADDI, X0_NUM, 0);} -#line 2789 "gen/gen_parser.c" +#line 2790 "gen/gen_parser.c" break; case 117: /* i: la gpr "," addr */ -#line 343 "src/parser.y" - {emit_u(ctx, OPCODE_LUI, (yyvsp[-2].gpr), 0); - /* important that the reloc is in the middle here */ - emit_reloc(ctx, RELOC_LA, (yyvsp[0].str)); +#line 344 "src/parser.y" + {emit_reloc(ctx, RELOC_LA, (yyvsp[0].str)); + emit_u(ctx, OPCODE_LUI, (yyvsp[-2].gpr), 0); emit_i(ctx, OPCODE_OP_IMM, (yyvsp[-2].gpr), OP_IMM_ADDI, (yyvsp[-2].gpr), 0);} #line 2798 "gen/gen_parser.c" break; diff --git a/tasm/include/tasm/assembler.h b/tasm/include/tasm/assembler.h index d687dbb..52ab867 100644 --- a/tasm/include/tasm/assembler.h +++ b/tasm/include/tasm/assembler.h @@ -6,7 +6,7 @@ struct asm_ctx; -enum asm_reloc { +enum asm_reloc_kind { /* absolute LUI + ADDI */ RELOC_LA, /* relative AUIPC + ADDI (currently unimplemented) */ @@ -35,7 +35,7 @@ void emit_d(struct asm_ctx *ctx, tri_t opcode, /* emits a relocation for the previous instruction, very important to keep in * mind! */ -void emit_reloc(struct asm_ctx *ctx, enum asm_reloc reloc, const char *name); +void emit_reloc(struct asm_ctx *ctx, enum asm_reloc_kind reloc, const char *name); void emit_label(struct asm_ctx *ctx, const char *name); tri_t check_nop(const char *nop); diff --git a/tasm/src/assembler.c b/tasm/src/assembler.c index c0c05be..9f6dc95 100644 --- a/tasm/src/assembler.c +++ b/tasm/src/assembler.c @@ -9,10 +9,29 @@ #include <stdio.h> #include <errno.h> +struct asm_symbol { + const char *name; + size_t offset; +}; + +struct asm_reloc { + enum asm_reloc_kind kind; + const char *sym; + size_t offset; +}; + struct asm_ctx { size_t size; size_t idx; tri_t *buf; + + size_t sym_max; + size_t sym_count; + struct asm_symbol *syms; + + size_t reloc_max; + size_t reloc_count; + struct asm_reloc *relocs; }; static void emit(struct asm_ctx *ctx, tri_t i) @@ -259,11 +278,174 @@ int process_file(struct asm_ctx *ctx, const char *file) return res; } +static struct asm_ctx *asm_ctx_create() +{ + struct asm_ctx *ctx = malloc(sizeof(struct asm_ctx)); + /* code buffer */ + ctx->size = 1; + ctx->buf = malloc(sizeof(tri_t)); + ctx->idx = 0; + + /* relocations */ + ctx->reloc_max = 1; + ctx->relocs = malloc(sizeof(struct asm_reloc)); + ctx->reloc_count = 0; + + /* symbols */ + ctx->sym_max = 1; + ctx->syms = malloc(sizeof(struct asm_reloc)); + ctx->sym_count = 0; + + return ctx; +} + +static void asm_ctx_relocs_destroy(struct asm_ctx *ctx) +{ + for (size_t i = 0; i < ctx->reloc_count; ++i) { + free((void *)ctx->relocs[i].sym); + } + + free(ctx->relocs); +} + +static void asm_ctx_syms_destroy(struct asm_ctx *ctx) +{ + for (size_t i = 0; i < ctx->sym_count; ++i) { + free((void *)ctx->syms[i].name); + } + + free(ctx->syms); +} + +static void asm_ctx_destroy(struct asm_ctx *ctx) +{ + free(ctx->buf); + asm_ctx_relocs_destroy(ctx); + asm_ctx_syms_destroy(ctx); + free(ctx); +} + +static void fix_reloc_la(struct asm_ctx *ctx, size_t ro, size_t so) +{ + tri_t t = tri_from(so); + /* 9 lowest */ + tri_t lo = tri_mask(t, 9); + /* 18 highest */ + tri_t hi = tri_mask(tri_sr(t, 9), 18); + + /* lui, assume zero-initialized immediate */ + tri_t lui = ctx->buf[ro]; + assert(parse_opcode(lui) == OPCODE_LUI); + tri_t rd, imm; + parse_u(lui, &rd, &imm); + assert(imm == 0); + ctx->buf[ro] = build_u(OPCODE_LUI, rd, hi); + + /* addi */ + tri_t addi = ctx->buf[ro + 1]; + assert(parse_opcode(addi) == OPCODE_OP_IMM); + tri_t fn0, rs1; + parse_i(addi, &rd, &fn0, &rs1, &imm); + assert(fn0 == OP_IMM_ADDI); + assert(imm == 0); + ctx->buf[ro + 1] = build_i(OPCODE_OP_IMM, rd, fn0, rs1, lo); +} + +static void fix_reloc_b(struct asm_ctx *ctx, size_t ro, size_t so) +{ + int64_t off = so - ctx->idx; + tri_t t = tri_from(off); + if (tri_mask(t, 9) != t) { + /* should really be line based rather than offset, but good + * enough for now */ + fprintf(stderr, "branch offset at %llu too large\n", + (unsigned long long)ro); + abort(); + } + + /* low five */ + tri_t lo = tri_mask(t, 5); + /* high four */ + tri_t hi = tri_mask(tri_sr(t, 5), 4); + + tri_t b = ctx->buf[ro]; + assert(parse_opcode(b) == OPCODE_BRANCH); + + tri_t imm4, fn0, rs1, rs2, imm5; + parse_s(b, &imm4, &fn0, &rs1, &rs2, &imm5); + assert(imm4 == 0 && imm5 == 0); + + ctx->buf[ro] = build_s(OPCODE_BRANCH, hi, fn0, rs1, rs2, lo); +} + +static void fix_reloc_j(struct asm_ctx *ctx, size_t ro, size_t so) +{ + int64_t off = so - ctx->idx; + tri_t t = tri_from(off); + if (tri_mask(t, 18) != t) { + fprintf(stderr, "jump offset at %llu too large\n", + (unsigned long long)ro); + abort(); + } + + tri_t j = ctx->buf[ro]; + assert(parse_opcode(j) == OPCODE_JAL); + + tri_t rd, imm18; + parse_u(j, &rd, &imm18); + assert(imm18 == 0); + + ctx->buf[ro] = build_u(OPCODE_JAL, rd, t); +} + +static int try_fix_reloc(struct asm_ctx *ctx, struct asm_reloc r) +{ + /* ideally this would probably be a hashmap, but good enough for now */ + for (size_t i = 0; i < ctx->sym_count; ++i) { + struct asm_symbol s = ctx->syms[i]; + if (strcmp(s.name, r.sym) != 0) + continue; + + size_t ro = r.offset; + size_t so = s.offset; + /* matching */ + switch (r.kind) { + case RELOC_LA: fix_reloc_la(ctx, ro, so); break; + case RELOC_B: fix_reloc_b(ctx, ro, so); break; + case RELOC_J: fix_reloc_j(ctx, ro, so); break; + default: fprintf(stderr, "unimplemented reloc: %d\n", r.kind); + abort(); + } + return 0; + } + + /* we didn't find a symbol matching reloc */ + return 1; +} + +static int fix_relocs(struct asm_ctx *ctx) +{ + for (size_t i = 0; i < ctx->reloc_count; ++i) { + struct asm_reloc r = ctx->relocs[i]; + if (try_fix_reloc(ctx, r)) { + /* we were unable to fulfill this reloc, fail */ + fprintf(stderr, "unable to fulfill reloc for %s\n", r.sym); + return 1; + } + } + + return 0; +} + int assemble(const char *outfile, const char *infile) { /** @todo cleanup */ - struct asm_ctx ctx = {.size = 1, .buf = malloc(sizeof(tri_t)), .idx = 0}; - int ret = process_file(&ctx, infile); + struct asm_ctx *ctx = asm_ctx_create(); + int ret = process_file(ctx, infile); + if (ret) + return ret; + + ret = fix_relocs(ctx); if (ret) return ret; @@ -271,8 +453,8 @@ int assemble(const char *outfile, const char *infile) if (!f) return -1; - for (size_t i = 0; i < ctx.idx; ++i) { - tri_t t = ctx.buf[i]; + for (size_t i = 0; i < ctx->idx; ++i) { + tri_t t = ctx->buf[i]; /* output trytewise LE */ uint32_t t0 = tri_mask(t, 9); uint32_t t1 = tri_mask(tri_sr(t, 9), 9); @@ -289,7 +471,8 @@ int assemble(const char *outfile, const char *infile) } fclose(f); - free(ctx.buf); + asm_ctx_destroy(ctx); + return 0; } void check_shift(tri_t shmt) @@ -382,12 +565,29 @@ tri_t check_width(const char *width) return 0; } -void emit_reloc(struct asm_ctx *ctx, enum asm_reloc reloc, const char *name) +void emit_reloc(struct asm_ctx *ctx, enum asm_reloc_kind reloc, const char *name) { - /** @todo implement */ + if (ctx->reloc_count >= ctx->reloc_max) { + ctx->reloc_max *= 2; + ctx->relocs = realloc(ctx->relocs, ctx->reloc_max * sizeof(struct asm_reloc)); + } + + ctx->relocs[ctx->reloc_count++] = (struct asm_reloc){ + .kind = reloc, + .sym = strdup(name), + .offset = ctx->idx + }; } void emit_label(struct asm_ctx *ctx, const char *name) { - /** @todo implement */ + if (ctx->sym_count >= ctx->sym_max) { + ctx->sym_max *= 2; + ctx->syms = realloc(ctx->syms, ctx->sym_max * sizeof(struct asm_symbol)); + } + + ctx->syms[ctx->sym_count++] = (struct asm_symbol){ + .name = strdup(name), + .offset = ctx->idx + }; } diff --git a/tasm/src/bits.c b/tasm/src/bits.c index 6397e2f..7a54632 100644 --- a/tasm/src/bits.c +++ b/tasm/src/bits.c @@ -36,10 +36,10 @@ tri_t build_i(tri_t opcode, tri_t rd, tri_t fn0, tri_t rs1, tri_t imm9) void parse_i(tri_t i, tri_t *rd, tri_t *fn0, tri_t *rs1, tri_t *imm9) { - *rd = tri_mask(tri_sl(i, 5), 4); - *fn0 = tri_mask(tri_sl(i, 9), 5); - *rs1 = tri_mask(tri_sl(i, 14), 4); - *imm9 = tri_mask(tri_sl(i, 18), 9); + *rd = tri_mask(tri_sr(i, 5), 4); + *fn0 = tri_mask(tri_sr(i, 9), 5); + *rs1 = tri_mask(tri_sr(i, 14), 4); + *imm9 = tri_mask(tri_sr(i, 18), 9); } tri_t build_s(tri_t opcode, tri_t imm4, tri_t fn0, tri_t rs1, tri_t rs2, tri_t imm5) @@ -54,11 +54,11 @@ tri_t build_s(tri_t opcode, tri_t imm4, tri_t fn0, tri_t rs1, tri_t rs2, tri_t i void parse_s(tri_t i, tri_t *imm4, tri_t *fn0, tri_t *rs1, tri_t *rs2, tri_t *imm5) { - *imm4 = tri_mask(tri_sl(i, 5), 4); - *fn0 = tri_mask(tri_sl(i, 9), 5); - *rs1 = tri_mask(tri_sl(i, 14), 4); - *rs2 = tri_mask(tri_sl(i, 18), 4); - *imm5 = tri_mask(tri_sl(i, 22), 5); + *imm4 = tri_mask(tri_sr(i, 5), 4); + *fn0 = tri_mask(tri_sr(i, 9), 5); + *rs1 = tri_mask(tri_sr(i, 14), 4); + *rs2 = tri_mask(tri_sr(i, 18), 4); + *imm5 = tri_mask(tri_sr(i, 22), 5); } tri_t build_u(tri_t opcode, tri_t rd, tri_t imm18) @@ -70,6 +70,6 @@ tri_t build_u(tri_t opcode, tri_t rd, tri_t imm18) void parse_u(tri_t i, tri_t *rd, tri_t *imm18) { - *rd = tri_mask(tri_sl(i, 5), 4); - *imm18 = tri_mask(tri_sl(i, 9), 18); + *rd = tri_mask(tri_sr(i, 5), 4); + *imm18 = tri_mask(tri_sr(i, 9), 18); } diff --git a/tasm/src/parser.y b/tasm/src/parser.y index ef8d3df..559cbba 100644 --- a/tasm/src/parser.y +++ b/tasm/src/parser.y @@ -289,27 +289,28 @@ i {emit_u(ctx, OPCODE_AUIPC, $2, $4);} | jal gpr "," addr - {emit_u(ctx, OPCODE_JAL, $2, 0); - emit_reloc(ctx, RELOC_J, $4);} + {emit_reloc(ctx, RELOC_J, $4); + emit_u(ctx, OPCODE_JAL, $2, 0);} | jalr gpr "," gpr "," imm {emit_i(ctx, OPCODE_JALR, $2, 0, $4, $6);} | beq gpr "," gpr "," addr - {emit_s(ctx, OPCODE_BRANCH, BRANCH_BEQ, $2, $4, 0); - emit_reloc(ctx, RELOC_B, $6);} + {emit_reloc(ctx, RELOC_B, $6); + emit_s(ctx, OPCODE_BRANCH, BRANCH_BEQ, $2, $4, 0);} | bne gpr "," gpr "," addr - {emit_s(ctx, OPCODE_BRANCH, BRANCH_BNE, $2, $4, 0); - emit_reloc(ctx, RELOC_B, $6);} + {emit_reloc(ctx, RELOC_B, $6); + emit_s(ctx, OPCODE_BRANCH, BRANCH_BNE, $2, $4, 0);} | blt gpr "," gpr "," addr - {emit_s(ctx, OPCODE_BRANCH, BRANCH_BLT, $2, $4, 0); - emit_reloc(ctx, RELOC_B, $6);} + {emit_reloc(ctx, RELOC_B, $6); + emit_s(ctx, OPCODE_BRANCH, BRANCH_BLT, $2, $4, 0); + } | bge gpr "," gpr "," addr - {emit_s(ctx, OPCODE_BRANCH, BRANCH_BGE, $2, $4, 0); - emit_reloc(ctx, RELOC_B, $6);} + {emit_reloc(ctx, RELOC_B, $6); + emit_s(ctx, OPCODE_BRANCH, BRANCH_BGE, $2, $4, 0);} | ld width "," gpr "," imm "(" gpr ")" {emit_i(ctx, OPCODE_LOAD, check_width($2), $4, $8, $6);} @@ -340,9 +341,8 @@ i {emit_i(ctx, OPCODE_OP_IMM, X0_NUM, OP_IMM_ADDI, X0_NUM, 0);} | la gpr "," addr - {emit_u(ctx, OPCODE_LUI, $2, 0); - /* important that the reloc is in the middle here */ - emit_reloc(ctx, RELOC_LA, $4); + {emit_reloc(ctx, RELOC_LA, $4); + emit_u(ctx, OPCODE_LUI, $2, 0); emit_i(ctx, OPCODE_OP_IMM, $2, OP_IMM_ADDI, $2, 0);} | li gpr "," imm diff --git a/tasm/tests/labels.t b/tasm/tests/labels.t new file mode 100644 index 0000000..5ad0d42 --- /dev/null +++ b/tasm/tests/labels.t @@ -0,0 +1,13 @@ +start: + /* RELOC_LA */ + la x1, other_func + /* RELOC_B */ + beq x0, x0, other_func + +other_func: + /* RELOC_J */ + jal x0, final_func + jal x0, start + +final_func: + nop |
