summaryrefslogtreecommitdiff
path: root/masm/gen.c
diff options
context:
space:
mode:
Diffstat (limited to 'masm/gen.c')
-rw-r--r--masm/gen.c661
1 files changed, 10 insertions, 651 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))