target: e2k: Reorg reg file.

This commit is contained in:
Denis Drakhnia 2020-12-01 14:00:12 +02:00 committed by Alibek Omarov
parent 284da505ff
commit 205647fbd9
12 changed files with 852 additions and 819 deletions

View File

@ -37,17 +37,17 @@ void cpu_loop(CPUE2KState *env)
switch (trapnr) {
case E2K_EXCP_SYSCALL: {
int offset = env->wd.base + env->syscall_wbs * 2;
uint64_t *regs = env->wregs;
uint64_t *regs = env->regs;
abi_ulong ret = do_syscall(env,
regs[(0 + offset) % WREGS_SIZE],
regs[(1 + offset) % WREGS_SIZE],
regs[(2 + offset) % WREGS_SIZE],
regs[(3 + offset) % WREGS_SIZE],
regs[(4 + offset) % WREGS_SIZE],
regs[(5 + offset) % WREGS_SIZE],
regs[(6 + offset) % WREGS_SIZE],
regs[(7 + offset) % WREGS_SIZE],
regs[(8 + offset) % WREGS_SIZE]
regs[(0 + offset) % E2K_NR_COUNT],
regs[(1 + offset) % E2K_NR_COUNT],
regs[(2 + offset) % E2K_NR_COUNT],
regs[(3 + offset) % E2K_NR_COUNT],
regs[(4 + offset) % E2K_NR_COUNT],
regs[(5 + offset) % E2K_NR_COUNT],
regs[(6 + offset) % E2K_NR_COUNT],
regs[(7 + offset) % E2K_NR_COUNT],
regs[(8 + offset) % E2K_NR_COUNT]
);
if (ret == -TARGET_ERESTARTSYS) {
/* TODO: restart syscall */
@ -57,7 +57,7 @@ void cpu_loop(CPUE2KState *env)
regs[0] = ret;
for (i = 1; i < 8; i++) {
regs[(i + offset) % WREGS_SIZE] = 0;
regs[(i + offset) % E2K_NR_COUNT] = 0;
}
}
env->ip = env->nip;

View File

@ -42,8 +42,8 @@ static void e2k_cpu_reset(DeviceState *dev)
memset(env, 0, offsetof(CPUE2KState, end_reset_fields));
env->wptr = &env->wregs[0];
env->tptr = &env->wtags[0];
env->rptr = &env->regs[0];
env->tptr = &env->tags[0];
env->cr1.wpsz = 4;
env->cr1.wbs = 4;
env->wd.base = 0;
@ -108,9 +108,9 @@ static inline void cpu_dump_state_br(CPUE2KState *env, FILE *f, int flags)
static inline int extract_tag(uint64_t *tags, int idx)
{
uint64_t tmp = tags[idx / TAGS_PER_REG];
int offset = (idx & GEN_MASK(0, TAG_BITS)) * TAG_BITS;
return extract64(tmp, offset, TAG_BITS);
uint64_t tmp = tags[idx / E2K_TAGS_PER_REG];
int offset = (idx & GEN_MASK(0, E2K_REG_TAGS_SIZE)) * E2K_REG_TAGS_SIZE;
return extract64(tmp, offset, E2K_REG_TAGS_SIZE);
}
void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
@ -132,22 +132,15 @@ void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
qemu_fprintf(f, " lsr = 0x%016lx\n", env->lsr);
cpu_dump_state_br(env, f, flags);
for (i = 0; i < WREGS_SIZE; i++) {
int tag = extract_tag(env->wtags, i);
int tl = tag & 3;
int th = tag >> 2;
qemu_fprintf(f, "%%r%d\t<%d%d> 0x%lx\n", i, th, tl, env->wregs[i]);
for (i = 0; i < E2K_REG_COUNT; i++) {
char name = i < E2K_NR_COUNT ? 'r' : 'g';
int tag = extract_tag(env->tags, i);
qemu_fprintf(f, "%%%c%d\t<%d%d> 0x%lx\n", name, i, tag & 3, tag >> 2,
env->regs[i]);
}
for (i = 0; i < 32; i++) {
int tag = extract_tag(env->gtags, i);
int tl = tag & 3;
int th = tag >> 2;
qemu_fprintf(f, "%%g%d\t<%d%d> 0x%lx\n", i, th, tl, env->gregs[i]);
}
for (i = 0; i < 32; i++) {
int preg = (env->pf >> (i * 2)) & 3;
int preg = (env->pregs >> (i * 2)) & 3;
qemu_fprintf(f, "pred%d\t<%d> %s\n", i, preg >> 1,
preg & 1 ? "true" : "false");
}

View File

@ -19,19 +19,24 @@ void e2k_tcg_initialize(void);
#define MMU_USER_IDX 1
#define CPU_RESOLVING_TYPE TYPE_E2K_CPU
#define REG_SIZE sizeof(uint64_t)
#define TAG_BITS 4 /* 2 bit per 32-bit half */
/* how many tags can be packed into register */
#define TAGS_PER_REG (REG_SIZE * 8 / TAG_BITS)
#define WREGS_SIZE 192
#define WTAGS_SIZE (WREGS_SIZE / TAGS_PER_REG)
#define GREGS_SIZE 32
#define GTAGS_SIZE (GREGS_SIZE / TAGS_PER_REG)
#define WREGS_MAX 64
#define BREGS_MAX 128
#define GREGS_MAX 24
#define BGREGS_MAX 8
#define PF_SIZE 32
#define E2K_TAG_SIZE 2 /* 2-bit tag for 32-bit value */
#define E2K_REG_LEN sizeof(uint64_t)
#define E2K_REG_SIZE (E2K_REG_LEN * 8)
#define E2K_REG_TAGS_SIZE (E2K_TAG_SIZE * 2) /* two tags for 32-bit halves */
#define E2K_WR_COUNT 64 /* %rN [0, 64) */
#define E2K_BR_COUNT 128 /* %b[N] [0, 128) */
#define E2K_NR_COUNT (E2K_WR_COUNT + E2K_BR_COUNT)
#define E2K_GR_COUNT 32 /* %gN [0, 32) */
#define E2K_BGR_COUNT 8 /* %gN [24, 32) */
#define E2K_REG_COUNT (E2K_NR_COUNT + E2K_GR_COUNT)
/* how many tags can be packed into a register */
#define E2K_TAGS_PER_REG (E2K_REG_LEN * 8 / E2K_REG_TAGS_SIZE)
/* packed tags registers count */
#define E2K_TAGS_REG_COUNT (E2K_REG_COUNT / E2K_TAGS_PER_REG)
#define E2K_PR_COUNT 32 /* %predN [0, 32) */
#define CTPR_BASE_OFF 0
#define CTPR_BASE_END 47
@ -283,12 +288,10 @@ typedef struct {
typedef struct {
/* register file */
uint64_t gregs[GREGS_SIZE]; /* global registers */
uint64_t gtags[GTAGS_SIZE]; /* global registers tags */
uint64_t wregs[WREGS_SIZE]; /* window registers */
uint64_t wtags[WTAGS_SIZE]; /* window registers tags */
uint64_t *wptr; /* pointer to wregs */
uint64_t *tptr; /* pointer to wtags */
uint64_t regs[E2K_REG_COUNT]; /* registers */
uint64_t tags[E2K_TAGS_REG_COUNT]; /* registers tags */
uint64_t *rptr; /* pointer to regs */
uint64_t *tptr; /* pointer to tags */
E2KCr1State cr1;
@ -314,7 +317,7 @@ typedef struct {
target_ulong ct_cond;
union {
uint64_t pf; /* predicate file */
uint64_t pregs; /* predicate file */
uint64_t cr0_lo;
};
union {
@ -324,7 +327,7 @@ typedef struct {
target_ulong nip; /* next instruction address */
uint32_t upsr;
uint64_t upsr;
uint64_t idr;
uint32_t pfpfr; // Packed Floating Point Flag Register (PFPFR)

View File

@ -39,7 +39,7 @@ int e2k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
}
if (3 <= n && n < 35) {
return gdb_get_reg64(mem_buf, env->gregs[n - 3]);
return gdb_get_reg64(mem_buf, env->regs[E2K_NR_COUNT + n - 3]);
}
switch (n) {

View File

@ -29,7 +29,7 @@ static inline void save_proc_chain_info(CPUE2KState *env, uint64_t buf[4],
env->cr1.wfx = env->wd.fx;
env->cr1.wbs = wbs;
env->wd.base = (env->wd.base + wbs * 2) % WREGS_SIZE;
env->wd.base = (env->wd.base + wbs * 2) % E2K_NR_COUNT;
env->wd.psize = env->wd.size -= wbs * 2;
}
@ -87,8 +87,8 @@ static void ps_push_nfx(CPUE2KState *env, unsigned int base, size_t len)
p = (uint64_t *) (env->psp.base + env->psp.index);
for (i = 0; i < len; i++) {
int idx = (base + i) % WREGS_SIZE;
memcpy(p + i, &env->wregs[idx], sizeof(uint64_t));
int idx = (base + i) % E2K_NR_COUNT;
memcpy(p + i, &env->regs[idx], sizeof(uint64_t));
}
env->psp.index += size;
@ -109,8 +109,8 @@ static void ps_pop_nfx(CPUE2KState *env, unsigned int base, size_t len)
env->psp.index -= size;
p = (uint64_t *) (env->psp.base + env->psp.index);
for (i = 0; i < len; i++) {
int idx = (base + i) % WREGS_SIZE;
memcpy(&env->wregs[idx], p + i, sizeof(uint64_t));
int idx = (base + i) % E2K_NR_COUNT;
memcpy(&env->regs[idx], p + i, sizeof(uint64_t));
}
}
@ -127,8 +127,8 @@ static void ps_push_fx(CPUE2KState *env, unsigned int base, size_t len)
p = (uint64_t *) (env->psp.base + env->psp.index);
for (i = 0; i < len; i += 2) {
int idx = (base + i) % WREGS_SIZE;
memcpy(p + i * 2, &env->wregs[idx], 2 * sizeof(uint64_t));
int idx = (base + i) % E2K_NR_COUNT;
memcpy(p + i * 2, &env->regs[idx], 2 * sizeof(uint64_t));
// TODO: save fx part
memcpy(p + i * 2 + 2, zeros, 2 * sizeof(uint64_t));
}
@ -151,8 +151,8 @@ static void ps_pop_fx(CPUE2KState *env, unsigned int base, size_t len)
env->psp.index -= size;
p = (uint64_t *) (env->psp.base + env->psp.index);
for (i = 0; i < len; i += 2) {
int idx = (base + i) % WREGS_SIZE;
memcpy(&env->wregs[idx], p + i * 2, sizeof(uint64_t));
int idx = (base + i) % E2K_NR_COUNT;
memcpy(&env->regs[idx], p + i * 2, sizeof(uint64_t));
// TODO: restore fx part
}
}
@ -160,11 +160,11 @@ static void ps_pop_fx(CPUE2KState *env, unsigned int base, size_t len)
static inline void ps_push(CPUE2KState *env)
{
int occupied = env->wd.size + env->pshtp.index;
if (WREGS_SIZE < occupied) {
int len = occupied - WREGS_SIZE;
if (E2K_NR_COUNT < occupied) {
int len = occupied - E2K_NR_COUNT;
int base = (int) env->wd.base - env->pshtp.index;
if (base < 0) {
base += WREGS_SIZE;
base += E2K_NR_COUNT;
}
// TODO: ps_push_fx
ps_push_nfx(env, base, len);
@ -219,9 +219,9 @@ void helper_return(CPUE2KState *env)
new_wd_size = env->wd.psize + offset;
new_wd_base = env->wd.base;
if (new_wd_base < offset) {
new_wd_base += WREGS_SIZE;
new_wd_base += E2K_NR_COUNT;
}
new_wd_base = (new_wd_base - offset) % WREGS_SIZE;
new_wd_base = (new_wd_base - offset) % E2K_NR_COUNT;
ps_pop(env, new_wd_base, offset);
pcs_pop(env);
@ -274,7 +274,7 @@ void e2k_break_save_state(CPUE2KState *env)
ps_push_fx(env, env->wd.base, env->wd.size);
pcs_push(env, wbs);
env->wd.base = (env->wd.base + env->wd.size) % WREGS_SIZE;
env->wd.base = (env->wd.base + env->wd.size) % E2K_NR_COUNT;
env->wd.size = 0;
env->wd.psize = 0;
@ -287,7 +287,7 @@ void helper_break_restore_state(CPUE2KState *env)
pcs_pop(env);
env->wd.size = wbs * 2;
env->wd.base = (env->wd.base - env->wd.size) % WREGS_SIZE;
env->wd.base = (env->wd.base - env->wd.size) % E2K_NR_COUNT;
ps_pop_fx(env, env->wd.base, env->wd.size);
env->is_bp = false;

View File

@ -7,8 +7,10 @@ DEF_HELPER_2(sxt, i64, i64, i64)
DEF_HELPER_1(debug_i32, void, i32)
DEF_HELPER_1(debug_i64, void, i64)
DEF_HELPER_1(debug_ptr, void, ptr)
DEF_HELPER_2(state_reg_get, i64, env, int)
DEF_HELPER_3(state_reg_set, void, env, int, i64)
DEF_HELPER_2(state_reg_read_i64, i64, env, int)
DEF_HELPER_2(state_reg_read_i32, i32, env, int)
DEF_HELPER_3(state_reg_write_i64, void, env, int, i64)
DEF_HELPER_3(state_reg_write_i32, void, env, int, i32)
DEF_HELPER_2(getsp, i64, env, i64) /* FIXME: return tl? */
DEF_HELPER_1(break_restore_state, void, env)
DEF_HELPER_2(setwd, void, env, i32)

View File

@ -29,52 +29,63 @@ uint64_t helper_sxt(uint64_t x, uint64_t y)
}
}
uint64_t helper_state_reg_get(CPUE2KState *env, int reg)
static uint64_t* state_reg_ptr(CPUE2KState *env, int idx)
{
switch (reg) {
case 0x2c: /* %usd.hi */
return env->usd_hi;
case 0x2d: /* %usd.lo */
return env->usd_lo;
case 0x80: /* %upsr */
return env->upsr;
case 0x81: /* %ip */
return env->ip;
case 0x83: /* %lsr */
return env->lsr;
case 0x8a: /* %idr */
return env->idr;
case 0x90: /* %clkr */
return cpu_get_host_ticks();
default:
/* TODO: exception */
qemu_log_mask(LOG_UNIMP, "unknown register 0x%x\n", reg);
abort();
return 0; /* unreachable */
switch (idx) {
/* FIXME: user cannot write */
case 0x2c: return &env->usd_hi; /* %usd.hi */
/* FIXME: user cannot write */
case 0x2d: return &env->usd_lo; /* %usd.lo */
case 0x80: return &env->upsr; /* %upsr */
case 0x83: return &env->lsr; /* %lsr */
default: return NULL;
}
}
void helper_state_reg_set(CPUE2KState *env, int reg, uint64_t val)
uint64_t helper_state_reg_read_i64(CPUE2KState *env, int idx)
{
switch (reg) {
case 0x2c: /* %usd.hi */
/* FIXME: user cannot write */
env->usd_hi = val;
break;
case 0x2d: /* %usd.lo */
/* FIXME: user cannot write */
env->usd_lo = val;
break;
case 0x80: /* %upsr */
env->upsr = val;
break;
case 0x83: /* %lsr */
env->lsr = val;
break;
default:
qemu_log_mask(LOG_UNIMP, "unknown register 0x%x\n", reg);
switch (idx) {
case 0x90: /* %clkr */
return cpu_get_host_ticks();
default: {
uint64_t *p = state_reg_ptr(env, idx);
if (p != NULL) {
return *p;
} else {
qemu_log_mask(LOG_UNIMP, "read unknown state register 0x%x\n", idx);
return 0;
}
}
}
}
uint32_t helper_state_reg_read_i32(CPUE2KState *env, int idx)
{
return helper_state_reg_read_i64(env, idx);
}
void helper_state_reg_write_i64(CPUE2KState *env, int idx, uint64_t val)
{
uint64_t *p = state_reg_ptr(env, idx);
if (p != NULL) {
*p = val;
} else {
qemu_log_mask(LOG_UNIMP, "unknown state register 0x%x\n", idx);
abort();
}
}
void helper_state_reg_write_i32(CPUE2KState *env, int idx, uint32_t val)
{
uint32_t *p = (uint32_t*) state_reg_ptr(env, idx);
if (p != NULL) {
*p = val;
} else {
qemu_log_mask(LOG_UNIMP, "unknown state register 0x%x\n", idx);
abort();
break;
}
}

View File

@ -287,19 +287,11 @@ static inline void do_execute(DisasContext *ctx)
e2k_plu_execute(ctx);
e2k_control_gen(ctx);
/* allocate storage for tags if needed */
for (i = 0; i < 6; i++) {
if (ctx->bundle.als_present[i]) {
ctx->alc_tags = e2k_get_temp_i64(ctx);
tcg_gen_movi_i64(ctx->alc_tags, 0);
break;
}
}
ctx->al_results[i].type = AL_RESULT_NONE;
for (i = 0; i < 6; i++) {
if (ctx->bundle.als_present[i]) {
ctx->alc[i].tag = RESULT_NONE;
e2k_execute_alc(ctx, i);
e2k_alc_execute(ctx, i);
}
}
}
@ -314,50 +306,7 @@ static inline void do_execute(DisasContext *ctx)
* */
static inline void do_commit(DisasContext *ctx)
{
unsigned int i;
for (i = 0; i < 6; i++) {
TCGLabel *l0 = gen_new_label();
TCGv_i64 t0;
Result *res = &ctx->alc[i];
if (!ctx->bundle.als_present[i]) {
continue;
}
t0 = tcg_temp_new_i64();
if (res->has_cond) {
tcg_gen_brcondi_i64(TCG_COND_EQ, res->cond, 0, l0);
}
switch(res->tag) {
case RESULT_BASED_REG:
e2k_gen_store_breg(ctx, res->u.reg.i, res->u.reg.v);
tcg_gen_extract_i64(t0, ctx->alc_tags, i * TAG_BITS, TAG_BITS);
e2k_gen_btag_set(res->u.reg.i, t0);
break;
case RESULT_REGULAR_REG:
e2k_gen_store_wreg(ctx, res->u.reg.i, res->u.reg.v);
tcg_gen_extract_i64(t0, ctx->alc_tags, i * TAG_BITS, TAG_BITS);
e2k_gen_wtagi_set(res->u.reg.i, t0);
break;
case RESULT_GLOBAL_REG:
e2k_gen_store_greg(res->u.reg.i, res->u.reg.v);
tcg_gen_extract_i64(t0, ctx->alc_tags, i * TAG_BITS, TAG_BITS);
e2k_gen_gtag_set(res->u.reg.i, t0);
break;
case RESULT_PREG:
e2k_gen_store_preg(res->u.reg.i, res->u.reg.v);
break;
default:
break;
}
gen_set_label(l0);
tcg_temp_free_i64(t0);
}
e2k_alc_commit(ctx);
e2k_plu_commit(ctx);
e2k_commit_stubs(ctx);
}
@ -559,7 +508,7 @@ void e2k_tcg_initialize(void) {
};
static const struct { TCGv_i64 *ptr; int off; const char *name; } r64[] = {
{ &e2k_cs.pregs, offsetof(CPUE2KState, pf), "pregs" },
{ &e2k_cs.pregs, offsetof(CPUE2KState, pregs), "pregs" },
{ &e2k_cs.lsr, offsetof(CPUE2KState, lsr), "lsr" },
};
@ -583,33 +532,23 @@ void e2k_tcg_initialize(void) {
*rtl[i].ptr = tcg_global_mem_new(cpu_env, rtl[i].off, rtl[i].name);
}
e2k_cs.wptr = tcg_global_mem_new_ptr(cpu_env,
offsetof(CPUE2KState, wptr), "wptr");
e2k_cs.rptr = tcg_global_mem_new_ptr(cpu_env,
offsetof(CPUE2KState, rptr), "regs_ptr");
e2k_cs.tptr = tcg_global_mem_new_ptr(cpu_env,
offsetof(CPUE2KState, tptr), "tptr");
offsetof(CPUE2KState, tptr), "tags_ptr");
for (i = 0; i < WREGS_SIZE; i++) {
snprintf(buf, ARRAY_SIZE(buf), "%%r%d", i);
e2k_cs.wregs[i] = tcg_global_mem_new_i64(e2k_cs.wptr,
i * REG_SIZE, buf);
for (i = 0; i < E2K_REG_COUNT; i++) {
char name = i < E2K_NR_COUNT ? 'r' : 'g';
snprintf(buf, ARRAY_SIZE(buf), "%%%c%d", name, i);
e2k_cs.regs[i] = tcg_global_mem_new_i64(e2k_cs.rptr,
i * E2K_REG_LEN, buf);
}
for (i = 0; i < WTAGS_SIZE; i++) {
snprintf(buf, ARRAY_SIZE(buf), "%%wtags%d", i);
e2k_cs.wtags[i] = tcg_global_mem_new_i64(e2k_cs.tptr,
i * REG_SIZE, buf);
}
for (i = 0; i < GREGS_SIZE; i++) {
snprintf(buf, ARRAY_SIZE(buf), "%%g%d", i);
e2k_cs.gregs[i] = tcg_global_mem_new_i64(cpu_env,
offsetof(CPUE2KState, gregs[i]), buf);
}
for (i = 0; i < GTAGS_SIZE; i++) {
snprintf(buf, ARRAY_SIZE(buf), "%%gtags%d", i);
e2k_cs.gtags[i] = tcg_global_mem_new_i64(cpu_env,
offsetof(CPUE2KState, gtags[i]), buf);
for (i = 0; i < E2K_TAGS_REG_COUNT; i++) {
char name = i < E2K_NR_COUNT ? 'r' : 'g';
snprintf(buf, ARRAY_SIZE(buf), "%%%c_tags%d", name, i);
e2k_cs.tags[i] = tcg_global_mem_new_i64(e2k_cs.tptr,
i * E2K_REG_LEN, buf);
}
for (i = 0; i < 3; i++) {

View File

@ -62,11 +62,9 @@ typedef struct CPUE2KStateTCG {
TCGv ct_cond;
TCGv_i32 is_bp; /* breakpoint flag */
TCGv_i64 lsr;
TCGv_i64 wregs[WREGS_SIZE];
TCGv_i64 wtags[WTAGS_SIZE];
TCGv_i64 gregs[GREGS_SIZE];
TCGv_i64 gtags[GTAGS_SIZE];
TCGv_ptr wptr; /* pointer to wregs */
TCGv_i64 regs[E2K_REG_COUNT];
TCGv_i64 tags[E2K_TAGS_REG_COUNT];
TCGv_ptr rptr; /* pointer to wregs */
TCGv_ptr tptr; /* pointer to wtags */
TCGv_i32 wd_base; /* holds wbs * 2 */
TCGv_i32 wd_size; /* holds wsz * 2 */
@ -103,30 +101,40 @@ typedef struct UnpackedBundle {
bool cds_present[3];
} UnpackedBundle;
enum ResultType {
RESULT_NONE,
RESULT_BASED_REG,
RESULT_REGULAR_REG,
RESULT_GLOBAL_REG,
RESULT_PREG,
};
typedef enum {
AL_RESULT_NONE,
AL_RESULT_REG32,
AL_RESULT_REG64,
AL_RESULT_PREG,
} AlResultType;
typedef struct {
enum ResultType tag;
bool has_cond;
TCGv_i64 cond;
AlResultType type;
union {
struct {
unsigned int i;
TCGv_i64 v;
TCGv_i32 index;
union {
TCGv_i32 v32;
TCGv_i64 v64;
};
TCGv_i32 tag;
} reg;
} u;
} Result;
struct {
int index;
TCGv_i64 value;
} preg;
};
} AlResult;
typedef struct {
bool is_set;
TCGv_i64 value;
} AlCond;
typedef struct {
int reg; // -1 means do not write
TCGv_i32 value;
} PluResult;
} PlResult;
typedef enum {
CT_NONE,
@ -164,9 +172,9 @@ typedef struct DisasContext {
int ttl_len;
TCGv_i64 cond[6];
Result alc[6];
TCGv_i64 alc_tags;
PluResult plu[3];
AlResult al_results[6];
AlCond al_cond[6];
PlResult pl_results[3];
ControlTransfer ct;
} DisasContext;
@ -229,28 +237,30 @@ static inline void e2k_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1,
tcg_temp_free_i64(t0);
}
/* register index must be valid */
void e2k_gen_wtag_get(TCGv_i64 ret, TCGv_i32 idx);
void e2k_gen_wtagi_get(TCGv_i64 ret, int reg);
void e2k_gen_wtag_set(TCGv_i32 idx, TCGv_i64 tag);
void e2k_gen_wtagi_set(int reg, TCGv_i64 tag);
void e2k_gen_btag_get(TCGv_i64 ret, int reg);
void e2k_gen_btag_set(int reg, TCGv_i64 tag);
void e2k_gen_gtag_get(TCGv_i64 ret, int reg);
void e2k_gen_gtag_set(int reg, TCGv_i64 tag);
static inline TCGv_i32 e2k_get_temp_i32(DisasContext *dc)
{
assert(dc->t32_len < ARRAY_SIZE(dc->t32));
return dc->t32[dc->t32_len++] = tcg_temp_local_new_i32();
}
static inline TCGv_i32 e2k_get_const_i32(DisasContext *dc, uint32_t value)
{
assert(dc->t32_len < ARRAY_SIZE(dc->t32));
return dc->t32[dc->t32_len++] = tcg_const_local_i32(value);
}
static inline TCGv_i64 e2k_get_temp_i64(DisasContext *dc)
{
assert(dc->t64_len < ARRAY_SIZE(dc->t64));
return dc->t64[dc->t64_len++] = tcg_temp_local_new_i64();
}
static inline TCGv_i64 e2k_get_const_i64(DisasContext *dc, uint64_t value)
{
assert(dc->t64_len < ARRAY_SIZE(dc->t64));
return dc->t64[dc->t64_len++] = tcg_const_local_i64(value);
}
static inline TCGv e2k_get_temp(DisasContext *dc)
{
assert(dc->ttl_len < ARRAY_SIZE(dc->ttl));
@ -287,15 +297,51 @@ static inline void e2k_gen_lcntex(TCGv_i32 ret)
tcg_temp_free_i32(t0);
}
void e2k_gen_store_preg(int idx, TCGv_i64 val);
void e2k_gen_reg_tag_read_i64(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_reg_tag_read_i32(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_reg_tag_write_i64(TCGv_i32 value, TCGv_i32 idx);
void e2k_gen_reg_tag_write_i32(TCGv_i32 value, TCGv_i32 idx);
static inline void e2k_gen_reg_tag_writei_i64(int value, TCGv_i32 idx)
{
TCGv_i32 t0 = tcg_const_i32(value);
e2k_gen_reg_tag_write_i64(t0, idx);
tcg_temp_free_i32(t0);
}
static inline void e2k_gen_reg_tag_writei_i32(int value, TCGv_i32 idx)
{
TCGv_i32 t0 = tcg_const_i32(value);
e2k_gen_reg_tag_write_i32(t0, idx);
tcg_temp_free_i32(t0);
}
static inline void e2k_gen_reg_tag_extract_lo(TCGv_i32 ret, TCGv_i32 tags)
{
tcg_gen_andi_i32(ret, tags, GEN_MASK(0, E2K_TAG_SIZE));
}
static inline void e2k_gen_reg_tag_extract_hi(TCGv_i32 ret, TCGv_i32 tags)
{
tcg_gen_shri_i32(ret, tags, E2K_TAG_SIZE);
}
void e2k_gen_reg_tag_check_i64(TCGv_i32 ret, TCGv_i32 tag);
void e2k_gen_reg_tag_check_i32(TCGv_i32 ret, TCGv_i32 tag);
void e2k_gen_reg_index_from_wregi(TCGv_i32 ret, int idx);
void e2k_gen_reg_index_from_bregi(TCGv_i32 ret, int idx);
void e2k_gen_reg_index_from_gregi(TCGv_i32 ret, int idx);
void e2k_gen_reg_read_i64(TCGv_i64 ret, TCGv_i32 idx);
void e2k_gen_reg_read_i32(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_reg_write_i64(TCGv_i64 value, TCGv_i32 idx);
void e2k_gen_reg_write_i32(TCGv_i32 value, TCGv_i32 idx);
void e2k_gen_preg(TCGv_i64 ret, int reg);
TCGv_i64 e2k_get_preg(DisasContext *dc, int reg);
void e2k_gen_store_preg(int reg, TCGv_i64 val);
TCGv_i64 e2k_get_wreg(DisasContext *ctx, int reg);
void e2k_gen_store_wreg(DisasContext *ctx, int reg, TCGv_i64 val);
TCGv_i64 e2k_get_breg(DisasContext *ctx, int reg);
void e2k_gen_store_breg(DisasContext *ctx, int reg, TCGv_i64 val);
TCGv_i64 e2k_get_greg(DisasContext *dc, int reg);
void e2k_gen_store_greg(int reg, TCGv_i64 val);
void e2k_gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc);
static inline void e2k_gen_cond_i64(DisasContext *ctx, TCGv_i64 ret,
@ -325,7 +371,7 @@ static inline void e2k_gen_exception(int excp)
void e2k_control_gen(DisasContext *dc);
void e2k_execute_alc(DisasContext *ctx, int index);
void e2k_alc_execute(DisasContext *ctx, int index);
void e2k_alc_commit(DisasContext *dc);
void e2k_plu_execute(DisasContext *ctx);

View File

@ -3,120 +3,250 @@
#include "exec/log.h"
#include "translate.h"
static TCGv_i64 get_src1(DisasContext *dc, uint32_t als)
typedef struct {
TCGv_i32 tag;
TCGv_i64 value;
} Src64;
typedef struct {
TCGv_i32 tag;
TCGv_i32 value;
} Src32;
static inline void gen_reg_index(TCGv_i32 ret, uint8_t arg)
{
unsigned int src1 = GET_FIELD(als, 16, 8);
if (IS_BASED(src1)) {
unsigned int i = GET_BASED(src1);
return e2k_get_breg(dc, i);
} else if (IS_REGULAR(src1)) {
unsigned int i = GET_REGULAR(src1);
return e2k_get_wreg(dc, i);
} else if (IS_IMM5(src1)) {
unsigned int imm = GET_IMM5(src1);
TCGv_i64 t = e2k_get_temp_i64(dc);
tcg_gen_movi_i64(t, imm);
return t;
if (IS_BASED(arg)) {
e2k_gen_reg_index_from_bregi(ret, GET_BASED(arg));
} else if (IS_REGULAR(arg)) {
e2k_gen_reg_index_from_wregi(ret, GET_REGULAR(arg));
} else if (IS_GLOBAL(arg)) {
e2k_gen_reg_index_from_gregi(ret, GET_GLOBAL(arg));
} else {
unsigned int i = GET_GLOBAL(src1);
return e2k_get_greg(dc, i);
e2k_gen_exception(E2K_EXCP_ILLOPN);
}
}
static TCGv_i64 get_src2(DisasContext *dc, uint32_t als)
static inline void gen_reg_i64(DisasContext *ctx, Src64 *ret, uint8_t arg)
{
unsigned int src2 = GET_FIELD(als, 8, 8);
if (IS_BASED(src2)) {
unsigned int i = GET_BASED(src2);
return e2k_get_breg(dc, i);
} else if (IS_REGULAR(src2)) {
unsigned int i = GET_REGULAR(src2);
return e2k_get_wreg(dc, i);
} else if (IS_IMM4(src2)) {
unsigned int imm = GET_IMM4(src2);
TCGv t = e2k_get_temp_i64(dc);
tcg_gen_movi_i64(t, imm);
return t;
} else if (IS_LIT(src2)) {
TCGv t = e2k_get_temp_i64(dc);
unsigned int i = GET_LIT(src2);
uint64_t lit = dc->bundle.lts[i];
// TODO: exception
assert(dc->bundle.lts_present[i]);
if (IS_LIT16_LO(src2) && i < 2) {
lit = ((int64_t) lit << 48) >> 48;
} else if (IS_LIT16_HI(src2) && i < 2) {
lit = ((int64_t) lit << 32) >> 48;
} else if (IS_LIT32(src2)) {
lit = ((int64_t) lit << 32) >> 32;
} else if (IS_LIT64(src2) && i < 3) {
if (!dc->bundle.lts_present[i + 1]) {
// TODO: check what exception must be raised
e2k_tr_gen_exception(dc, E2K_EXCP_MAPERR);
}
lit |= (uint64_t) dc->bundle.lts[i + 1] << 32;
} else {
// TODO: check what exception must be raised
e2k_tr_gen_exception(dc, E2K_EXCP_MAPERR);
TCGv_i32 t0 = tcg_temp_new_i32();
gen_reg_index(t0, arg);
ret->tag = e2k_get_temp_i32(ctx);
ret->value = e2k_get_temp_i64(ctx);
e2k_gen_reg_tag_read_i32(ret->tag, t0);
e2k_gen_reg_read_i64(ret->value, t0);
tcg_temp_free_i32(t0);
}
static inline void gen_reg_i32(DisasContext *ctx, Src32 *ret, uint8_t arg)
{
TCGv_i32 t0 = tcg_temp_new_i32();
gen_reg_index(t0, arg);
ret->tag = e2k_get_temp_i32(ctx);
ret->value = e2k_get_temp_i32(ctx);
e2k_gen_reg_tag_read_i32(ret->tag, t0);
e2k_gen_reg_read_i32(ret->value, t0);
tcg_temp_free_i32(t0);
}
static inline void gen_literal_i64(DisasContext *ctx, Src64 *ret, uint8_t arg)
{
int i = GET_LIT(arg);
uint64_t lit = ctx->bundle.lts[i];
if (!ctx->bundle.lts_present[i]) {
e2k_gen_exception(E2K_EXCP_ILLOPN);
} else if (IS_LIT16_LO(arg) && i < 2) {
lit = ((int64_t) lit << 48) >> 48;
} else if (IS_LIT16_HI(arg) && i < 2) {
lit = ((int64_t) lit << 32) >> 48;
} else if (IS_LIT32(arg)) {
lit = ((int64_t) lit << 32) >> 32;
} else if (IS_LIT64(arg) && i < 3) {
if (!ctx->bundle.lts_present[i + 1]) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
}
tcg_gen_movi_i64(t, lit);
return t;
lit |= (uint64_t) ctx->bundle.lts[i + 1] << 32;
} else {
unsigned int i = GET_GLOBAL(src2);
return e2k_get_greg(dc, i);
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
}
ret->value = e2k_get_const_i64(ctx, lit);
}
static inline void gen_literal_i32(DisasContext *ctx, Src32 *ret, uint8_t arg)
{
int i = GET_LIT(arg);
int32_t lit = ctx->bundle.lts[i];
if (!ctx->bundle.lts_present[i]) {
e2k_gen_exception(E2K_EXCP_ILLOPN);
} else if (IS_LIT16_LO(arg) && i < 2) {
lit = (lit << 16) >> 16;
} else if (IS_LIT16_HI(arg) && i < 2) {
lit = lit >> 16;
} else if (IS_LIT32(arg)) {
// nop
} else if (IS_LIT64(arg) && i < 3) {
// FIXME: check CPU behavior in such situation
if (!ctx->bundle.lts_present[i + 1]) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
}
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
}
ret->value = e2k_get_const_i32(ctx, lit);
}
static inline Src64 get_src1_i64(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 16, 8);
Src64 ret = { 0 };
if (IS_IMM5(arg)) {
ret.value = e2k_get_const_i64(ctx, GET_IMM5(arg));
} else {
gen_reg_i64(ctx, &ret, arg);
}
return ret;
}
static inline Src32 get_src1_i32(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 16, 8);
Src32 ret = { 0 };
if (IS_IMM5(arg)) {
ret.value = e2k_get_const_i32(ctx, GET_IMM5(arg));
} else {
gen_reg_i32(ctx, &ret, arg);
}
return ret;
}
static inline Src64 get_src2_i64(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 8, 8);
Src64 ret = { 0 };
if (IS_IMM4(arg)) {
ret.value = e2k_get_const_i64(ctx, GET_IMM4(arg));
} else if (IS_LIT(arg)) {
gen_literal_i64(ctx, &ret, arg);
} else {
gen_reg_i64(ctx, &ret, arg);
}
return ret;
}
static inline Src32 get_src2_i32(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 8, 8);
Src32 ret = { 0 };
if (IS_IMM4(arg)) {
ret.tag = NULL;
ret.value = e2k_get_const_i32(ctx, GET_IMM4(arg));
} else if (IS_LIT(arg)) {
gen_literal_i32(ctx, &ret, arg);
} else {
gen_reg_i32(ctx, &ret, arg);
}
return ret;
}
static inline Src64 get_src4_i64(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 0, 8);
Src64 ret = { 0 };
gen_reg_i64(ctx, &ret, arg);
return ret;
}
static inline Src32 get_src4_i32(DisasContext *ctx, int chan)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 0, 8);
Src32 ret = { 0 };
gen_reg_i32(ctx, &ret, arg);
return ret;
}
static inline void set_al_result_reg64_tag(DisasContext *ctx, int chan,
TCGv_i64 value, TCGv_i32 tag)
{
uint8_t arg = extract32(ctx->bundle.als[chan], 0, 8);
AlResult *res = &ctx->al_results[chan];
// TODO: %ctpr, %tst, %tc, %tcd
if (arg == 0xdf) { /* %empty */
res->type = AL_RESULT_NONE;
res->reg.index = NULL;
res->reg.v64 = NULL;
res->reg.tag = NULL;
} else {
res->type = AL_RESULT_REG64;
res->reg.v64 = value;
res->reg.tag = tag;
res->reg.index = e2k_get_temp_i32(ctx);
gen_reg_index(res->reg.index, arg);
}
}
static TCGv_i64 get_dst(DisasContext *dc, unsigned int als)
static inline void set_al_result_reg64(DisasContext *ctx, int chan,
TCGv_i64 value)
{
unsigned int dst = als & 0xff;
if (IS_BASED(dst)) {
unsigned int i = GET_BASED(dst);
return e2k_get_breg(dc, i);
} else if (IS_REGULAR(dst)) {
unsigned int i = GET_REGULAR(dst);
return e2k_get_wreg(dc, i);
} else if (IS_GLOBAL(dst)) {
unsigned int i = GET_GLOBAL(dst);
return e2k_get_greg(dc, i);
} else {
// TODO: %empty, %ctpr, etc
abort();
}
// TODO: remove
return e2k_get_temp_i64(dc);
set_al_result_reg64_tag(ctx, chan, value, e2k_get_const_i32(ctx, 0));
}
static void store_reg_alc_result(DisasContext *dc, int chan, TCGv_i64 val)
static inline void set_al_result_reg32_tag(DisasContext *ctx, int chan,
TCGv_i32 value, TCGv_i32 tag)
{
uint8_t dst = dc->bundle.als[chan];
Result *res = &dc->alc[chan];
res->u.reg.v = val;
uint8_t arg = extract32(ctx->bundle.als[chan], 0, 8);
AlResult *res = &ctx->al_results[chan];
// TODO: write tag to temp storage
TCGv_i64 tag = tcg_const_i64(dst % 15);
tcg_gen_deposit_i64(dc->alc_tags, dc->alc_tags, tag, chan * TAG_BITS,
TAG_BITS);
tcg_temp_free_i64(tag);
if (IS_BASED(dst)) {
res->tag = RESULT_BASED_REG;
res->u.reg.i = GET_BASED(dst);
} else if (IS_REGULAR(dst)) {
res->tag = RESULT_REGULAR_REG;
res->u.reg.i = GET_REGULAR(dst);
} else if (IS_GLOBAL(dst)) {
res->tag = RESULT_GLOBAL_REG;
res->u.reg.i = GET_GLOBAL(dst);
} else if (dst == 0xdf) { /* %empty */
res->tag = RESULT_NONE;
res->u.reg.i = -1;
// TODO: %ctpr, %tst, %tc, %tcd
if (arg == 0xdf) { /* %empty */
res->type = AL_RESULT_NONE;
res->reg.index = NULL;
res->reg.v32 = NULL;
res->reg.tag = NULL;
} else {
// TODO: %ctpr, etc
abort();
res->type = AL_RESULT_REG32;
res->reg.v32 = value;
res->reg.tag = tag;
res->reg.index = e2k_get_temp_i32(ctx);
gen_reg_index(res->reg.index, arg);
}
}
static inline void set_al_result_reg32(DisasContext *ctx, int chan,
TCGv_i32 value)
{
set_al_result_reg32_tag(ctx, chan, value, e2k_get_const_i32(ctx, 0));
}
static inline void set_al_result_preg(DisasContext *ctx, int chan, int index,
TCGv_i64 value)
{
AlResult *res = &ctx->al_results[chan];
res->type = AL_RESULT_PREG;
res->preg.index = index;
res->preg.value = value;
}
static inline void gen_andn_i32(TCGv_i32 ret, TCGv_i32 x, TCGv_i32 y)
{
TCGv_i32 t0 = tcg_temp_new_i32();
@ -274,54 +404,22 @@ static TCGCond e2k_gen_cmp_op(unsigned int cmp_op)
return TCG_COND_NEVER; /* unreachable */
}
static inline void gen_cmpsb(DisasContext *dc, int chan)
static inline void gen_cmp_i32(TCGv_i32 ret, int opc,
TCGv_i32 src1, TCGv_i32 src2)
{
uint32_t als = dc->bundle.als[chan];
TCGv_i64 s1 = get_src1(dc, als);
TCGv_i64 s2 = get_src2(dc, als);
TCGv_i64 dst64 = e2k_get_temp_i64(dc);
TCGv_i32 dst32 = tcg_temp_new_i32();
TCGv_i32 lo1 = tcg_temp_new_i32();
TCGv_i32 lo2 = tcg_temp_new_i32();
TCGCond cond = e2k_gen_cmp_op(GET_FIELD(als, 5, 3));
Result res = { 0 };
tcg_gen_extrl_i64_i32(lo1, s1);
tcg_gen_extrl_i64_i32(lo2, s2);
tcg_gen_setcond_i32(cond, dst32, lo1, lo2);
tcg_gen_extu_i32_i64(dst64, dst32);
res.tag = RESULT_PREG;
res.u.reg.i = als & 0x1f;
res.u.reg.v = dst64;
dc->alc[chan] = res;
tcg_temp_free_i32(lo2);
tcg_temp_free_i32(lo1);
tcg_temp_free_i32(dst32);
TCGCond cond = e2k_gen_cmp_op(opc);
tcg_gen_setcond_i32(cond, ret, src1, src2);
}
static inline void gen_cmpdb(DisasContext* dc, int chan)
static inline void gen_cmp_i64(TCGv_i64 ret, int opc, TCGv_i64 src1,
TCGv_i64 src2)
{
uint32_t als = dc->bundle.als[chan];
TCGv_i64 src1 = get_src1(dc, als);
TCGv_i64 src2 = get_src2(dc, als);
TCGv_i64 dst = e2k_get_temp_i64(dc);
TCGCond cond = e2k_gen_cmp_op(GET_FIELD(als, 5, 3));
Result res = { 0 };
tcg_gen_setcond_i64(cond, dst, src1, src2);
res.tag = RESULT_PREG;
res.u.reg.i = als & 0x1f;
res.u.reg.v = dst;
dc->alc[chan] = res;
TCGCond cond = e2k_gen_cmp_op(opc);
tcg_gen_setcond_i64(cond, ret, src1, src2);
}
static inline void gen_cmpand_i64(DisasContext *ctx, TCGv_i64 ret, int opc,
TCGv_i64 src1, TCGv_i64 src2)
static inline void gen_cmpand_i64(TCGv_i64 ret, int opc, TCGv_i64 src1,
TCGv_i64 src2)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_and_i64(t0, src1, src2);
@ -352,53 +450,50 @@ static inline void gen_cmpand_i64(DisasContext *ctx, TCGv_i64 ret, int opc,
tcg_gen_setcondi_i64(TCG_COND_LE, ret, t0, 0);
break;
default:
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
e2k_gen_exception(E2K_EXCP_ILLOPC);
break;
}
tcg_temp_free_i64(t0);
}
static inline void gen_cmpandsb(DisasContext *ctx, int chan)
static inline void gen_cmpand_i32(TCGv_i32 ret, int opc, TCGv_i32 src1,
TCGv_i32 src2)
{
uint32_t als = ctx->bundle.als[chan];
int opc = GET_FIELD(als, 5, 3);
TCGv_i64 src1 = get_src1(ctx, als);
TCGv_i64 src2 = get_src2(ctx, als);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
Result res = { 0 };
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
tcg_gen_and_i32(t0, src1, src2);
tcg_gen_extrl_i64_i32(t0, src1);
tcg_gen_extrl_i64_i32(t1, src2);
tcg_gen_ext_i32_i64(src1, t0);
tcg_gen_ext_i32_i64(src2, t1);
gen_cmpand_i64(ctx, dst, opc, src1, src2);
switch (opc) {
case 2: /* is zero */
tcg_gen_setcondi_i32(TCG_COND_EQ, ret, t0, 0);
break;
case 4: /* is negative */
tcg_gen_setcondi_i32(TCG_COND_LT, ret, t0, 0);
break;
case 5: { /* is odd and greater than 3 */
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
TCGv_i32 t3 = tcg_temp_new_i32();
res.tag = RESULT_PREG;
res.u.reg.i = als & 0x1f;
res.u.reg.v = dst;
tcg_gen_andi_i32(t1, t0, 1);
tcg_gen_setcondi_i32(TCG_COND_NE, t2, t1, 0);
tcg_gen_setcondi_i32(TCG_COND_GTU, t3, t0, 2);
tcg_gen_setcond_i32(TCG_COND_EQ, ret, t2, t3);
ctx->alc[chan] = res;
}
tcg_temp_free_i32(t3);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
break;
}
case 7: /* signed less or equal 0 */
tcg_gen_setcondi_i32(TCG_COND_LE, ret, t0, 0);
break;
default:
e2k_gen_exception(E2K_EXCP_ILLOPC);
break;
}
static inline void gen_cmpanddb(DisasContext *ctx, int chan)
{
uint32_t als = ctx->bundle.als[chan];
int opc = GET_FIELD(als, 5, 3);
TCGv_i64 src1 = get_src1(ctx, als);
TCGv_i64 src2 = get_src2(ctx, als);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
Result res = { 0 };
gen_cmpand_i64(ctx, dst, opc, src1, src2);
res.tag = RESULT_PREG;
res.u.reg.i = als & 0x1f;
res.u.reg.v = dst;
ctx->alc[chan] = res;
tcg_temp_free_i32(t0);
}
/*
@ -492,29 +587,20 @@ static uint16_t find_cond(DisasContext *ctx, int chan)
return 0;
}
static inline void gen_mrgc_i64(DisasContext *dc, int chan, TCGv_i64 ret)
static inline void gen_mrgc_i64(DisasContext *ctx, int chan, TCGv_i64 ret)
{
uint16_t rlp = find_mrgc(dc, chan);
TCGv_i64 t0;
TCGv_i64 t1;
TCGv_i64 inv;
uint16_t rlp = find_mrgc(ctx, chan);
TCGv_i64 inv = tcg_const_i64(GET_BIT(rlp, 7 + chan % 3));
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
if(rlp == 0) {
/* TODO: exception */
abort();
}
t0 = tcg_temp_new_i64();
t1 = tcg_temp_new_i64();
inv = tcg_const_i64(GET_BIT(rlp, 7 + chan % 3));
e2k_gen_cond_i64(dc, t0, rlp & 0x7f);
e2k_gen_cond_i64(ctx, t0, rlp & 0x7f);
tcg_gen_not_i64(t1, t0);
tcg_gen_movcond_i64(TCG_COND_EQ, ret, t0, inv, t0, t1);
tcg_temp_free_i64(inv);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(inv);
}
static inline void gen_mrgc_i32(DisasContext *dc, int chan, TCGv_i32 ret)
@ -525,90 +611,70 @@ static inline void gen_mrgc_i32(DisasContext *dc, int chan, TCGv_i32 ret)
tcg_temp_free(t0);
}
static inline void gen_rr_i64(TCGv_i64 ret, uint8_t state_reg)
static inline void gen_rr_i64(DisasContext *ctx, int chan)
{
uint32_t als = ctx->bundle.als[chan];
uint8_t state_reg = extract32(als, 16, 8);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
TCGv_i32 t0 = tcg_const_i32(state_reg);
gen_helper_state_reg_get(ret, cpu_env, t0);
gen_helper_state_reg_read_i64(dst, cpu_env, t0);
set_al_result_reg64(ctx, chan, dst);
tcg_temp_free_i32(t0);
}
static inline void gen_rrd(DisasContext *dc, int chan)
{
uint32_t als = dc->bundle.als[chan];
uint8_t state_reg = GET_FIELD(als, 16, 8);
TCGv_i64 ret = e2k_get_temp_i64(dc);
gen_rr_i64(ret, state_reg);
store_reg_alc_result(dc, chan, ret);
}
static inline void gen_rrs(DisasContext *dc, int chan)
{
uint32_t als = dc->bundle.als[chan];
uint8_t state_reg = GET_FIELD(als, 16, 8);
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = e2k_get_temp_i64(dc);
gen_rr_i64(t0, state_reg);
gen_movehl_i64(t1, t0, get_dst(dc, als));
store_reg_alc_result(dc, chan, t1);
tcg_temp_free_i64(t0);
}
static inline void gen_rw_i64(uint8_t state_reg, TCGv_i64 val)
static inline void gen_rr_i32(DisasContext *ctx, int chan)
{
uint32_t als = ctx->bundle.als[chan];
uint8_t state_reg = extract32(als, 16, 8);
TCGv_i32 dst = e2k_get_temp_i32(ctx);
TCGv_i32 t0 = tcg_const_i32(state_reg);
gen_helper_state_reg_set(cpu_env, t0, val);
gen_helper_state_reg_read_i32(dst, cpu_env, t0);
set_al_result_reg32(ctx, chan, dst);
tcg_temp_free_i32(t0);
}
static inline void gen_rwd(DisasContext *dc, int chan)
static inline void gen_rw_i64(DisasContext *ctx, int chan)
{
uint32_t als = dc->bundle.als[chan];
TCGv_i64 src2 = get_src2(dc, als);
gen_rw_i64(als & 0xff, src2);
uint32_t als = ctx->bundle.als[chan];
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i32 t0 = tcg_const_i32(als & 0xff);
// TODO: check tags
gen_helper_state_reg_write_i64(cpu_env, t0, s2.value);
tcg_temp_free_i32(t0);
}
static inline void gen_rws(DisasContext *dc, int chan)
static inline void gen_rw_i32(DisasContext *ctx, int chan)
{
uint32_t als = dc->bundle.als[chan];
uint8_t state_reg = als & 0xff;
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
uint32_t als = ctx->bundle.als[chan];
Src32 s2 = get_src2_i32(ctx, chan);
TCGv_i32 t0 = tcg_const_i32(als & 0xff);
gen_rr_i64(t0, state_reg);
gen_movehl_i64(t1, get_src2(dc, als), t0);
gen_rw_i64(state_reg, t1);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
// TODO: check tags
gen_helper_state_reg_write_i32(cpu_env, t0, s2.value);
tcg_temp_free_i32(t0);
}
static void gen_getsp(DisasContext *dc, int chan)
static void gen_getsp(DisasContext *ctx, int chan)
{
uint32_t als = dc->bundle.als[chan];
TCGv_i64 src2 = get_src2(dc, als);
TCGv_i64 t0 = e2k_get_temp_i64(dc);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
gen_helper_getsp(t0, cpu_env, src2);
store_reg_alc_result(dc, chan, t0);
// TODO: check tags
gen_helper_getsp(dst, cpu_env, s2.value);
set_al_result_reg64(ctx, chan, dst);
}
/* FIXME: movtd: don't know what it does */
static void gen_movtd(DisasContext *dc, int chan)
static void gen_movtd(DisasContext *ctx, int chan)
{
uint32_t als = dc->bundle.als[chan];
TCGv_i64 src2 = get_src2(dc, als);
TCGv_i64 t0 = e2k_get_temp_i64(dc);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
tcg_gen_mov_i64(t0, src2);
store_reg_alc_result(dc, chan, t0);
tcg_gen_mov_i64(dst, s2.value);
set_al_result_reg64(ctx, chan, dst);
}
static MemOp gen_mas(DisasContext *ctx, int chan, MemOp memop, TCGv_i64 addr)
@ -636,107 +702,123 @@ static MemOp gen_mas(DisasContext *ctx, int chan, MemOp memop, TCGv_i64 addr)
return memop;
}
static void gen_ld(DisasContext *dc, int chan, MemOp memop)
static void gen_ld(DisasContext *ctx, int chan, MemOp memop)
{
uint32_t als = dc->bundle.als[chan];
TCGv_i64 src1 = get_src1(dc, als);
TCGv_i64 src2 = get_src2(dc, als);
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = e2k_get_temp_i64(dc);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
tcg_gen_add_i64(t0, src1, src2);
memop = gen_mas(dc, chan, memop, t0);
tcg_gen_qemu_ld_i64(t1, t0, dc->mmuidx, memop);
store_reg_alc_result(dc, chan, t1);
// TODO: check tags
tcg_gen_add_i64(t0, s1.value, s2.value);
memop = gen_mas(ctx, chan, memop, t0);
tcg_gen_qemu_ld_i64(dst, t0, ctx->mmuidx, memop);
set_al_result_reg64(ctx, chan, dst);
tcg_temp_free_i64(t0);
}
static void gen_st(DisasContext *dc, int chan, MemOp memop)
static void gen_st(DisasContext *ctx, int chan, MemOp memop)
{
uint32_t als = dc->bundle.als[chan];
TCGv_i64 src1 = get_src1(dc, als);
TCGv_i64 src2 = get_src2(dc, als);
TCGv_i64 src4 = get_dst(dc, als);
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
Src64 s4 = get_src4_i64(ctx, chan);
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_add_i64(t0, src1, src2);
memop = gen_mas(dc, chan, memop, t0);
tcg_gen_qemu_st_i64(src4, t0, dc->mmuidx, memop);
// TODO: check tags
tcg_gen_add_i64(t0, s1.value, s2.value);
memop = gen_mas(ctx, chan, memop, t0);
tcg_gen_qemu_st_i64(s4.value, t0, ctx->mmuidx, memop);
tcg_temp_free_i64(t0);
}
static void gen_op2_i32(TCGv_i64 ret, TCGv_i64 s1, TCGv_i64 s2, TCGv_i64 dst,
static void gen_alopf1_i32(DisasContext *ctx, int chan,
void (*op)(TCGv_i32, TCGv_i32, TCGv_i32))
{
TCGv_i32 lo1 = tcg_temp_new_i32();
TCGv_i32 lo2 = tcg_temp_new_i32();
TCGv_i32 dst_hi = tcg_temp_new_i32();
TCGv_i32 tmp = tcg_temp_new_i32();
Src32 s1 = get_src1_i32(ctx, chan);
Src32 s2 = get_src2_i32(ctx, chan);
TCGv_i32 dst = e2k_get_temp_i32(ctx);
tcg_gen_extrl_i64_i32(lo1, s1);
tcg_gen_extrl_i64_i32(lo2, s2);
tcg_gen_extrh_i64_i32(dst_hi, dst);
(*op)(tmp, lo1, lo2);
tcg_gen_concat_i32_i64(ret, tmp, dst_hi);
tcg_temp_free_i32(tmp);
tcg_temp_free_i32(dst_hi);
tcg_temp_free_i32(lo2);
tcg_temp_free_i32(lo1);
// TODO: check tags
(*op)(dst, s1.value, s2.value);
set_al_result_reg32(ctx, chan, dst);
}
static void gen_alopf1_i32(DisasContext *dc, int chan,
void (*op)(TCGv_i32, TCGv_i32, TCGv_i32))
{
uint32_t als = dc->bundle.als[chan];
TCGv_i64 t0 = e2k_get_temp_i64(dc);
gen_op2_i32(t0, get_src1(dc, als), get_src2(dc, als), get_dst(dc, als), op);
store_reg_alc_result(dc, chan, t0);
}
static void gen_alopf1_i64(DisasContext *dc, int chan,
static void gen_alopf1_i64(DisasContext *ctx, int chan,
void (*op)(TCGv_i64, TCGv_i64, TCGv_i64))
{
uint32_t als = dc->bundle.als[chan];
TCGv_i64 t0 = e2k_get_temp_i64(dc);
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
(*op)(t0, get_src1(dc, als), get_src2(dc, als));
store_reg_alc_result(dc, chan, t0);
// TODO: check tags
(*op)(dst, s1.value, s2.value);
set_al_result_reg64(ctx, chan, dst);
}
static void gen_alopf1_mrgc_i32(DisasContext *dc, int chan)
static void gen_alopf1_cmp_i64(DisasContext *ctx, int chan,
void (*op)(TCGv_i64, int, TCGv_i64, TCGv_i64))
{
uint32_t als = dc->bundle.als[chan];
TCGv_i64 src1 = get_src1(dc, als);
TCGv_i64 src2 = get_src2(dc, als);
TCGv_i64 dst = get_dst(dc, als);
uint32_t als = ctx->bundle.als[chan];
int opc = extract32(als, 5, 3);
int idx = extract32(als, 0, 5);
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
// TODO: check tags
(*op)(dst, opc, s1.value, s2.value);
set_al_result_preg(ctx, chan, idx, dst);
}
static void gen_alopf1_cmp_i32(DisasContext *ctx, int chan,
void (*op)(TCGv_i32, int, TCGv_i32, TCGv_i32))
{
uint32_t als = ctx->bundle.als[chan];
int opc = extract32(als, 5, 3);
int idx = extract32(als, 0, 5);
Src32 s1 = get_src1_i32(ctx, chan);
Src32 s2 = get_src2_i32(ctx, chan);
TCGv_i64 dst = e2k_get_temp_i64(ctx);
TCGv_i32 t0 = tcg_temp_new_i32();
// TODO: check tags
(*op)(t0, opc, s1.value, s2.value);
tcg_gen_extu_i32_i64(dst, t0);
tcg_temp_free_i32(t0);
set_al_result_preg(ctx, chan, idx, dst);
}
static void gen_alopf1_mrgc_i32(DisasContext *ctx, int chan)
{
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i32 dst = e2k_get_temp_i32(ctx);
TCGv_i64 cond = tcg_temp_new_i64();
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = e2k_get_temp_i64(dc);
TCGv_i64 cond = tcg_temp_new_i64();
gen_mrgc_i64(dc, chan, cond);
gen_merge_i64(t0, src1, src2, cond);
gen_movehl_i64(t1, t0, dst);
store_reg_alc_result(dc, chan, t1);
// TODO: check tags
gen_mrgc_i64(ctx, chan, cond);
gen_merge_i64(t0, s1.value, s2.value, cond);
tcg_gen_extrl_i64_i32(dst, t0);
set_al_result_reg32(ctx, chan, dst);
tcg_temp_free_i64(cond);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(cond);
}
static void gen_alopf1_mrgc_i64(DisasContext *dc, int chan)
static void gen_alopf1_mrgc_i64(DisasContext *ctx, int chan)
{
uint32_t als = dc->bundle.als[chan];
TCGv_i64 src1 = get_src1(dc, als);
TCGv_i64 src2 = get_src2(dc, als);
TCGv_i64 t0 = e2k_get_temp_i64(dc);
Src64 s1 = get_src1_i64(ctx, chan);
Src64 s2 = get_src2_i64(ctx, chan);
TCGv_i64 cond = tcg_temp_new_i64();
TCGv_i64 dst = e2k_get_temp_i64(ctx);
gen_mrgc_i64(dc, chan, cond);
gen_merge_i64(t0, src1, src2, cond);
store_reg_alc_result(dc, chan, t0);
// TODO: check tags
gen_mrgc_i64(ctx, chan, cond);
gen_merge_i64(dst, s1.value, s2.value, cond);
set_al_result_reg64(ctx, chan, dst);
tcg_temp_free_i64(cond);
}
@ -782,28 +864,28 @@ static void execute_alopf_simple(DisasContext *dc, int chan)
if (chan == 2 || chan == 5) {
abort();
} else {
gen_cmpsb(dc, chan); /* cmp{op}sb */
gen_alopf1_cmp_i32(dc, chan, gen_cmp_i32); /* cmp{op}sb */
}
break;
case 0x21:
if (chan == 2 || chan == 5) {
abort();
} else {
gen_cmpdb(dc, chan); /* cmp{op}db */
gen_alopf1_cmp_i64(dc, chan, gen_cmp_i64); /* cmp{op}db */
}
break;
case 0x22:
if (chan == 2 || chan == 5) {
abort();
} else {
gen_cmpandsb(dc, chan); /* cmpand{op}sb */
gen_alopf1_cmp_i32(dc, chan, gen_cmpand_i32); /* cmpand{op}sb */
}
break;
case 0x23:
if (chan == 2 || chan == 5) {
abort();
} else {
gen_cmpanddb(dc, chan); /* cmpand{op}db */
gen_alopf1_cmp_i64(dc, chan, gen_cmpand_i64); /* cmpand{op}db */
}
break;
case 0x24: { /* stb */
@ -842,8 +924,8 @@ static void execute_alopf_simple(DisasContext *dc, int chan)
if (chan == 5) {
// FIXME: temp hack
TCGLabel *l0 = gen_new_label();
TCGv_i64 src2 = get_src2(dc, als);
tcg_gen_brcondi_i64(TCG_COND_NE, src2, 0, l0);
Src64 s2 = get_src2_i64(dc, chan);
tcg_gen_brcondi_i64(TCG_COND_NE, s2.value, 0, l0);
e2k_gen_exception(0);
gen_set_label(l0);
@ -930,17 +1012,17 @@ static void execute_ext1(DisasContext *dc, int chan)
/* TODO: exception */
break;
}
case 0x3c: /* rws */ gen_rws(dc, chan); break; /* TODO: only channel 1 */
case 0x3d: /* rwd */ gen_rwd(dc, chan); break; /* TODO: only channel 1 */
case 0x3e: /* rrs */ gen_rrs(dc, chan); break; /* TODO: only channel 1 */
case 0x3f: /* rrd */ gen_rrd(dc, chan); break; /* TODO: only channel 1 */
case 0x3c: /* rws */ gen_rw_i32(dc, chan); break; /* TODO: only channel 1 */
case 0x3d: /* rwd */ gen_rw_i64(dc, chan); break; /* TODO: only channel 1 */
case 0x3e: /* rrs */ gen_rr_i32(dc, chan); break; /* TODO: only channel 1 */
case 0x3f: /* rrd */ gen_rr_i64(dc, chan); break; /* TODO: only channel 1 */
default:
/* TODO: exception */
break;
}
}
void e2k_execute_alc(DisasContext *ctx, int chan)
void e2k_alc_execute(DisasContext *ctx, int chan)
{
const UnpackedBundle *bundle = &ctx->bundle;
uint16_t rlp = find_cond(ctx, chan);
@ -986,6 +1068,47 @@ void e2k_execute_alc(DisasContext *ctx, int chan)
gen_set_label(l0);
ctx->alc[chan].has_cond = rlp != 0;
ctx->alc[chan].cond = cond;
ctx->al_cond[chan].is_set = rlp != 0;
ctx->al_cond[chan].value = cond;
}
void e2k_alc_commit(DisasContext *ctx)
{
unsigned int i;
for (i = 0; i < 6; i++) {
TCGLabel *l0;
AlResult *res = &ctx->al_results[i];
AlCond *cond = &ctx->al_cond[i];
if (!ctx->bundle.als_present[i]) {
continue;
}
if (res->type != AL_RESULT_NONE && cond->is_set) {
l0 = gen_new_label();
tcg_gen_brcondi_i64(TCG_COND_EQ, cond->value, 0, l0);
}
switch(res->type) {
case AL_RESULT_REG32:
e2k_gen_reg_tag_write_i32(res->reg.tag, res->reg.index);
e2k_gen_reg_write_i32(res->reg.v32, res->reg.index);
break;
case AL_RESULT_REG64:
e2k_gen_reg_tag_write_i64(res->reg.tag, res->reg.index);
e2k_gen_reg_write_i64(res->reg.v64, res->reg.index);
break;
case AL_RESULT_PREG:
// TODO: write predicate register tag
e2k_gen_store_preg(res->preg.index, res->preg.value);
break;
default:
break;
}
if (res->type != AL_RESULT_NONE && cond->is_set) {
gen_set_label(l0);
}
}
}

View File

@ -104,7 +104,7 @@ void e2k_plu_execute(DisasContext *ctx)
for (i = 0; i < 3; i++) {
if (!bundle->pls_present[i]) {
ctx->plu[i].reg = -1;
ctx->pl_results[i].reg = -1;
continue;
}
@ -138,8 +138,8 @@ void e2k_plu_execute(DisasContext *ctx)
gen_get_lp(p1, clp, 6, lp);
if (vdst) {
ctx->plu[i].reg = pdst;
ctx->plu[i].value = e2k_get_temp_i32(ctx);
ctx->pl_results[i].reg = pdst;
ctx->pl_results[i].value = e2k_get_temp_i32(ctx);
}
switch (opc) {
@ -148,7 +148,7 @@ void e2k_plu_execute(DisasContext *ctx)
case 1: /* landp */
tcg_gen_and_i32(lp[4 + i], p0, p1);
if (vdst) {
tcg_gen_mov_i32(ctx->plu[i].value, lp[4 + i]);
tcg_gen_mov_i32(ctx->pl_results[i].value, lp[4 + i]);
}
break;
case 3: { /* movep */
@ -162,7 +162,7 @@ void e2k_plu_execute(DisasContext *ctx)
e2k_gen_preg(t0, pdst);
tcg_gen_extrl_i64_i32(t1, t0);
tcg_gen_movcond_i32(TCG_COND_EQ, ctx->plu[i].value,
tcg_gen_movcond_i32(TCG_COND_EQ, ctx->pl_results[i].value,
p0, one, p1, t1);
tcg_temp_free_i32(t1);
@ -192,14 +192,14 @@ void e2k_plu_commit(DisasContext *ctx)
for (i = 0; i < 3; i++) {
TCGv_i64 t0;
if (ctx->plu[i].reg < 0) {
if (ctx->pl_results[i].reg < 0) {
continue;
}
t0 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, ctx->plu[i].value);
e2k_gen_store_preg(ctx->plu[i].reg, t0);
tcg_gen_extu_i32_i64(t0, ctx->pl_results[i].value);
e2k_gen_store_preg(ctx->pl_results[i].reg, t0);
tcg_temp_free_i64(t0);
}

View File

@ -3,110 +3,12 @@
#include "exec/log.h"
#include "translate.h"
#define TAG_MASK GEN_MASK(0, TAG_BITS)
static inline void gen_tag_group_index(TCGv_i64 ret, TCGv_i64 idx)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_shri_i64(t0, idx, 4);
tcg_gen_shli_i64(ret, t0, 3);
tcg_temp_free_i64(t0);
}
static inline void gen_tag_offset_in_group(TCGv_i64 ret, TCGv_i64 idx)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_andi_i64(t0, idx, TAG_MASK);
tcg_gen_muli_i64(ret, t0, TAG_BITS);
tcg_temp_free_i64(t0);
}
static inline void gen_tag_group_get(TCGv_i64 ret, TCGv_ptr tags, TCGv_i64 idx)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
TCGv_ptr t1 = tcg_temp_new_ptr();
tcg_gen_trunc_i64_ptr(t0, idx);
tcg_gen_add_ptr(t1, tags, t0);
tcg_gen_ld_i64(ret, t1, 0);
tcg_temp_free_ptr(t1);
tcg_temp_free_ptr(t0);
}
static inline void get_tag_group_set(TCGv_ptr tags, TCGv_i64 idx,
TCGv_i64 group)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
TCGv_ptr t1 = tcg_temp_new_ptr();
tcg_gen_trunc_i64_ptr(t0, idx);
tcg_gen_add_ptr(t1, tags, t0);
tcg_gen_st_i64(group, t1, 0);
tcg_temp_free_ptr(t1);
tcg_temp_free_ptr(t0);
}
static inline void gen_tag_group_extract(TCGv_i64 ret, TCGv_i64 group,
TCGv_i64 offset)
{
TCGv_i64 t0 = tcg_const_i64(TAG_BITS);
e2k_gen_extract_i64(ret, group, offset, t0);
tcg_temp_free_i64(t0);
}
static inline void gen_tag_group_deposit(TCGv_i64 ret, TCGv_i64 group,
TCGv_i64 tag, TCGv_i64 offset)
{
TCGv_i64 t0 = tcg_const_i64(TAG_BITS);
e2k_gen_deposit_i64(ret, group, tag, offset, t0);
tcg_temp_free_i64(t0);
}
static inline void gen_tag_get(TCGv_i64 ret, TCGv_ptr tags, TCGv_i64 idx)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
gen_tag_group_index(t0, idx);
gen_tag_group_get(t1, tags, t0);
gen_tag_offset_in_group(t2, idx);
gen_tag_group_extract(ret, t1, t2);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
static inline void gen_tag_set(TCGv_ptr tags, TCGv_i64 idx, TCGv_i64 tag)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
TCGv_i64 t3 = tcg_temp_new_i64();
gen_tag_group_index(t0, idx);
gen_tag_group_get(t1, tags, t0);
gen_tag_offset_in_group(t2, idx);
gen_tag_group_deposit(t3, t1, tag, t2);
get_tag_group_set(tags, t0, t3);
tcg_temp_free_i64(t3);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
static void gen_preg_offset(TCGv_i64 ret, int reg)
{
assert(reg < 32);
TCGv_i32 zero = tcg_const_i32(0);
TCGv_i32 pf_size = tcg_const_i32(PF_SIZE);
TCGv_i32 pf_size = tcg_const_i32(E2K_PR_COUNT);
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
@ -167,14 +69,14 @@ TCGv_i64 e2k_get_preg(DisasContext *dc, int reg)
return ret;
}
void e2k_gen_store_preg(int reg, TCGv_i64 val)
void e2k_gen_store_preg(int idx, TCGv_i64 val)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
TCGv_i64 t3 = tcg_temp_new_i64();
gen_preg_offset(t0, reg);
gen_preg_offset(t0, idx);
gen_preg_clear(t1, t0);
tcg_gen_setcondi_i64(TCG_COND_NE, t2, val, 0);
tcg_gen_shl_i64(t3, t2, t0);
@ -186,220 +88,234 @@ void e2k_gen_store_preg(int reg, TCGv_i64 val)
tcg_temp_free_i64(t0);
}
static inline void gen_wreg_index(TCGv_i32 ret, TCGv_i32 reg)
static inline void gen_reg_tags_group_ptr(TCGv_ptr ret, TCGv_i32 idx)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_const_i32(WREGS_SIZE);
TCGv_i32 t0 = tcg_const_i32(E2K_TAGS_PER_REG);
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
TCGv_ptr t3 = tcg_temp_new_ptr();
tcg_gen_add_i32(t0, e2k_cs.wd_base, reg);
tcg_gen_remu_i32(ret, t0, t1);
tcg_temp_free_i32(t1);
tcg_gen_divu_i32(t1, idx, t0);
tcg_temp_free_i32(t0);
tcg_gen_muli_i32(t2, t1, E2K_REG_LEN);
tcg_temp_free_i32(t1);
tcg_gen_ext_i32_ptr(t3, t2);
tcg_temp_free_i32(t2);
tcg_gen_add_ptr(ret, e2k_cs.tptr, t3);
tcg_temp_free_ptr(t3);
}
static inline void gen_wreg_ptr(TCGv_ptr ret, TCGv_i32 reg)
static inline void gen_reg_tags_group_offset(TCGv_i64 ret, TCGv_i32 idx)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, idx);
tcg_gen_andi_i64(t1, t0, E2K_TAGS_PER_REG - 1);
tcg_temp_free_i64(t0);
tcg_gen_muli_i64(ret, t1, E2K_REG_TAGS_SIZE);
tcg_temp_free_i64(t1);
}
static inline void gen_reg_tags_read(TCGv_i32 ret, TCGv_i32 idx, int len)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
TCGv_i64 t3 = tcg_const_i64(len);
TCGv_i64 t4 = tcg_temp_new_i64();
gen_reg_tags_group_ptr(t0, idx);
tcg_gen_ld_i64(t1, t0, 0);
tcg_temp_free_ptr(t0);
gen_reg_tags_group_offset(t2, idx);
e2k_gen_extract_i64(t4, t1, t2, t3);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t3);
tcg_gen_extrl_i64_i32(ret, t4);
tcg_temp_free_i64(t4);
}
void e2k_gen_reg_tag_read_i64(TCGv_i32 ret, TCGv_i32 idx)
{
gen_reg_tags_read(ret, idx, E2K_REG_TAGS_SIZE);
}
void e2k_gen_reg_tag_read_i32(TCGv_i32 ret, TCGv_i32 idx)
{
gen_reg_tags_read(ret, idx, E2K_TAG_SIZE);
}
static inline void gen_tag_check(TCGv_i32 ret, TCGv_i32 tag)
{
// FIXME: what CPU does if tag is greater than 1?
tcg_gen_setcondi_i32(TCG_COND_GTU, ret, tag, 0);
}
void e2k_gen_reg_tag_check_i64(TCGv_i32 ret, TCGv_i32 tag)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_ptr t2 = tcg_temp_new_ptr();
TCGv_i32 t2 = tcg_temp_new_i32();
TCGv_i32 t3 = tcg_temp_new_i32();
gen_wreg_index(t0, reg);
tcg_gen_muli_i32(t1, t0, 8);
tcg_gen_ext_i32_ptr(t2, t1);
tcg_gen_add_ptr(ret, e2k_cs.wptr, t2);
tcg_temp_free_ptr(t2);
e2k_gen_reg_tag_extract_lo(t0, tag);
gen_tag_check(t1, t0);
tcg_temp_free_i32(t0);
e2k_gen_reg_tag_extract_hi(t2, tag);
gen_tag_check(t3, t2);
tcg_temp_free_i32(t2);
tcg_gen_or_i32(ret, t1, t3);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(t3);
}
static inline void gen_wregi_ptr(TCGv_ptr ret, int reg)
void e2k_gen_reg_tag_check_i32(TCGv_i32 ret, TCGv_i32 tag)
{
TCGv_i32 t0 = tcg_const_i32(reg);
gen_wreg_ptr(ret, t0);
tcg_temp_free_i32(t0);
gen_tag_check(ret, tag);
}
static inline void gen_wreg_check(DisasContext *ctx, int reg)
static inline void gen_reg_tags_write(TCGv_i32 value, TCGv_i32 idx, int len)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
TCGv_i64 t3 = tcg_temp_new_i64();
TCGv_i64 t4 = tcg_const_i64(len);
TCGv_i64 t5 = tcg_temp_new_i64();
gen_reg_tags_group_ptr(t0, idx);
tcg_gen_ld_i64(t1, t0, 0);
tcg_gen_extu_i32_i64(t2, value);
gen_reg_tags_group_offset(t3, idx);
e2k_gen_deposit_i64(t5, t1, t2, t3, t4);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t3);
tcg_temp_free_i64(t4);
tcg_gen_st_i64(t5, t0, 0);
tcg_temp_free_ptr(t0);
tcg_temp_free_i64(t5);
}
void e2k_gen_reg_tag_write_i64(TCGv_i32 value, TCGv_i32 idx)
{
gen_reg_tags_write(value, idx, E2K_REG_TAGS_SIZE);
}
void e2k_gen_reg_tag_write_i32(TCGv_i32 value, TCGv_i32 idx)
{
gen_reg_tags_write(value, idx, E2K_TAG_SIZE);
}
static inline void gen_reg_index_from_wreg(TCGv_i32 ret, TCGv_i32 idx)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_local_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2;
assert(reg < 64);
tcg_gen_mov_i32(t0, idx);
tcg_gen_brcondi_i32(TCG_COND_GTU, e2k_cs.wd_size, reg, l0);
tcg_gen_brcond_i32(TCG_COND_LTU, t0, e2k_cs.wd_size, l0);
e2k_gen_exception(E2K_EXCP_MAPERR);
gen_set_label(l0);
tcg_gen_add_i32(t1, e2k_cs.wd_base, t0);
tcg_temp_free_i32(t0);
t2 = tcg_const_i32(E2K_NR_COUNT);
tcg_gen_remu_i32(ret, t1, t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
}
TCGv_i64 e2k_get_wreg(DisasContext *ctx, int reg)
void e2k_gen_reg_index_from_wregi(TCGv_i32 ret, int idx)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
TCGv_i64 t1 = e2k_get_temp_i64(ctx);
gen_wreg_check(ctx, reg);
gen_wregi_ptr(t0, reg);
tcg_gen_ld_i64(t1, t0, 0);
tcg_temp_free_ptr(t0);
return t1;
}
void e2k_gen_store_wreg(DisasContext *ctx, int reg, TCGv_i64 val)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
gen_wreg_check(ctx, reg);
gen_wregi_ptr(t0, reg);
tcg_gen_st_i64(val, t0, 0);
tcg_temp_free_ptr(t0);
}
void e2k_gen_wtag_get(TCGv_i64 ret, TCGv_i32 idx)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i64 t1 = tcg_temp_new_i64();
gen_wreg_index(t0, idx);
tcg_gen_extu_i32_i64(t1, t0);
gen_tag_get(ret, e2k_cs.wptr, t1);
tcg_temp_free_i64(t1);
TCGv_i32 t0 = tcg_const_i32(idx);
gen_reg_index_from_wreg(ret, t0);
tcg_temp_free_i32(t0);
}
void e2k_gen_wtagi_get(TCGv_i64 ret, int reg)
{
TCGv_i32 t0 = tcg_const_i32(reg);
e2k_gen_wtag_get(ret, t0);
tcg_temp_free_i32(t0);
}
/* register index must be valid */
void e2k_gen_wtag_set(TCGv_i32 idx, TCGv_i64 tag)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i64 t1 = tcg_temp_new_i64();
gen_wreg_index(t0, idx);
tcg_gen_extu_i32_i64(t1, t0);
gen_tag_set(e2k_cs.tptr, t1, tag);
tcg_temp_free_i64(t1);
tcg_temp_free_i32(t0);
}
/* register index must be valid */
void e2k_gen_wtagi_set(int reg, TCGv_i64 tag)
{
TCGv_i32 t0 = tcg_const_i32(reg);
e2k_gen_wtag_set(t0, tag);
tcg_temp_free_i32(t0);
}
static inline void gen_breg_index(TCGv_i32 ret, int idx)
void e2k_gen_reg_index_from_bregi(TCGv_i32 ret, int idx)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
tcg_gen_brcondi_i32(tcg_invert_cond(TCG_COND_LTU), e2k_cs.bsize, idx, l0);
e2k_gen_exception(E2K_EXCP_MAPERR);
gen_set_label(l0);
tcg_gen_addi_i32(t0, e2k_cs.bcur, idx);
tcg_gen_remu_i32(t1, t0, e2k_cs.bsize);
tcg_gen_add_i32(ret, t1, e2k_cs.boff);
tcg_temp_free_i32(t0);
tcg_gen_add_i32(t2, e2k_cs.boff, t1);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
gen_reg_index_from_wreg(ret, t2);
tcg_temp_free_i32(t2);
}
static inline void gen_bregi_ptr(DisasContext *ctx, TCGv_ptr ret, int idx)
void e2k_gen_reg_index_from_gregi(TCGv_i32 ret, int idx)
{
TCGLabel *l0 = gen_new_label();
TCGLabel *l1 = gen_new_label();
TCGv_i32 t0 = tcg_temp_new_i32();
assert(idx < 128);
tcg_gen_brcondi_i32(TCG_COND_LEU, e2k_cs.bsize, idx, l0);
tcg_gen_add_i32(t0, e2k_cs.boff, e2k_cs.bsize);
tcg_gen_brcond_i32(TCG_COND_LTU, e2k_cs.wd_size, t0, l0);
tcg_gen_br(l1);
gen_set_label(l0);
e2k_gen_exception(E2K_EXCP_MAPERR);
gen_set_label(l1);
gen_breg_index(t0, idx);
gen_wreg_ptr(ret, t0);
tcg_temp_free_i32(t0);
// TODO: based global registers index
tcg_gen_movi_i32(ret, E2K_NR_COUNT + idx);
}
TCGv_i64 e2k_get_breg(DisasContext *ctx, int reg)
{
TCGv_i64 ret = e2k_get_temp(ctx);
TCGv_ptr ptr = tcg_temp_new_ptr();
gen_bregi_ptr(ctx, ptr, reg);
tcg_gen_ld_i64(ret, ptr, 0);
tcg_temp_free_ptr(ptr);
return ret;
}
void e2k_gen_store_breg(DisasContext *ctx, int reg, TCGv_i64 val)
{
TCGv_ptr ptr = tcg_temp_new_ptr();
gen_bregi_ptr(ctx, ptr, reg);
tcg_gen_st_i64(val, ptr, 0);
tcg_temp_free_ptr(ptr);
}
/* register index must be valid */
void e2k_gen_btag_get(TCGv_i64 ret, int reg)
static inline void gen_reg_ptr_from_index(TCGv_ptr ret, TCGv_i32 idx)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_ptr t1 = tcg_temp_new_ptr();
gen_breg_index(t0, reg);
e2k_gen_wtag_get(ret, t0);
tcg_gen_muli_i32(t0, idx, 8);
tcg_gen_ext_i32_ptr(t1, t0);
tcg_gen_add_ptr(ret, e2k_cs.rptr, t1);
tcg_temp_free_ptr(t1);
tcg_temp_free_i32(t0);
}
/* register index must be valid */
void e2k_gen_btag_set(int reg, TCGv_i64 tag)
void e2k_gen_reg_read_i64(TCGv_i64 ret, TCGv_i32 idx)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_ptr t0 = tcg_temp_new_ptr();
gen_breg_index(t0, reg);
e2k_gen_wtag_set(t0, tag);
tcg_temp_free_i32(t0);
gen_reg_ptr_from_index(t0, idx);
tcg_gen_ld_i64(ret, t0, 0);
tcg_temp_free_ptr(t0);
}
TCGv_i64 e2k_get_greg(DisasContext *dc, int reg)
void e2k_gen_reg_read_i32(TCGv_i32 ret, TCGv_i32 idx)
{
assert(reg < GREGS_MAX + BGREGS_MAX);
return e2k_cs.gregs[reg];
TCGv_ptr t0 = tcg_temp_new_ptr();
gen_reg_ptr_from_index(t0, idx);
tcg_gen_ld_i32(ret, t0, 0);
tcg_temp_free_ptr(t0);
}
void e2k_gen_store_greg(int reg, TCGv_i64 val)
void e2k_gen_reg_write_i64(TCGv_i64 value, TCGv_i32 idx)
{
assert(reg < GREGS_MAX + BGREGS_MAX);
tcg_gen_mov_i64(e2k_cs.gregs[reg], val);
}
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_ptr t1 = tcg_temp_new_ptr();
void e2k_gen_gtag_get(TCGv_i64 ret, int reg)
{
TCGv_i64 group = e2k_cs.gtags[reg / TAGS_PER_REG];
TCGv_i64 t0 = tcg_const_i64((reg & TAG_MASK) * TAG_BITS);
gen_tag_group_extract(ret, group, t0);
tcg_gen_mov_i64(t0, value);
gen_reg_ptr_from_index(t1, idx);
tcg_gen_st_i64(t0, t1, 0);
tcg_temp_free_ptr(t1);
tcg_temp_free_i64(t0);
}
void e2k_gen_gtag_set(int reg, TCGv_i64 tag)
void e2k_gen_reg_write_i32(TCGv_i32 value, TCGv_i32 idx)
{
TCGv_i64 group = e2k_cs.gtags[reg / TAGS_PER_REG];
TCGv_i64 t0 = tcg_const_i64((reg & TAG_MASK) * TAG_BITS);
gen_tag_group_deposit(group, group, tag, t0);
tcg_temp_free_i64(t0);
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_ptr t1 = tcg_temp_new_ptr();
tcg_gen_mov_i32(t0, value);
gen_reg_ptr_from_index(t1, idx);
tcg_gen_st_i32(t0, t1, 0);
tcg_temp_free_ptr(t1);
tcg_temp_free_i32(t0);
}