update generator to support multipe isas, expand grammer syntax

This commit is contained in:
Freya Murphy 2024-10-09 12:07:27 -04:00
parent 94617351ed
commit 55137aee81
Signed by: freya
GPG key ID: 744AB800E383AE52
2 changed files with 383 additions and 56 deletions

View file

@ -1,7 +1,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <merror.h> #include <merror.h>
#include <melf.h> #include <melf.h>
#include <mips32.h> #include <mips.h>
#include <mips1.h>
#include <mips32r2.h>
#include <mips32r6.h> #include <mips32r6.h>
#include "tab.h" #include "tab.h"
@ -263,30 +265,6 @@ static int gen_constant(struct generator *gen, struct expr_const *const expr)
return M_ERROR; 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(IMMD, "immd")
CHK(OFFSET_BASE, "offset(base)")
CHK(OFFSET, "offset")
CHK(TARGET, "target")
CHK(HI, "hi")
CHK(LO, "lo")
#undef CHK
ERROR("!!! BUG: this should never hit !!!");
exit(1);
}
static int parse_register(enum mips32_register *reg, struct string *name) static int parse_register(enum mips32_register *reg, struct string *name)
{ {
int len = name->len; int len = name->len;
@ -403,6 +381,141 @@ static int parse_register(enum mips32_register *reg, struct string *name)
return M_ERROR; 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, static int gen_ins_read_state(struct generator *gen,
struct expr *const expr, struct expr *const expr,
struct gen_ins_state *state, struct gen_ins_state *state,
@ -459,6 +572,42 @@ static int gen_ins_read_state(struct generator *gen,
return M_ERROR; return M_ERROR;
} }
break; 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: case GMR_IMMD:
// immd // immd
if (arg->type != EXPR_INS_ARG_IMMEDIATE) { if (arg->type != EXPR_INS_ARG_IMMEDIATE) {
@ -468,6 +617,61 @@ static int gen_ins_read_state(struct generator *gen,
} }
state->immd = arg->immd; state->immd = arg->immd;
break; 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: case GMR_OFFSET:
// offset // offset
state->offset = 0; state->offset = 0;
@ -494,6 +698,19 @@ static int gen_ins_read_state(struct generator *gen,
return M_ERROR; return M_ERROR;
} }
break; 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: case GMR_TARGET:
// target // target
state->target = 0; state->target = 0;
@ -521,7 +738,7 @@ static int gen_ins_read_state(struct generator *gen,
} else if (*ptr == '\0') { } else if (*ptr == '\0') {
break; break;
} else { } else {
ERROR("!! BUG3: invalid splitting char %c !!!", *ptr); BUG("invalid grammer '%s'", grammer);
exit(1); exit(1);
} }
@ -536,27 +753,31 @@ static int gen_ins_write_state(
struct gen_ins_state *state, // the current read state struct gen_ins_state *state, // the current read state
char *grammer) // the gramemr to parse char *grammer) // the gramemr to parse
{ {
// grammer pointer
char *ptr = grammer; char *ptr = grammer;
// new reference type if needed
enum reference_type reftype = REF_NONE; enum reference_type reftype = REF_NONE;
// hardcoded
struct gen_ins_override hstate;
bool hc = false;
// read values into state // read values into state
while (*ptr != '\0') { while (*ptr != '\0') {
// parse next dsl entry // parse next dsl entry
size_t skip; size_t skip;
enum grammer_type gmr = get_gmr_type(ptr, &skip); enum grammer_type gmr = get_gmr_type(ptr, &skip);
// check for dsl hardcoded register argument // check for dsl hardcoded register argument
bool hardcoded = false; hc = false;
enum mips32_register hard_reg;
if (*(ptr + skip) == '=') { if (*(ptr + skip) == '=') {
// parse argument // get value pointer
char *rptr = ptr + skip + 2; char *value = ptr + skip + 1;
hardcoded = true; hc = true;
struct string regname; // parse value
string_bss(&regname, rptr); if (get_gmr_hc(state, &hstate, value)) {
if (parse_register(&hard_reg, &regname)) { BUG("invalid grammer: %s", grammer);
ERROR("!!! BUG2: this should never hit !!!");
exit(1); exit(1);
} }
} }
@ -568,16 +789,43 @@ static int gen_ins_write_state(
switch (gmr) { switch (gmr) {
case GMR_RD: case GMR_RD:
ins.rd = hardcoded ? hard_reg : state->rd; ins.rd = hc ? hstate.reg : state->rd;
break; break;
case GMR_RS: case GMR_RS:
ins.rs = hardcoded ? hard_reg : state->rs; ins.rs = hc ? hstate.reg : state->rs;
break; break;
case GMR_RT: case GMR_RT:
ins.rt = hardcoded ? hard_reg : state->rt; ins.rt = hc ? hstate.reg : state->rt;
break;
case GMR_FS:
ins.fs = hc ? hstate.fpreg : state->fs;
break;
case GMR_FT:
ins.ft = hc ? hstate.fpreg : state->ft;
break;
case GMR_FD:
ins.fd = hc ? hstate.fpreg : state->fd;
break; break;
case GMR_IMMD: case GMR_IMMD:
ins.immd = state->immd; ins.immd = hc ? hstate.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 ? hstate.immd : state->hb;
break;
case GMR_HINT:
ins.rt = state->hint;
break; break;
case GMR_OFFSET: case GMR_OFFSET:
ins.offset = state->offset; ins.offset = state->offset;
@ -588,6 +836,10 @@ static int gen_ins_write_state(
ins.rs = state->base; ins.rs = state->base;
reftype = REF_MIPS_16; reftype = REF_MIPS_16;
break; break;
case GMR_INDEX_BASE:
ins.rt = state->index;
ins.rs = state->base;
break;
case GMR_TARGET: case GMR_TARGET:
ins.target = state->target; ins.target = state->target;
reftype = REF_MIPS_26; reftype = REF_MIPS_26;
@ -600,6 +852,7 @@ static int gen_ins_write_state(
ins.immd = state->target & 0x0000FFFF; ins.immd = state->target & 0x0000FFFF;
reftype = REF_MIPS_LO16; reftype = REF_MIPS_LO16;
break; break;
break;
} }
} }
@ -721,8 +974,8 @@ static int gen_label(struct generator *gen, struct string *const label)
return M_SUCCESS; return M_SUCCESS;
} }
/* run codegen */ /* run codegen for next expression */
static int generate(struct generator *gen) static int generate_next(struct generator *gen)
{ {
struct expr expr; struct expr expr;
int res = M_SUCCESS; int res = M_SUCCESS;
@ -771,16 +1024,10 @@ static int generate(struct generator *gen)
return res; return res;
} }
/* run codegen with the mips32r6 specification */ static int generate(struct generator *gen)
int generate_mips32r6(struct generator *gen)
{ {
gen->instructions_len = __MIPS32R6_INS_LEN;
gen->instructions = mips32r6_instructions;
gen->grammers_len = __MIPS32R6_GRAMMER_LEN;
gen->grammers = mips32r6_grammers;
int res; int res;
while (res = generate(gen), 1) { while (res = generate_next(gen), 1) {
if (res == M_ERROR) if (res == M_ERROR)
return M_ERROR; return M_ERROR;
if (res == M_EOF) if (res == M_EOF)
@ -790,6 +1037,36 @@ int generate_mips32r6(struct generator *gen)
return M_SUCCESS; return M_SUCCESS;
} }
/* run codegen with the mips32r6 specification */
int generate_mips32r6(struct generator *gen)
{
gen->instructions_len = __MIPS32R6_INS_LEN;
gen->instructions = mips32r6_instructions;
gen->grammers_len = __MIPS32R6_GRAMMER_LEN;
gen->grammers = mips32r6_grammers;
return generate(gen);
}
/* run codegen with the mips32r2 specification */
int generate_mips32r2(struct generator *gen)
{
gen->instructions_len = __MIPS32R2_INS_LEN;
gen->instructions = mips32r2_instructions;
gen->grammers_len = __MIPS32R2_GRAMMER_LEN;
gen->grammers = mips32r2_grammers;
return generate(gen);
}
/* run codegen with the mips32r6 specification */
int generate_mips1(struct generator *gen)
{
gen->instructions_len = __MIPS1_INS_LEN;
gen->instructions = mips1_instructions;
gen->grammers_len = __MIPS1_GRAMMER_LEN;
gen->grammers = mips1_grammers;
return generate(gen);
}
int generator_init(const char *file, struct generator *gen) int generator_init(const char *file, struct generator *gen)
{ {
if (parser_init(file, &gen->parser)) if (parser_init(file, &gen->parser))

View file

@ -4,7 +4,7 @@
#define __GEN_H__ #define __GEN_H__
#include <mlimits.h> #include <mlimits.h>
#include <mips32.h> #include <mips.h>
#include <stdint.h> #include <stdint.h>
#include "parse.h" #include "parse.h"
@ -44,16 +44,42 @@ void section_free(struct section *section);
/// ///
struct gen_ins_state { struct gen_ins_state {
// rd,rst,rt // rd,rs,rt
enum mips32_register rd; enum mips32_register rd;
enum mips32_register rs; enum mips32_register rs;
enum mips32_register rt; enum mips32_register rt;
// fs,ft
enum mips32_fp_register fs;
enum mips32_fp_register ft;
enum mips32_fp_register fd;
// immd // immd
uint16_t immd; uint16_t immd; // 16 bit
// cc
uint16_t cc; // 3 bit
// code
uint32_t code; // 5 bit
// pos
uint32_t pos; // 5 bit
// size
uint32_t size; // 5 bit - 1
// hb
bool hb; // 1 bit - 1
// index
uint32_t index;
// hint
uint32_t hint;
// offset(base) // offset(base)
uint16_t offset; uint16_t offset; // 16 bit
enum mips32_register base; enum mips32_register base;
// target // target
@ -63,15 +89,35 @@ struct gen_ins_state {
struct string *label; struct string *label;
}; };
struct gen_ins_override {
enum mips32_register reg;
enum mips32_fp_register fpreg;
uint32_t immd;
};
/// ///
/// grammer type /// grammer type
/// ///
enum grammer_type { enum grammer_type {
// registers
GMR_RD, GMR_RD,
GMR_RS, GMR_RS,
GMR_RT, GMR_RT,
GMR_INDEX_BASE,
// fp registers
GMR_FS,
GMR_FT,
GMR_FD,
// numeric fields
GMR_IMMD, GMR_IMMD,
GMR_CC,
GMR_CODE,
GMR_POS,
GMR_SIZE,
GMR_HB,
GMR_HINT,
// addresses
GMR_OFFSET, GMR_OFFSET,
GMR_OFFSET_BASE, GMR_OFFSET_BASE,
GMR_TARGET, GMR_TARGET,
@ -108,6 +154,10 @@ struct generator {
/* generate the input as mips32r6 */ /* generate the input as mips32r6 */
int generate_mips32r6(struct generator *gen); int generate_mips32r6(struct generator *gen);
/* run codegen with the mips32r2 specification */
int generate_mips32r2(struct generator *gen);
/* run codegen with the mips32r6 specification */
int generate_mips1(struct generator *gen);
/* initalize a generator */ /* initalize a generator */
int generator_init(const char *file, struct generator *gen); int generator_init(const char *file, struct generator *gen);