diff --git a/masm/gen.c b/masm/gen.c index ba6960b..c4a15a0 100644 --- a/masm/gen.c +++ b/masm/gen.c @@ -1,7 +1,9 @@ #include #include #include -#include +#include +#include +#include #include #include "tab.h" @@ -263,30 +265,6 @@ static int gen_constant(struct generator *gen, struct expr_const *const expr) return M_ERROR; } -static enum grammer_type get_gmr_type(const char *name, size_t *len) -{ - #define CHK(part, str) { \ - if (strncasecmp(str, name, strlen(str)) == 0) { \ - *len = strlen(str); \ - return GMR_ ##part; \ - }} \ - - CHK(RD, "rd") - CHK(RS, "rs") - CHK(RT, "rt") - CHK(IMMD, "immd") - CHK(OFFSET_BASE, "offset(base)") - CHK(OFFSET, "offset") - CHK(TARGET, "target") - CHK(HI, "hi") - CHK(LO, "lo") - - #undef CHK - - ERROR("!!! BUG: this should never hit !!!"); - exit(1); -} - static int parse_register(enum mips32_register *reg, struct string *name) { int len = name->len; @@ -403,6 +381,141 @@ static int parse_register(enum mips32_register *reg, struct string *name) return M_ERROR; } +static int parse_fp_register(enum mips32_fp_register *reg, struct string *name) +{ + int len = name->len; + int c0 = len > 0 ? name->str[0] : '\0', + c1 = len > 1 ? name->str[1] : '\0', + c2 = len > 2 ? name->str[2] : '\0'; + + *reg = 0; + + if (c0 != 'f') + goto error; + + if (c1 < '0' || c1 > '9') + goto error; + + *reg += c1 - '0'; + + if (c1 == '\0') + return M_SUCCESS; + + if (c2 < '0' || c2 > '9') + goto error; + + *reg *= 10; + *reg += c2 - '0'; + + return M_SUCCESS; + +error: + ERROR("unknown fp register $%.*s", name->len, name->str); + return M_ERROR; + +} + +static enum grammer_type get_gmr_type(const char *name, size_t *len) +{ + #define CHK(part, str) { \ + if (strncasecmp(str, name, strlen(str)) == 0) { \ + *len = strlen(str); \ + return GMR_ ##part; \ + }} \ + + CHK(RD, "rd") + CHK(RS, "rs") + CHK(RT, "rt") + CHK(FS, "fs") + CHK(FT, "ft") + CHK(FD, "fd") + CHK(IMMD, "immd") + CHK(CC, "cc") + CHK(CODE, "code") + CHK(POS, "pos") + CHK(SIZE, "size") + CHK(HB, "hb") + CHK(HINT, "hint") + CHK(OFFSET_BASE, "offset(base)") + CHK(INDEX_BASE, "index(base)") + CHK(OFFSET, "offset") + CHK(TARGET, "target") + CHK(HI, "hi") + CHK(LO, "lo") + + #undef CHK + + BUG("invalid grammer key: %s", name); + exit(1); +} + +static int get_gmr_hc(struct gen_ins_state *state, + struct gen_ins_override *over, + char *value) +{ + int vlen = 0; + int res = M_SUCCESS; + + /* get length of value */ + for (const char *ptr = value; + *ptr != '\0' && *ptr != ','; + ptr++, vlen++); + + /* must be at least of length 1 */ + if (vlen < 1) + return M_ERROR; + + #define VAL(v) if (strncmp(v, value, vlen) == 0) + /* register to register mapping */ + VAL("rd") + over->reg = state->rd; + else VAL("rs") + over->reg = state->rs; + else VAL("rt") + { + over->reg = state->rt; + } + else VAL("fs") + over->fpreg = state->fs; + else VAL("ft") + over->fpreg = state->ft; + else VAL("fd") + over->fpreg = state->fd; + else VAL("immd") + over->immd = state->immd; + else VAL("-immd") + over->immd = -state->immd; + /* hardcoded register */ + else if (*value == '$') { + // register + if (vlen < 2) + return M_ERROR; + struct string name; + name.str = value + 1; + name.len = vlen - 1; + if (*name.str == 'f') + res = parse_fp_register(&over->fpreg, &name); + else + res = parse_register(&over->reg, &name); + /* hardcoded immediate */ + } else { + // immediate + char c; + int immd = 0; + while (c = *(value++), c != ',' && c != '\0') { + if (c < '0' || c > '9') + return M_ERROR; + immd *= 10; + immd += c - '0'; + } + over->immd = immd; + } + + #undef KEY + + return res; +} + static int gen_ins_read_state(struct generator *gen, struct expr *const expr, struct gen_ins_state *state, @@ -459,6 +572,42 @@ static int gen_ins_read_state(struct generator *gen, return M_ERROR; } break; + case GMR_FS: + // fs + if (arg->type != EXPR_INS_ARG_REGISTER) { + ERROR("expected a register"); + print_curr_line(gen, expr); + return M_ERROR; + } + if (parse_fp_register(&state->fs, &arg->reg)) { + print_curr_line(gen, expr); + return M_ERROR; + } + break; + case GMR_FT: + // ft + if (arg->type != EXPR_INS_ARG_REGISTER) { + ERROR("expected a register"); + print_curr_line(gen, expr); + return M_ERROR; + } + if (parse_fp_register(&state->ft, &arg->reg)) { + print_curr_line(gen, expr); + return M_ERROR; + } + break; + case GMR_FD: + // fd + if (arg->type != EXPR_INS_ARG_REGISTER) { + ERROR("expected a register"); + print_curr_line(gen, expr); + return M_ERROR; + } + if (parse_fp_register(&state->fd, &arg->reg)) { + print_curr_line(gen, expr); + return M_ERROR; + } + break; case GMR_IMMD: // immd if (arg->type != EXPR_INS_ARG_IMMEDIATE) { @@ -468,6 +617,61 @@ static int gen_ins_read_state(struct generator *gen, } state->immd = arg->immd; break; + case GMR_CC: + // cc + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + print_curr_line(gen, expr); + return M_ERROR; + } + state->cc = arg->immd; + break; + case GMR_CODE: + // code + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + print_curr_line(gen, expr); + return M_ERROR; + } + state->code = arg->immd; + break; + case GMR_POS: + // pos + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + print_curr_line(gen, expr); + return M_ERROR; + } + state->pos = arg->immd; + break; + case GMR_SIZE: + // size + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + print_curr_line(gen, expr); + return M_ERROR; + } + // TODO: check valid size + state->size = arg->immd; + break; + case GMR_HB: + // hb + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + print_curr_line(gen, expr); + return M_ERROR; + } + state->hb = !!(arg->immd); + break; + case GMR_HINT: + // hint + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + print_curr_line(gen, expr); + return M_ERROR; + } + state->hint = arg-> immd; + break; case GMR_OFFSET: // offset state->offset = 0; @@ -494,6 +698,19 @@ static int gen_ins_read_state(struct generator *gen, return M_ERROR; } break; + case GMR_INDEX_BASE: + // index(base) + if (arg->type != EXPR_INS_ARG_OFFSET) { + ERROR("expected an index($base)"); + print_curr_line(gen, expr); + return M_ERROR; + } + state->index = arg->offset.immd; + if (parse_register(&state->base, &arg->offset.reg)) { + print_curr_line(gen, expr); + return M_ERROR; + } + break; case GMR_TARGET: // target state->target = 0; @@ -521,7 +738,7 @@ static int gen_ins_read_state(struct generator *gen, } else if (*ptr == '\0') { break; } else { - ERROR("!! BUG3: invalid splitting char %c !!!", *ptr); + BUG("invalid grammer '%s'", grammer); exit(1); } @@ -536,27 +753,31 @@ static int gen_ins_write_state( struct gen_ins_state *state, // the current read state char *grammer) // the gramemr to parse { + // grammer pointer char *ptr = grammer; + + // new reference type if needed enum reference_type reftype = REF_NONE; + // hardcoded + struct gen_ins_override hstate; + bool hc = false; + // read values into state while (*ptr != '\0') { - // parse next dsl entry size_t skip; enum grammer_type gmr = get_gmr_type(ptr, &skip); // check for dsl hardcoded register argument - bool hardcoded = false; - enum mips32_register hard_reg; + hc = false; if (*(ptr + skip) == '=') { - // parse argument - char *rptr = ptr + skip + 2; - hardcoded = true; - struct string regname; - string_bss(®name, rptr); - if (parse_register(&hard_reg, ®name)) { - ERROR("!!! BUG2: this should never hit !!!"); + // get value pointer + char *value = ptr + skip + 1; + hc = true; + // parse value + if (get_gmr_hc(state, &hstate, value)) { + BUG("invalid grammer: %s", grammer); exit(1); } } @@ -568,16 +789,43 @@ static int gen_ins_write_state( switch (gmr) { case GMR_RD: - ins.rd = hardcoded ? hard_reg : state->rd; + ins.rd = hc ? hstate.reg : state->rd; break; case GMR_RS: - ins.rs = hardcoded ? hard_reg : state->rs; + ins.rs = hc ? hstate.reg : state->rs; break; case GMR_RT: - ins.rt = hardcoded ? hard_reg : state->rt; + ins.rt = hc ? hstate.reg : state->rt; + break; + case GMR_FS: + ins.fs = hc ? hstate.fpreg : state->fs; + break; + case GMR_FT: + ins.ft = hc ? hstate.fpreg : state->ft; + break; + case GMR_FD: + ins.fd = hc ? hstate.fpreg : state->fd; break; case GMR_IMMD: - ins.immd = state->immd; + ins.immd = hc ? hstate.immd : state->immd; + break; + case GMR_CC: + ins.cc = state->cc; + break; + case GMR_CODE: + ins.code = state->code; + break; + case GMR_POS: + ins.shamt = state->pos; + break; + case GMR_SIZE: + ins.rd = state->size ? state->size - 1 : 0; + break; + case GMR_HB: + ins.hb = hc ? hstate.immd : state->hb; + break; + case GMR_HINT: + ins.rt = state->hint; break; case GMR_OFFSET: ins.offset = state->offset; @@ -588,6 +836,10 @@ static int gen_ins_write_state( ins.rs = state->base; reftype = REF_MIPS_16; break; + case GMR_INDEX_BASE: + ins.rt = state->index; + ins.rs = state->base; + break; case GMR_TARGET: ins.target = state->target; reftype = REF_MIPS_26; @@ -600,8 +852,9 @@ static int gen_ins_write_state( ins.immd = state->target & 0x0000FFFF; reftype = REF_MIPS_LO16; break; - } - } + break; + } + } // get offset for reference (if needed) uint32_t offset = gen->current->len; @@ -721,8 +974,8 @@ static int gen_label(struct generator *gen, struct string *const label) return M_SUCCESS; } -/* run codegen */ -static int generate(struct generator *gen) +/* run codegen for next expression */ +static int generate_next(struct generator *gen) { struct expr expr; int res = M_SUCCESS; @@ -771,16 +1024,10 @@ static int generate(struct generator *gen) return res; } -/* run codegen with the mips32r6 specification */ -int generate_mips32r6(struct generator *gen) +static int generate(struct generator *gen) { - gen->instructions_len = __MIPS32R6_INS_LEN; - gen->instructions = mips32r6_instructions; - gen->grammers_len = __MIPS32R6_GRAMMER_LEN; - gen->grammers = mips32r6_grammers; - int res; - while (res = generate(gen), 1) { + while (res = generate_next(gen), 1) { if (res == M_ERROR) return M_ERROR; if (res == M_EOF) @@ -790,6 +1037,36 @@ int generate_mips32r6(struct generator *gen) return M_SUCCESS; } +/* run codegen with the mips32r6 specification */ +int generate_mips32r6(struct generator *gen) +{ + gen->instructions_len = __MIPS32R6_INS_LEN; + gen->instructions = mips32r6_instructions; + gen->grammers_len = __MIPS32R6_GRAMMER_LEN; + gen->grammers = mips32r6_grammers; + return generate(gen); +} + +/* run codegen with the mips32r2 specification */ +int generate_mips32r2(struct generator *gen) +{ + gen->instructions_len = __MIPS32R2_INS_LEN; + gen->instructions = mips32r2_instructions; + gen->grammers_len = __MIPS32R2_GRAMMER_LEN; + gen->grammers = mips32r2_grammers; + return generate(gen); +} + +/* run codegen with the mips32r6 specification */ +int generate_mips1(struct generator *gen) +{ + gen->instructions_len = __MIPS1_INS_LEN; + gen->instructions = mips1_instructions; + gen->grammers_len = __MIPS1_GRAMMER_LEN; + gen->grammers = mips1_grammers; + return generate(gen); +} + int generator_init(const char *file, struct generator *gen) { if (parser_init(file, &gen->parser)) diff --git a/masm/gen.h b/masm/gen.h index 19f575c..42fbf50 100644 --- a/masm/gen.h +++ b/masm/gen.h @@ -4,7 +4,7 @@ #define __GEN_H__ #include -#include +#include #include #include "parse.h" @@ -44,16 +44,42 @@ void section_free(struct section *section); /// struct gen_ins_state { - // rd,rst,rt + // rd,rs,rt enum mips32_register rd; enum mips32_register rs; enum mips32_register rt; + // fs,ft + enum mips32_fp_register fs; + enum mips32_fp_register ft; + enum mips32_fp_register fd; + // immd - uint16_t immd; + uint16_t immd; // 16 bit + + // cc + uint16_t cc; // 3 bit + + // code + uint32_t code; // 5 bit + + // pos + uint32_t pos; // 5 bit + + // size + uint32_t size; // 5 bit - 1 + + // hb + bool hb; // 1 bit - 1 + + // index + uint32_t index; + + // hint + uint32_t hint; // offset(base) - uint16_t offset; + uint16_t offset; // 16 bit enum mips32_register base; // target @@ -63,15 +89,35 @@ struct gen_ins_state { struct string *label; }; +struct gen_ins_override { + enum mips32_register reg; + enum mips32_fp_register fpreg; + uint32_t immd; +}; + /// /// grammer type /// enum grammer_type { + // registers GMR_RD, GMR_RS, GMR_RT, + GMR_INDEX_BASE, + // fp registers + GMR_FS, + GMR_FT, + GMR_FD, + // numeric fields GMR_IMMD, + GMR_CC, + GMR_CODE, + GMR_POS, + GMR_SIZE, + GMR_HB, + GMR_HINT, + // addresses GMR_OFFSET, GMR_OFFSET_BASE, GMR_TARGET, @@ -108,6 +154,10 @@ struct generator { /* generate the input as mips32r6 */ int generate_mips32r6(struct generator *gen); +/* run codegen with the mips32r2 specification */ +int generate_mips32r2(struct generator *gen); +/* run codegen with the mips32r6 specification */ +int generate_mips1(struct generator *gen); /* initalize a generator */ int generator_init(const char *file, struct generator *gen);