diff options
| author | Freya Murphy <freya@freyacat.org> | 2024-10-21 12:27:18 -0400 |
|---|---|---|
| committer | Freya Murphy <freya@freyacat.org> | 2024-10-21 12:27:18 -0400 |
| commit | 37a4e740133f8e4d669cafc8468dd13107a4810a (patch) | |
| tree | 116b001142b5c0aea03ae46ef299f5fc220c4e5e /masm/gen | |
| parent | add mips1 and mips32r2 isa definitions (diff) | |
| download | mips-37a4e740133f8e4d669cafc8468dd13107a4810a.tar.gz mips-37a4e740133f8e4d669cafc8468dd13107a4810a.tar.bz2 mips-37a4e740133f8e4d669cafc8468dd13107a4810a.zip | |
save dev statedev
Diffstat (limited to 'masm/gen')
| -rw-r--r-- | masm/gen/grammer.c | 643 | ||||
| -rw-r--r-- | masm/gen/log.c | 28 | ||||
| -rw-r--r-- | masm/gen/section.c | 156 |
3 files changed, 827 insertions, 0 deletions
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 <strings.h> +#include <string.h> +#include <merror.h> + +#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; + } + } + + +} diff --git a/masm/gen/log.c b/masm/gen/log.c new file mode 100644 index 0000000..2df455b --- /dev/null +++ b/masm/gen/log.c @@ -0,0 +1,28 @@ +#include "../gen.h" + +void gen_output_expr(struct generator *gen, struct expr *expr) +{ + int line = expr->line_no, + len = expr->byte_end - expr->byte_start, + nl = true, + c = EOF; + FILE *file = gen->parser.lexer.file; + + fseek(file, expr->byte_start, SEEK_SET); + + while (len--) { + c = getc(file); + if (c == EOF || c == '\0') + break; + if (nl) { + fprintf(stderr, "\t%d | ", line); + line++; + nl = false; + } + if (c == '\n') + nl = true; + putc(c, stderr); + } + +} + diff --git a/masm/gen/section.c b/masm/gen/section.c new file mode 100644 index 0000000..44f83f8 --- /dev/null +++ b/masm/gen/section.c @@ -0,0 +1,156 @@ +#include "../gen.h" + +#include <strings.h> +#include <string.h> +#include <stdlib.h> +#include <merror.h> + +struct section_default { + char *name; + int name_len; + + bool read; + bool write; + bool execute; + int alignment; +}; + +#define SECTION_DEFAULTS_LEN 7 +#define MAPPING(name, ...) {name, sizeof(name), __VA_ARGS__} +static const struct section_default section_defaults[SECTION_DEFAULTS_LEN] = { + MAPPING(".text", true, false, true, 4), + MAPPING(".code", true, false, true, 4), + MAPPING(".data", true, true, false, 1), + MAPPING(".stack", true, true, false, 1), + MAPPING(".rodata", true, false, false, 1), + MAPPING(".bss", true, true, false, 1), + MAPPING(".robss", true, false, false, 1), +}; + +static void section_get_default_perm(struct section *sec, const char *name) +{ + for (int i = 0; i < SECTION_DEFAULTS_LEN; i++) { + const struct section_default *defaults = §ion_defaults[i]; + if (strncasecmp(name, defaults->name, defaults->name_len)) + continue; + sec->read = defaults->read; + sec->write = defaults->write; + sec->execute = defaults->execute; + sec->align = defaults->alignment; + break; + } +} + +int gen_get_section(struct generator *gen, struct section **res, + struct string *name) +{ + /// find the section if it exists + for (size_t i = 0; i < gen->sections_len; i++) { + struct section *sec = &gen->sections[i]; + if (sec->name.len != name->len) + continue; + if (strcmp(sec->name.str, name->str) != 0) + continue; + *res = sec; + return 0; + } + + /// allocate a new one if it doesnt + size_t size = gen->sections_size ? gen->sections_size * 2 : 8; + void *new = realloc(gen->sections, size * sizeof(struct section)); + if (new == NULL) { + PERROR("cannot realloc"); + return 1; + } + + gen->sections_size = size; + gen->sections = new; + + struct section *sec = &gen->sections[gen->sections_len++]; + if (section_init(sec, name)) + return 1; + + *res = sec; + return 0; +} + +int section_init(struct section *sec, struct string *name) +{ + sec->len = 0; + sec->size = 0; + sec->align = 1; + sec->data = NULL; + sec->read = true; + sec->write = true; + sec->execute = false; + + // set defaults + section_get_default_perm(sec, name->str); + + // alloc reftab + if (reftab_init(&sec->reftab)) + return 1; + + // copy name + if (string_clone(&sec->name, name)) + return 1; + + return 0; +} + +int section_extend(struct section *section, size_t space) +{ + size_t newlen = section->len + space; + if (newlen < section->size) + return M_SUCCESS; + + size_t size = section->size ? section->size * 2 + newlen : newlen * 2; + void *new = realloc(section->data, size); + if (new == NULL) { + PERROR("cannot realloc"); + return M_ERROR; + } + section->size = size; + section->data = new; + + return M_SUCCESS; +} + +int section_push(struct section *section, void *data, size_t len) +{ + size_t newlen = section->len + len; + size_t zeros = newlen % section->align; + if (zeros) + zeros = section->align - zeros; + + if (section_extend(section, len + zeros)) + return M_ERROR; + + memset(section->data + section->len, 0, zeros); + memcpy(section->data + section->len + zeros, data, len); + section->len += len + zeros; + + return M_SUCCESS; +} + +int section_zero(struct section *section, size_t len) +{ + size_t zeros = section->len % section->align; + if (zeros) + zeros = section->align - zeros; + + if (section_extend(section, len + zeros)) + return M_ERROR; + + memset(section->data + section->len, 0, len + zeros); + section->len += len + zeros; + + return M_SUCCESS; +} + +void section_free(struct section *section) +{ + reftab_free(§ion->reftab); + string_free(§ion->name); + free(section->data); +} |