From 37a4e740133f8e4d669cafc8468dd13107a4810a Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 21 Oct 2024 12:27:18 -0400 Subject: save dev state --- masm/gen/grammer.c | 643 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 643 insertions(+) create mode 100644 masm/gen/grammer.c (limited to 'masm/gen/grammer.c') diff --git a/masm/gen/grammer.c b/masm/gen/grammer.c new file mode 100644 index 0000000..d7327da --- /dev/null +++ b/masm/gen/grammer.c @@ -0,0 +1,643 @@ +#include +#include +#include + +#include "../gen.h" +#include "mips.h" + +struct grammer_mapping { + char *name; + int name_len; + enum grammer_type type; +}; + +#define MAPPING(name, enum) {name, sizeof(name), GMR_ ##enum} + +static const struct grammer_mapping grammer_mappings[__GMR_LEN] = { + // registers + MAPPING("rd", RD), + MAPPING("rs", RS), + MAPPING("rt", RT), + // fp registers + MAPPING("fs", FS), + MAPPING("ft", FT), + MAPPING("fd", FD), + // numberic fileds + MAPPING("immd", IMMD), + MAPPING("cc", CC), + MAPPING("code", CODE), + MAPPING("pos", POS), + MAPPING("size", SIZE), + MAPPING("hb", HB), + MAPPING("hint", HINT), + // addresses + MAPPING("hi", HI), + MAPPING("lo", LO), + MAPPING("target", TARGET), + MAPPING("offset", OFFSET), + MAPPING("offset(base)", OFFSET_BASE), + MAPPING("index(base)", INDEX_BASE) +}; + +/* Parses the input string and matches it to a grammer type. Returns + * the number of characters consumed, or -1 on error. + */ +int gen_parse_grammer_type(const char *name, enum grammer_type *res) +{ + for (int i = 0; i < __GMR_LEN; i++) { + const struct grammer_mapping *mapping = &grammer_mappings[i]; + if (strncasecmp(name, mapping->name, mapping->name_len) != 0) + continue; + if (res != NULL) + *res = mapping->type; + return mapping->name_len; + } + + return -1; +} + +/* Parses a register name, returing 0 on success, 1 on error*/ +int gen_parse_register(enum mips32_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', + c3 = len > 3 ? name->str[3] : '\0'; + + // $zero + if (c0 == 'z') { + if (c1 == 'e' && c2 == 'r' && c3 == 'o') { + *reg = MIPS32_REG_ZERO; + return M_SUCCESS; + } + } + + // $a0-a3 $at + else if (c0 == 'a') { + if (c1 == 't') { + *reg = MIPS32_REG_AT; + return M_SUCCESS; + } + if (c1 >= '0' && c1 <= '3') { + *reg = MIPS32_REG_A0; + *reg += c1 - '0'; + return M_SUCCESS; + } + } + + // $v0-v1 + else if (c0 == 'v') { + if (c1 >= '0' && c1 <= '1') { + *reg = MIPS32_REG_V0; + *reg += c1 - '0'; + return M_SUCCESS; + } + } + + // $t0-t9 + else if (c0 == 't') { + if (c1 >= '0' && c1 <= '7') { + *reg = MIPS32_REG_T0; + *reg += c1 - '0'; + return M_SUCCESS; + } + // reg T8-T9 are not in order with T0-T7 + if (c1 >= '8' && c1 <= '9') { + *reg = MIPS32_REG_T8; + *reg += c1 - '8'; + return M_SUCCESS; + } + } + + // $s0-s7 $sp + else if (c0 == 's') { + if (c1 >= '0' && c1 <= '7') { + *reg = MIPS32_REG_S0; + *reg += c1 - '0'; + return M_SUCCESS; + } + if (c1 == 'p') { + *reg = MIPS32_REG_SP; + return M_SUCCESS; + } + } + + // $k0-k1 + else if (c0 == 'k') { + if (c1 >= '0' && c1 <= '1') { + *reg = MIPS32_REG_K0; + *reg += c1 - '0'; + return M_SUCCESS; + } + } + + // $gp + else if (c0 == 'g') { + if (c1 == 'p') { + *reg = MIPS32_REG_GP; + return M_SUCCESS; + } + } + + // $fp + else if (c0 == 'f') { + if (c1 == 'p') { + *reg = MIPS32_REG_FP; + return M_SUCCESS; + } + } + + // $rp + else if (c0 == 'r') { + if (c1 == 'a') { + *reg = MIPS32_REG_RA; + return M_SUCCESS; + } + } + + // $0-31 (non aliased register names) + else if (c0 >= '0' && c0 <= '9') { + int i = c0 - '0'; + if (c1 >= '0' && c1 <= '9') { + i *= 10; + i += c1 - '0'; + } + if (i <= 31) { + *reg = i; + return M_SUCCESS; + } + } + + ERROR("unknown register $%.*s", name->len, name->str); + return 1; +} + +/* Parses a floating point register name, returing 0 on success, 1 on error*/ +int gen_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 1; + +} + +/* convert string to number with int len max length */ +static int antoi(char *str, int len) +{ + char c; + int num = 0; + + while (c = *str++, len--) { + if (c < '0' || c > '9') + break; + num *= 10; + num += c - '0'; + } + + return num; +} + +/* Parses the override expression (after the =) in the dsl for the grammer. + * returns the number of characters consumed, or -1 on error. */ +int gen_parse_grammer_override(struct gen_ins_state *state, + struct gen_ins_override *over, char *value) +{ + int value_len = 0; + + /* get length of value */ + for (const char *ptr = value; + *ptr != '\0' && *ptr != ','; + ptr++, value_len++); + + // rd + if (strncmp("rd", value, value_len)) + over->reg = state->rd; + // rs + else if (strncmp("rs", value, value_len)) + over->reg = state->rs; + // rt + else if (strncmp("rt", value, value_len)) + over->reg = state->rt; + + // fd + else if (strncmp("fd", value, value_len)) + over->fpreg = state->fd; + // fs + else if (strncmp("fs", value, value_len)) + over->fpreg = state->fs; + // ft + else if (strncmp("ft", value, value_len)) + over->fpreg = state->ft; + + // immd + else if (strncmp("immd", value, value_len)) + over->immd = state->immd; + // -immd + else if (strncmp("-immd", value, value_len)) + over->immd = -state->immd; + + // floating point register + else if (value_len > 2 && value[0] == '$' && value[1] == 'f') { + struct string temp = { + .str = value + 1, + .len = value_len - 1 + }; + if (gen_parse_fp_register(&over->fpreg, &temp)) + return -1; + } + + // register + else if (value_len > 1 && value[0] == '$') { + struct string temp = { + .str = value + 1, + .len = value_len - 1 + }; + if (gen_parse_register(&over->reg, &temp)) + return -1; + } + + // number + else + over->immd = antoi(value, value_len); + + return value_len; +} + +static int read_next_state(struct expr_ins_arg *arg, + struct gen_ins_state *state, + enum grammer_type type) +{ + switch (type) { + case GMR_RD: + // rd + if (arg->type != EXPR_INS_ARG_REGISTER) { + ERROR("expected a register"); + return 1; + } + if (gen_parse_register(&state->rd, &arg->reg)) + return 1; + break; + case GMR_RS: + // rs + if (arg->type != EXPR_INS_ARG_REGISTER) { + ERROR("expected a register"); + return 1; + } + if (gen_parse_register(&state->rs, &arg->reg)) + return 1; + break; + case GMR_RT: + // rt + if (arg->type != EXPR_INS_ARG_REGISTER) { + ERROR("expected a register"); + return 1; + } + if (gen_parse_register(&state->rt, &arg->reg)) + return 1; + break; + case GMR_FS: + // fs + if (arg->type != EXPR_INS_ARG_REGISTER) { + ERROR("expected a register"); + return 1; + } + if (gen_parse_fp_register(&state->fs, &arg->reg)) + return 1; + break; + case GMR_FT: + // ft + if (arg->type != EXPR_INS_ARG_REGISTER) { + ERROR("expected a register"); + return 1; + } + if (gen_parse_fp_register(&state->ft, &arg->reg)) + return 1; + break; + case GMR_FD: + // fd + if (arg->type != EXPR_INS_ARG_REGISTER) { + ERROR("expected a register"); + return 1; + } + if (gen_parse_fp_register(&state->fd, &arg->reg)) + return 1; + break; + case GMR_IMMD: + // immd + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + return 1; + } + state->immd = arg->immd; + break; + case GMR_CC: + // cc + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + return 1; + } + state->cc = arg->immd; + break; + case GMR_CODE: + // code + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + return 1; + } + state->code = arg->immd; + break; + case GMR_POS: + // pos + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + return 1; + } + state->pos = arg->immd; + break; + case GMR_SIZE: + // size + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + return 1; + } + // TODO: check valid size + state->size = arg->immd; + break; + case GMR_HB: + // hb + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + return 1; + } + state->hb = !!(arg->immd); + break; + case GMR_HINT: + // hint + if (arg->type != EXPR_INS_ARG_IMMEDIATE) { + ERROR("expected an immediate"); + return 1; + } + state->hint = arg-> immd; + break; + case GMR_OFFSET: + // offset + state->offset = 0; + if (arg->type == EXPR_INS_ARG_IMMEDIATE) + state->offset = arg->immd; + else if (arg->type == EXPR_INS_ARG_LABEL) + state->label = &arg->label; + else { + ERROR("invalid instruction"); + return 1; + } + break; + case GMR_OFFSET_BASE: + // offset(base) + if (arg->type != EXPR_INS_ARG_OFFSET) { + ERROR("expected an offset($base)"); + return 1; + } + state->offset = arg->offset.immd; + if (gen_parse_register(&state->base, &arg->offset.reg)) + return 1; + break; + case GMR_INDEX_BASE: + // index(base) + if (arg->type != EXPR_INS_ARG_OFFSET) { + ERROR("expected an index($base)"); + return 1; + } + state->index = arg->offset.immd; + if (gen_parse_register(&state->base, &arg->offset.reg)) + return 1; + break; + case GMR_TARGET: + // target + state->target = 0; + if (arg->type == EXPR_INS_ARG_IMMEDIATE) + state->target = arg->immd; + else if (arg->type == EXPR_INS_ARG_LABEL) + state->label = &arg->label; + else { + ERROR("invalid instruction"); + return 1; + } + break; + default: + break; + } + + return 0; +} + +int gen_read_grammer_state(struct generator *gen, + struct expr *const expr, + struct gen_ins_state *state, + struct mips32_grammer *grammer) +{ + + char *ptr = grammer->grammer; + uint32_t argi = 0; + + // read values into state + while (*ptr != '\0') { + struct expr_ins_arg *arg; + enum grammer_type type; + size_t consumed; + + if (argi >= expr->instruction.args_len) { + ERROR("not enough arguments passed"); + gen_output_expr(gen, expr); + return 1; + } + + arg = &expr->instruction.args[argi++]; + consumed = gen_parse_grammer_type(ptr, &type); + + if (consumed < 0) { + BUG("invalid grammer: %s", grammer); + return 1; + } + + if (read_next_state(arg, state, type)) { + gen_output_expr(gen, expr); + return 1; + } + + ptr += consumed; + + if (*ptr == ',') { + ptr++; + continue; + } + + if (*ptr != '\0') { + BUG("invalid grammer: %s", grammer); + return 1; + } + } + + return 0; +} + +static int write_next_state(struct gen_ins_state *state, + struct gen_ins_override *over, + union mips32_instruction *ins, + enum reference_type *reftype, + char *ptr) +{ + enum grammer_type type; + size_t consumed; + bool hc = false; + + consumed = gen_parse_grammer_type(ptr, &type); + + if (consumed < 0) { + BUG("invalid grammer: %s", ptr); + return -1; + } + + if (*(ptr + consumed) == '=') { + hc = true; + consumed += gen_parse_grammer_override(state, over, ptr); + + if (consumed < 0) { + BUG("invalid grammer: %s", ptr); + return -1; + } + } + + switch (type) { + case GMR_RD: + ins->rd = hc ? over->reg : state->rd; + break; + case GMR_RS: + ins->rs = hc ? over->reg : state->rs; + break; + case GMR_RT: + ins->rt = hc ? over->reg : state->rt; + break; + case GMR_FS: + ins->fs = hc ? over->fpreg : state->fs; + break; + case GMR_FT: + ins->ft = hc ? over->fpreg : state->ft; + break; + case GMR_FD: + ins->fd = hc ? over->fpreg : state->fd; + break; + case GMR_IMMD: + ins->immd = hc ? over->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 ? over->immd : state->hb; + break; + case GMR_HINT: + ins->rt = state->hint; + break; + case GMR_OFFSET: + ins->offset = state->offset; + *reftype = REF_MIPS_PC16; + break; + case GMR_OFFSET_BASE: + ins->offset = state->offset; + 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; + break; + case GMR_HI: + ins->immd = state->target >> 16; + *reftype = REF_MIPS_HI16; + break; + case GMR_LO: + ins->immd = state->target & 0x0000FFFF; + *reftype = REF_MIPS_LO16; + break; + default: + break; + } + + return consumed; +} + + +int gen_write_grammer_state(struct generator *gen, + struct gen_ins_state *state, + char *grammer) +{ + enum reference_type reftype = REF_NONE; + struct gen_ins_override over; + char *ptr = grammer; + + union mips32_instruction ins; + + while (*ptr != '\0') { + int consumed; + + consumed = write_next_state(state, &over, + &ins, &reftype, ptr); + + if (consumed < 0) + return 1; + + ptr += consumed; + + if (*ptr == ',') { + ptr++; + continue; + } + + if (*ptr != '\0') { + BUG("invalid grammer: %s", grammer); + return 1; + } + } + + +} -- cgit v1.2.3-freya