summaryrefslogtreecommitdiff
path: root/masm/gen
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2024-10-21 12:27:18 -0400
committerFreya Murphy <freya@freyacat.org>2024-10-21 12:27:18 -0400
commit37a4e740133f8e4d669cafc8468dd13107a4810a (patch)
tree116b001142b5c0aea03ae46ef299f5fc220c4e5e /masm/gen
parentadd mips1 and mips32r2 isa definitions (diff)
downloadmips-37a4e740133f8e4d669cafc8468dd13107a4810a.tar.gz
mips-37a4e740133f8e4d669cafc8468dd13107a4810a.tar.bz2
mips-37a4e740133f8e4d669cafc8468dd13107a4810a.zip
save dev statedev
Diffstat (limited to 'masm/gen')
-rw-r--r--masm/gen/grammer.c643
-rw-r--r--masm/gen/log.c28
-rw-r--r--masm/gen/section.c156
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 = &section_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(&section->reftab);
+ string_free(&section->name);
+ free(section->data);
+}