summaryrefslogtreecommitdiff
path: root/masm
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
parentadd mips1 and mips32r2 isa definitions (diff)
downloadmips-dev.tar.gz
mips-dev.tar.bz2
mips-dev.zip
save dev statedev
Diffstat (limited to 'masm')
-rw-r--r--masm/gen.c661
-rw-r--r--masm/gen.h93
-rw-r--r--masm/gen/grammer.c643
-rw-r--r--masm/gen/log.c28
-rw-r--r--masm/gen/section.c156
-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
diff --git a/masm/gen.c b/masm/gen.c
index c4a15a0..74d30d2 100644
--- a/masm/gen.c
+++ b/masm/gen.c
@@ -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(&section->reftab);
- string_free(&section->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))
diff --git a/masm/gen.h b/masm/gen.h
index 42fbf50..ed35750 100644
--- a/masm/gen.h
+++ b/masm/gen.h
@@ -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 = &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);
+}
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