update generator to support multipe isas, expand grammer syntax
This commit is contained in:
parent
94617351ed
commit
55137aee81
2 changed files with 383 additions and 56 deletions
377
masm/gen.c
377
masm/gen.c
|
@ -1,7 +1,9 @@
|
|||
#include <stdlib.h>
|
||||
#include <merror.h>
|
||||
#include <melf.h>
|
||||
#include <mips32.h>
|
||||
#include <mips.h>
|
||||
#include <mips1.h>
|
||||
#include <mips32r2.h>
|
||||
#include <mips32r6.h>
|
||||
|
||||
#include "tab.h"
|
||||
|
@ -263,30 +265,6 @@ static int gen_constant(struct generator *gen, struct expr_const *const expr)
|
|||
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)
|
||||
{
|
||||
int len = name->len;
|
||||
|
@ -403,6 +381,141 @@ static int parse_register(enum mips32_register *reg, struct string *name)
|
|||
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,
|
||||
|
@ -459,6 +572,42 @@ static int gen_ins_read_state(struct generator *gen,
|
|||
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) {
|
||||
|
@ -468,6 +617,61 @@ static int gen_ins_read_state(struct generator *gen,
|
|||
}
|
||||
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;
|
||||
|
@ -494,6 +698,19 @@ static int gen_ins_read_state(struct generator *gen,
|
|||
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;
|
||||
|
@ -521,7 +738,7 @@ static int gen_ins_read_state(struct generator *gen,
|
|||
} else if (*ptr == '\0') {
|
||||
break;
|
||||
} else {
|
||||
ERROR("!! BUG3: invalid splitting char %c !!!", *ptr);
|
||||
BUG("invalid grammer '%s'", grammer);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -536,27 +753,31 @@ static int gen_ins_write_state(
|
|||
struct gen_ins_state *state, // the current read state
|
||||
char *grammer) // the gramemr to parse
|
||||
{
|
||||
// grammer pointer
|
||||
char *ptr = grammer;
|
||||
|
||||
// new reference type if needed
|
||||
enum reference_type reftype = REF_NONE;
|
||||
|
||||
// hardcoded
|
||||
struct gen_ins_override hstate;
|
||||
bool hc = false;
|
||||
|
||||
// read values into state
|
||||
while (*ptr != '\0') {
|
||||
|
||||
// parse next dsl entry
|
||||
size_t skip;
|
||||
enum grammer_type gmr = get_gmr_type(ptr, &skip);
|
||||
|
||||
// check for dsl hardcoded register argument
|
||||
bool hardcoded = false;
|
||||
enum mips32_register hard_reg;
|
||||
hc = false;
|
||||
if (*(ptr + skip) == '=') {
|
||||
// parse argument
|
||||
char *rptr = ptr + skip + 2;
|
||||
hardcoded = true;
|
||||
struct string regname;
|
||||
string_bss(®name, rptr);
|
||||
if (parse_register(&hard_reg, ®name)) {
|
||||
ERROR("!!! BUG2: this should never hit !!!");
|
||||
// get value pointer
|
||||
char *value = ptr + skip + 1;
|
||||
hc = true;
|
||||
// parse value
|
||||
if (get_gmr_hc(state, &hstate, value)) {
|
||||
BUG("invalid grammer: %s", grammer);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -568,16 +789,43 @@ static int gen_ins_write_state(
|
|||
|
||||
switch (gmr) {
|
||||
case GMR_RD:
|
||||
ins.rd = hardcoded ? hard_reg : state->rd;
|
||||
ins.rd = hc ? hstate.reg : state->rd;
|
||||
break;
|
||||
case GMR_RS:
|
||||
ins.rs = hardcoded ? hard_reg : state->rs;
|
||||
ins.rs = hc ? hstate.reg : state->rs;
|
||||
break;
|
||||
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;
|
||||
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;
|
||||
case GMR_OFFSET:
|
||||
ins.offset = state->offset;
|
||||
|
@ -588,6 +836,10 @@ static int gen_ins_write_state(
|
|||
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;
|
||||
|
@ -600,6 +852,7 @@ static int gen_ins_write_state(
|
|||
ins.immd = state->target & 0x0000FFFF;
|
||||
reftype = REF_MIPS_LO16;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -721,8 +974,8 @@ static int gen_label(struct generator *gen, struct string *const label)
|
|||
return M_SUCCESS;
|
||||
}
|
||||
|
||||
/* run codegen */
|
||||
static int generate(struct generator *gen)
|
||||
/* run codegen for next expression */
|
||||
static int generate_next(struct generator *gen)
|
||||
{
|
||||
struct expr expr;
|
||||
int res = M_SUCCESS;
|
||||
|
@ -771,16 +1024,10 @@ static int generate(struct generator *gen)
|
|||
return res;
|
||||
}
|
||||
|
||||
/* run codegen with the mips32r6 specification */
|
||||
int generate_mips32r6(struct generator *gen)
|
||||
static int generate(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;
|
||||
while (res = generate(gen), 1) {
|
||||
while (res = generate_next(gen), 1) {
|
||||
if (res == M_ERROR)
|
||||
return M_ERROR;
|
||||
if (res == M_EOF)
|
||||
|
@ -790,6 +1037,36 @@ int generate_mips32r6(struct generator *gen)
|
|||
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)
|
||||
{
|
||||
if (parser_init(file, &gen->parser))
|
||||
|
|
58
masm/gen.h
58
masm/gen.h
|
@ -4,7 +4,7 @@
|
|||
#define __GEN_H__
|
||||
|
||||
#include <mlimits.h>
|
||||
#include <mips32.h>
|
||||
#include <mips.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "parse.h"
|
||||
|
@ -44,16 +44,42 @@ void section_free(struct section *section);
|
|||
///
|
||||
|
||||
struct gen_ins_state {
|
||||
// rd,rst,rt
|
||||
// rd,rs,rt
|
||||
enum mips32_register rd;
|
||||
enum mips32_register rs;
|
||||
enum mips32_register rt;
|
||||
|
||||
// fs,ft
|
||||
enum mips32_fp_register fs;
|
||||
enum mips32_fp_register ft;
|
||||
enum mips32_fp_register fd;
|
||||
|
||||
// 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)
|
||||
uint16_t offset;
|
||||
uint16_t offset; // 16 bit
|
||||
enum mips32_register base;
|
||||
|
||||
// target
|
||||
|
@ -63,15 +89,35 @@ struct gen_ins_state {
|
|||
struct string *label;
|
||||
};
|
||||
|
||||
struct gen_ins_override {
|
||||
enum mips32_register reg;
|
||||
enum mips32_fp_register fpreg;
|
||||
uint32_t immd;
|
||||
};
|
||||
|
||||
///
|
||||
/// grammer type
|
||||
///
|
||||
|
||||
enum grammer_type {
|
||||
// registers
|
||||
GMR_RD,
|
||||
GMR_RS,
|
||||
GMR_RT,
|
||||
GMR_INDEX_BASE,
|
||||
// fp registers
|
||||
GMR_FS,
|
||||
GMR_FT,
|
||||
GMR_FD,
|
||||
// numeric fields
|
||||
GMR_IMMD,
|
||||
GMR_CC,
|
||||
GMR_CODE,
|
||||
GMR_POS,
|
||||
GMR_SIZE,
|
||||
GMR_HB,
|
||||
GMR_HINT,
|
||||
// addresses
|
||||
GMR_OFFSET,
|
||||
GMR_OFFSET_BASE,
|
||||
GMR_TARGET,
|
||||
|
@ -108,6 +154,10 @@ struct generator {
|
|||
|
||||
/* generate the input as mips32r6 */
|
||||
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 */
|
||||
int generator_init(const char *file, struct generator *gen);
|
||||
|
|
Loading…
Reference in a new issue