diff options
Diffstat (limited to 'output')
-rw-r--r-- | output/output_asm.c | 134 | ||||
-rw-r--r-- | output/output_asm.h | 6 | ||||
-rw-r--r-- | output/output_bin.c | 200 | ||||
-rw-r--r-- | output/output_bin.h | 6 |
4 files changed, 346 insertions, 0 deletions
diff --git a/output/output_asm.c b/output/output_asm.c new file mode 100644 index 0000000..fd9f792 --- /dev/null +++ b/output/output_asm.c @@ -0,0 +1,134 @@ +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +#include "parse.h" +#include "util.h" + +static size_t inst_sizes[] = { + [INST_TYPE_R] = 2, + [INST_TYPE_NI] = 2, + [INST_TYPE_WI] = 4, + [INST_TYPE_JR] = 2, + [INST_TYPE_JI] = 4, + [INST_TYPE_B] = 2, +}; + +void emit_single_r_type(FILE *f, struct r_type inst) +{ + const char *oper = get_asm_from_oper(inst.oper); + const char *dest = get_asm_from_reg(inst.dest); + const char *left = get_asm_from_reg(inst.left); + const char *right = get_asm_from_reg(inst.right); + + fprintf(f, "%s %s, %s, %s\n", oper, dest, left, right); +} + +void emit_single_i_type(FILE *f, struct i_type inst) +{ + const char *oper = get_asm_from_oper(inst.oper); + const char *dest = get_asm_from_reg(inst.dest); + const char *left = get_asm_from_reg(inst.left); + + fprintf(f, "%si %s, %s, 0x%x\n", oper, dest, left, inst.imm.value); +} + +/*void emit_single_wi_type(FILE *f, struct i_type inst) +{ + const char *oper = get_asm_from_oper(inst.oper); + const char *dest = get_asm_from_oper(inst.dest); + const char *left = get_asm_from_oper(inst.left); + + fprintf(f, "%si %s, %s, 0x%s\n", oper, dest, left, inst.imm.value); +}*/ + +void emit_single_ji_type(FILE *f, struct ji_type inst) +{ + const char *cond = get_asm_from_j(inst.cond); + + fprintf(f, "%s 0x%x\n", cond, inst.imm.value); +} + +void emit_single_jr_type(FILE *f, struct jr_type inst) +{ + const char *cond = get_asm_from_j(inst.cond); + const char *reg = get_asm_from_reg(inst.reg); + + fprintf(f, "%s %s\n", cond, reg); +} + +void emit_single_b_type(FILE *f, struct b_type inst) +{ + const char *cond = get_asm_from_b(inst.cond); + + fprintf(f, "%s 0x%x\n", cond, inst.imm.value); +} + + +int look_up_label(struct label *labels, size_t labels_count, uint16_t *val, const char *label) +{ + size_t i = 0; + + for (i = 0; i < labels_count; i++) { + if (strcmp(labels[i].name, label) == 0) { + *val = labels[i].byte_offset; + return 0; + } + } + + /* FIXME emit */ + fprintf(stderr, "Reference to undefined label `%s'\n", label); + return 1; +} + +int output_single(FILE *f, size_t *cur_byte, struct label *labels, size_t labels_count, struct instruction inst) +{ + switch (inst.type) { + case INST_TYPE_R: + emit_single_r_type(f, inst.inst.r); + break; + case INST_TYPE_NI: + case INST_TYPE_WI: + if ( inst.inst.i.imm_is_ident + && look_up_label(labels, labels_count, &inst.inst.i.imm.value, inst.inst.i.imm.label)) + return 1; + + emit_single_i_type(f, inst.inst.i); + break; + case INST_TYPE_JR: + emit_single_jr_type(f, inst.inst.jr); + break; + case INST_TYPE_JI: + if ( inst.inst.ji.imm_is_ident + && look_up_label(labels, labels_count, &inst.inst.ji.imm.value, inst.inst.ji.imm.label)) + return 1; + + emit_single_ji_type(f, inst.inst.ji); + break; + case INST_TYPE_B: + if ( inst.inst.b.imm_is_ident + && look_up_label(labels, labels_count, &inst.inst.b.imm.value, inst.inst.b.imm.label)) + return 1; + emit_single_b_type(f, inst.inst.b); + break; + default: + fprintf(stderr, "Internal error: unhandled instruction type\n"); + break; + } + + *cur_byte += inst_sizes[inst.type]; + + return 0; +} + +int output_asm(FILE *fout, struct label *labels, size_t label_count, struct instruction *insts, size_t insts_count) +{ + size_t i = 0; + size_t cur_byte = 0; + + for (i = 0; i < insts_count; i++) + if (output_single(fout, &cur_byte, labels, label_count, insts[i])) + return 1; + + return 0; +} diff --git a/output/output_asm.h b/output/output_asm.h new file mode 100644 index 0000000..b4afd2a --- /dev/null +++ b/output/output_asm.h @@ -0,0 +1,6 @@ +#ifndef OUTPUT_ASM_H +#define OUTPUT_ASM_H + +int output_asm(FILE *fout, struct label *labels, size_t label_count, struct instruction *insts, size_t insts_count); + +#endif /* OUTPUT_ASM_H */ diff --git a/output/output_bin.c b/output/output_bin.c new file mode 100644 index 0000000..1c7b961 --- /dev/null +++ b/output/output_bin.c @@ -0,0 +1,200 @@ +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +#include "parse.h" + +static size_t cur_byte; + +int generate_single_r_type(uint32_t *dest, struct r_type inst) +{ + uint32_t i = 0; + + i |= MASK_INST_RTYPE; + i |= MASK_OPER(inst.oper); + i |= MASK_REG_DEST(inst.dest); + i |= MASK_REG_LEFT(inst.left); + i |= MASK_REG_RIGHT(inst.right); + + *dest = i; + return 1; +} +int generate_single_ni_type(uint32_t *dest, struct i_type inst) +{ + uint32_t i = 0; + + i |= MASK_INST_NITYPE; + i |= MASK_OPER(inst.oper); + i |= MASK_REG_DEST(inst.dest); + i |= MASK_REG_LEFT(inst.left); + i |= MASK_NI_IMM(inst.imm.value); + + *dest = i; + return 1; +} + +int generate_single_wi_type(uint32_t *dest, struct i_type inst) +{ + uint32_t i = 0; + + i |= MASK_INST_WITYPE; + i |= MASK_OPER(inst.oper); + i |= MASK_REG_DEST(inst.dest); + i |= MASK_REG_LEFT(inst.left); + + /* two-word instruction - make room for the immediate */ + i <<= 16; + + i |= inst.imm.value; + + *dest = i; + return 2; +} + +int generate_single_ji_type(uint32_t *dest, struct ji_type inst) +{ + uint32_t i = 0; + + i |= MASK_INST_JTYPE; + i |= MASK_IS_JUMP; + i |= MASK_JB_COND(inst.cond); + i |= MASK_JI; + + /* two-word instruction - make room for the immediate */ + i <<= 16; + + i |= inst.imm.value; + + *dest = i; + return 2; +} + +int generate_single_jr_type(uint32_t *dest, struct jr_type inst) +{ + uint32_t i = 0; + + i |= MASK_INST_JTYPE; + i |= MASK_IS_JUMP; + i |= MASK_JB_COND(inst.cond); + i |= MASK_JR; + i |= MASK_JUMP_REGISTER(inst.reg); + + *dest = i; + return 1; +} + +int generate_single_b_type(uint32_t *dest, struct b_type inst) +{ + uint32_t i = 0; + + i |= MASK_INST_JTYPE; + i |= MASK_IS_BRANCH; + i |= MASK_JB_COND(inst.cond); + i |= MASK_B_OFFSET(inst.imm.value); + + *dest = i; + return 1; +} + + +int look_up_label(struct label *labels, size_t labels_count, uint16_t *val, const char *label) +{ + size_t i = 0; + + for (i = 0; i < labels_count; i++) { + if (strcmp(labels[i].name, label) == 0) { + *val = labels[i].byte_offset; + return 0; + } + } + + /* FIXME emit */ + fprintf(stderr, "Reference to undefined label `%s'\n", label); + return 1; +} + +int output_single(FILE *f, struct label *labels, size_t labels_count, struct instruction inst) +{ + int len = 0; + uint32_t i = 0; + + switch (inst.type) { + case INST_TYPE_R: + len = generate_single_r_type(&i, inst.inst.r); + break; + case INST_TYPE_NI: + if ( inst.inst.i.imm_is_ident + && look_up_label(labels, labels_count, &inst.inst.i.imm.value, inst.inst.i.imm.label)) + return 1; + + len = generate_single_ni_type(&i, inst.inst.i); + break; + case INST_TYPE_WI: + if ( inst.inst.i.imm_is_ident + && look_up_label(labels, labels_count, &inst.inst.i.imm.value, inst.inst.i.imm.label)) + return 1; + + len = generate_single_wi_type(&i, inst.inst.i); + break; + case INST_TYPE_JR: + len = generate_single_jr_type(&i, inst.inst.jr); + break; + case INST_TYPE_JI: + if ( inst.inst.ji.imm_is_ident + && look_up_label(labels, labels_count, &inst.inst.ji.imm.value, inst.inst.ji.imm.label)) + return 1; + + len = generate_single_ji_type(&i, inst.inst.ji); + break; + case INST_TYPE_B: + if ( inst.inst.b.imm_is_ident + && look_up_label(labels, labels_count, &inst.inst.b.imm.value, inst.inst.b.imm.label)) + return 1; + inst.inst.b.imm.value -= cur_byte; + if (inst.inst.b.imm.value % 2 != 0) { + fprintf(stderr, "Internal error: branch offset %d not a multiple of 2\n", inst.inst.b.imm.value); + } + inst.inst.b.imm.value /= 2; + + len = generate_single_b_type(&i, inst.inst.b); + break; + default: + fprintf(stderr, "Internal error: unhandled instruction type\n"); + break; + } + + if (len == 2) { +#define RAW +#ifdef RAW + fputc(0xFF & (i >> 24), f); + fputc(0xFF & (i >> 16), f); +#else + fprintf(f, "%04x ", i >> 16); +#endif + } +#ifdef RAW + fputc(0xFF & (i >> 8), f); + fputc(0xFF & (i >> 0), f); +#else + fprintf(f, "%04x ", 0xFFFF & i); +#endif + + cur_byte += 2 * len; + return 0; +} + +int output_bin(FILE *fout, struct label *labels, size_t label_count, struct instruction *insts, size_t insts_count) +{ + size_t i = 0; + cur_byte = 0; + +#ifndef RAW + fprintf(fout, "v2.0 raw\n"); +#endif + + for (i = 0; i < insts_count; i++) + if (output_single(fout, labels, label_count, insts[i])) + return 1; + + return 0; +} diff --git a/output/output_bin.h b/output/output_bin.h new file mode 100644 index 0000000..d57326b --- /dev/null +++ b/output/output_bin.h @@ -0,0 +1,6 @@ +#ifndef OUTPUT_H +#define OUTPUT_H + +int output_bin(FILE *fout, struct label *labels, size_t label_count, struct instruction *insts, size_t insts_count); + +#endif /* OUTPUT_H */ |