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 | |
| parent | add mips1 and mips32r2 isa definitions (diff) | |
| download | mips-dev.tar.gz mips-dev.tar.bz2 mips-dev.zip | |
save dev statedev
Diffstat (limited to 'masm')
| -rw-r--r-- | masm/gen.c | 661 | ||||
| -rw-r--r-- | masm/gen.h | 93 | ||||
| -rw-r--r-- | masm/gen/grammer.c | 643 | ||||
| -rw-r--r-- | masm/gen/log.c | 28 | ||||
| -rw-r--r-- | masm/gen/section.c | 156 | ||||
| -rw-r--r-- | masm/tab/reftab.c (renamed from masm/reftab.c) | 2 | ||||
| -rw-r--r-- | masm/tab/symtab.c (renamed from masm/symtab.c) | 3 |
7 files changed, 910 insertions, 676 deletions
@@ -11,178 +11,9 @@ #include "parse.h" /// -/// section table -/// - -static void section_get_default_perm(struct section *sec, const char *name) -{ - #define __LEN 7 - static const struct perms { - char *name; - bool read; - bool write; - bool execute; - int alignment; - } defaults[__LEN] = { - {".text", true, false, true, 4}, - {".code", true, false, true, 4}, - {".data", true, true, false, 1}, - {".stack", true, true, false, 1}, - {".rodata", true, false, false, 1}, - {".bss", true, true, false, 1}, - {".robss", true, false, false, 1}, - }; - - for (int i = 0; i < __LEN; i++) { - const struct perms *p = &defaults[i]; - if (strcasecmp(name, p->name) != 0) - continue; - sec->read = p->read; - sec->write = p->write; - sec->execute = p->execute; - sec->align = p->alignment; - break; - } - -} - -static int section_get(struct generator *gen, struct section **res, - const struct string *const 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 M_SUCCESS; - } - - /// 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 M_ERROR; - } - - gen->sections_size = size; - gen->sections = new; - - struct section *sec = &gen->sections[gen->sections_len++]; - - // alloc reftab - if (reftab_init(&sec->reftab)) - return M_ERROR; - - // copy name - if (string_clone(&sec->name, name)) - return M_ERROR; - - // set defaults - sec->len = 0; - sec->size = 0; - sec->align = 1; - sec->data = NULL; - sec->read = true; - sec->write = true; - sec->execute = false; - section_get_default_perm(sec, name->str); - - *res = sec; - return M_SUCCESS; -} - -static 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; -} - -static 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; -} - -static 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); -} - -/// /// generation functions /// -static void print_curr_line(struct generator *gen, - const struct expr *const 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); - } - -} - static int gen_directive_whb(struct generator *gen, const void *data, uint32_t count, uint32_t len) { @@ -265,488 +96,6 @@ static int gen_constant(struct generator *gen, struct expr_const *const expr) return M_ERROR; } -static int 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 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, - struct mips32_grammer *grammer) -{ - char *ptr = grammer->grammer; - uint32_t argi = 0; - - // read values into state - while (*ptr != '\0') { - - if (argi >= expr->instruction.args_len) { - ERROR("not enough arguments passed"); - print_curr_line(gen, expr); - return M_ERROR; - } - struct expr_ins_arg *arg = &expr->instruction.args[argi++]; - - size_t skip; - switch (get_gmr_type(ptr, &skip)) { - case GMR_RD: - // rd - if (arg->type != EXPR_INS_ARG_REGISTER) { - ERROR("expected a register"); - print_curr_line(gen, expr); - return M_ERROR; - } - if (parse_register(&state->rd, &arg->reg)) { - print_curr_line(gen, expr); - return M_ERROR; - } - break; - case GMR_RS: - // rs - if (arg->type != EXPR_INS_ARG_REGISTER) { - ERROR("expected a register"); - print_curr_line(gen, expr); - return M_ERROR; - } - if (parse_register(&state->rs, &arg->reg)) { - print_curr_line(gen, expr); - return M_ERROR; - } - break; - case GMR_RT: - // rt - if (arg->type != EXPR_INS_ARG_REGISTER) { - ERROR("expected a register"); - print_curr_line(gen, expr); - return M_ERROR; - } - if (parse_register(&state->rt, &arg->reg)) { - print_curr_line(gen, expr); - 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) { - ERROR("expected an immediate"); - print_curr_line(gen, expr); - return M_ERROR; - } - 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; - 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"); - print_curr_line(gen, expr); - return M_ERROR; - } - break; - case GMR_OFFSET_BASE: - // offset(base) - if (arg->type != EXPR_INS_ARG_OFFSET) { - ERROR("expected an offset($base)"); - print_curr_line(gen, expr); - return M_ERROR; - } - state->offset = arg->offset.immd; - if (parse_register(&state->base, &arg->offset.reg)) { - print_curr_line(gen, expr); - 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; - 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"); - print_curr_line(gen, expr); - return M_ERROR; - } - break; - default: - break; - } - - // skip entry - ptr += skip; - - // skip comma - if (*ptr == ',') { - ptr++; - continue; - } else if (*ptr == '\0') { - break; - } else { - BUG("invalid grammer '%s'", grammer); - exit(1); - } - - } - - return M_SUCCESS; -} - static int gen_ins_write_state( struct generator *gen, union mips32_instruction ins, // the instruction to modify @@ -1037,6 +386,12 @@ static int generate(struct generator *gen) return M_SUCCESS; } +// +// the following functions set default generator +// state values for different versions of the mips +// isa +// + /* run codegen with the mips32r6 specification */ int generate_mips32r6(struct generator *gen) { @@ -1067,6 +422,10 @@ int generate_mips1(struct generator *gen) return generate(gen); } +// +// constructors and deconstructors +// + int generator_init(const char *file, struct generator *gen) { if (parser_init(file, &gen->parser)) @@ -37,8 +37,26 @@ struct section { struct reference_table reftab; }; +/* get a section from the generator by name, and return it into res. if the + * section does not exist, one will be created. */ +int gen_get_section(struct generator *gen, struct section **res, + struct string *name); + +/* initalize a section */ +int section_init(struct section *section, struct string *name); + +/* free a section */ void section_free(struct section *section); +/* extend a section by space bytes plus alignment */ +int section_extend(struct section *section, size_t space); + +/* push data into a section */ +int section_push(struct section *section, void *data, size_t len); + +/* push zeros (empty space) to a section */ +int section_zero(struct section *section, size_t len); + /// /// instruction generation state /// @@ -55,36 +73,35 @@ struct gen_ins_state { enum mips32_fp_register fd; // immd - uint16_t immd; // 16 bit + uint16_t immd; // cc - uint16_t cc; // 3 bit + uint16_t cc; // code - uint32_t code; // 5 bit + uint32_t code; // pos - uint32_t pos; // 5 bit + uint32_t pos; // size - uint32_t size; // 5 bit - 1 - - // hb - bool hb; // 1 bit - 1 - - // index - uint32_t index; + uint32_t size; // hint uint32_t hint; - // offset(base) - uint16_t offset; // 16 bit - enum mips32_register base; + // hazard barrier + bool hb; // 1 bit - 1 // target uint32_t target; + // index(base) + // offset(base) + uint32_t index; + uint16_t offset; + enum mips32_register base; + // current referencd label struct string *label; }; @@ -95,16 +112,11 @@ struct gen_ins_override { uint32_t immd; }; -/// -/// grammer type -/// - enum grammer_type { // registers GMR_RD, GMR_RS, GMR_RT, - GMR_INDEX_BASE, // fp registers GMR_FS, GMR_FT, @@ -118,13 +130,47 @@ enum grammer_type { GMR_HB, GMR_HINT, // addresses - GMR_OFFSET, - GMR_OFFSET_BASE, - GMR_TARGET, GMR_HI, GMR_LO, + GMR_TARGET, + GMR_OFFSET, + GMR_INDEX_BASE, + GMR_OFFSET_BASE, + // len + __GMR_LEN }; +/* 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); + +/* Parses a register name, returing 0 on success, 1 on error*/ +int gen_parse_register(enum mips32_register *reg, struct string *name); + +/* 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); + +/* Parses the overide expression (after the =) in the dsl for the grammer. + * returns the number of characters consumed, or -1 on error. */ +int gen_parse_grammer_overide(struct gen_ins_state *state, + struct gen_ins_override *over, char *value); + +/* Given a grammer for an instruction, read all args as values into the + * instruction generator state. */ +int gen_read_grammer_state(struct generator *gen, + struct expr *const expr, + struct gen_ins_state *state, + struct mips32_grammer *grammer); + +/* Given a grammer for an instruction, and a read state, output multiple + * instructions into the current section in the generator. note: + * this write_grammer is different from the read grammer such that + * it supports paramater reassignment and overides. */ +int gen_write_grammer_state(struct generator *gen, + struct gen_ins_state *state, + char *write_grammer); + /// /// generates assembley /// from a parser stream @@ -152,6 +198,9 @@ struct generator { struct symbol_table symtab; }; +/* output the source code lines for a provided expression */ +void gen_output_expr(struct generator *gen, struct expr *expr); + /* generate the input as mips32r6 */ int generate_mips32r6(struct generator *gen); /* run codegen with the mips32r2 specification */ 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); +} diff --git a/masm/reftab.c b/masm/tab/reftab.c index f8793e1..3eddc50 100644 --- a/masm/reftab.c +++ b/masm/tab/reftab.c @@ -1,7 +1,7 @@ #include <stdlib.h> #include <merror.h> -#include "tab.h" +#include "../tab.h" #define REFTAB_INIT_LEN 8 diff --git a/masm/symtab.c b/masm/tab/symtab.c index 990be46..a2aa1ea 100644 --- a/masm/symtab.c +++ b/masm/tab/symtab.c @@ -5,8 +5,7 @@ #include <stdlib.h> #include <string.h> -#include "lex.h" -#include "tab.h" +#include "../tab.h" #define SYMTBL_INIT_LEN 24 |