e2k: Remove control.c

This commit is contained in:
Denis Drakhnia 2021-01-22 00:20:49 +02:00 committed by Denis Drakhnia
parent 0b7f461be7
commit 23a0139ee6
13 changed files with 955 additions and 997 deletions

View File

@ -58,6 +58,7 @@ typedef enum {
} CtprTag;
typedef enum {
CTPR_OPC_DISP = 0x0,
CTPR_OPC_LDISP = 0x1,
} CtprOpc;
@ -618,7 +619,14 @@ typedef struct CPUArchState {
E2KBnState bn;
E2KBpState bp;
uint64_t lsr; /* loop status register */
/* loop status register */
uint64_t lsr;
uint32_t lsr_lcnt;
uint32_t lsr_ecnt;
uint32_t lsr_vlc;
uint32_t lsr_over;
uint32_t lsr_pcnt;
uint32_t lsr_strmd;
uint64_t sbr;
E2KUserStackDesc usd;

View File

@ -174,7 +174,16 @@ int e2k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
case 344: return gdb_get_reg64(mem_buf, 0); // cutd
case 345: return gdb_get_reg64(mem_buf, 0); // cuir
case 346: return gdb_get_reg64(mem_buf, 0); // tsd
case 347: return gdb_get_reg64(mem_buf, env->lsr); // lsr
case 347: { // lsr
uint64_t lsr = env->lsr;
lsr = deposit64(lsr, LSR_LCNT_OFF, LSR_LCNT_LEN, env->lsr_lcnt);
lsr = deposit64(lsr, LSR_ECNT_OFF, LSR_ECNT_LEN, env->lsr_ecnt);
lsr = deposit64(lsr, LSR_VLC_OFF, 1, env->lsr_vlc);
lsr = deposit64(lsr, LSR_OVER_OFF, 1, env->lsr_over);
lsr = deposit64(lsr, LSR_PCNT_OFF, LSR_PCNT_LEN, env->lsr_pcnt);
lsr = deposit64(lsr, LSR_STRMD_OFF, LSR_STRMD_LEN, env->lsr_strmd);
return gdb_get_reg64(mem_buf, lsr);
}
case 348: return gdb_get_reg64(mem_buf, env->lsr & LSR_ILCR_MASK); // ilcr
default:
break;

View File

@ -127,7 +127,12 @@ static void ps_fill(CPUE2KState *env, int n, bool fx)
static inline void ps_spill_all(CPUE2KState *env)
{
ps_spill(env, env->wd.size, env->wd.fx);
ps_spill(env, env->wd.size, true);
}
static inline void ps_fill_all(CPUE2KState *env)
{
ps_fill(env, env->wd.size, true);
}
static void move_regs(CPUE2KState *env, int dst, int src, int n)
@ -225,26 +230,22 @@ void HELPER(raise_exception_no_spill)(CPUE2KState *env, int tt)
cpu_loop_exit(cs);
}
void HELPER(setwd)(CPUE2KState *env, uint32_t lts)
void HELPER(setwd)(CPUE2KState *env, int wsz, int nfx, int dbl)
{
int i, old_size = env->wd.size, size = extract32(lts, 5, 7) * 2;
int i, size = wsz * 2;
if (size < env->wd.psize) {
helper_raise_exception(env, E2K_EXCP_ILLOPN);
return;
}
for (i = env->wd.size; i < size; i++) {
env->tags[i] = E2K_TAG_NON_NUMBER64;
}
env->wd.size = size;
env->wd.fx = extract32(lts, 4, 1) == 0;
if (env->version >= 3) {
bool dbl = extract32(lts, 3, 1);
env->wdbl = dbl;
}
for (i = 0; i < size - old_size; i++) {
env->tags[old_size + i] = E2K_TAG_NON_NUMBER64;
}
env->wd.fx = nfx == 0;
env->wdbl = dbl;
}
bool e2k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
@ -270,7 +271,7 @@ void e2k_break_save_state(CPUE2KState *env)
void HELPER(break_restore_state)(CPUE2KState *env)
{
proc_chain_restore(env);
ps_fill(env, env->wd.size, env->wd.fx);
ps_fill_all(env);
env->is_bp = false;
}

View File

@ -22,7 +22,7 @@ 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, i32) /* FIXME: return tl? */
DEF_HELPER_1(break_restore_state, void, env)
DEF_HELPER_2(setwd, void, env, i32)
DEF_HELPER_4(setwd, void, env, int, int, int)
DEF_HELPER_2(probe_read_access, int, env, tl)
DEF_HELPER_2(probe_write_access, int, env, tl)

View File

@ -34,7 +34,6 @@ static uint64_t* state_reg_ptr(CPUE2KState *env, int idx)
{
switch (idx) {
case 0x80: return &env->upsr; /* %upsr */
case 0x83: return &env->lsr; /* %lsr */
default: return NULL;
}
}
@ -78,6 +77,15 @@ uint32_t helper_state_reg_read_i32(CPUE2KState *env, int idx)
void helper_state_reg_write_i64(CPUE2KState *env, int idx, uint64_t val)
{
switch(idx) {
case 0x83: /* %lsr */
env->lsr = val;
env->lsr_lcnt = extract64(val, LSR_LCNT_OFF, LSR_LCNT_LEN);
env->lsr_ecnt = extract64(val, LSR_ECNT_OFF, LSR_ECNT_LEN);
env->lsr_vlc = extract64(val, LSR_VLC_OFF, 1);
env->lsr_over = extract64(val, LSR_OVER_OFF, 1);
env->lsr_pcnt = extract64(val, LSR_PCNT_OFF, LSR_PCNT_LEN);
env->lsr_strmd = extract64(val, LSR_STRMD_OFF, LSR_STRMD_LEN);
break;
case 0x85: /* %fpcr */
env->fpcr.raw = val;
e2k_update_fp_status(env);
@ -100,6 +108,9 @@ void helper_state_reg_write_i64(CPUE2KState *env, int idx, uint64_t val)
void helper_state_reg_write_i32(CPUE2KState *env, int idx, uint32_t val)
{
switch (idx) {
case 0x83: /* %lsr */
env->lsr_lcnt = val;
break;
case 0x85: /* %fpcr */
env->fpcr.raw = val;
e2k_update_fp_status(env);

View File

@ -11,7 +11,6 @@ e2k_ss.add(files(
'translate.c',
'translate/alc.c',
'translate/aau.c',
'translate/control.c',
'translate/plu.c',
'translate/state.c',
))

View File

@ -6,6 +6,68 @@
struct CPUE2KStateTCG e2k_cs;
static inline uint64_t ctpr_new(uint8_t tag, uint8_t opc, uint8_t ipd,
target_ulong base)
{
uint64_t ctpr = 0;
ctpr = deposit64(ctpr, CTPR_BASE_OFF, CTPR_BASE_LEN, base);
ctpr = deposit64(ctpr, CTPR_TAG_OFF, CTPR_TAG_LEN, tag);
ctpr = deposit64(ctpr, CTPR_IPD_OFF, CTPR_IPD_LEN, ipd);
ctpr = deposit64(ctpr, CTPR_OPC_OFF, CTPR_OPC_LEN, opc);
return ctpr;
}
static inline uint64_t ctpr_new_disp(DisasContext *ctx, Cs0Disp *disp)
{
target_ulong base = ctx->pc + disp->sdisp;
return ctpr_new(CTPR_TAG_DISP, disp->opc, disp->ipd, base);
}
static void gen_goto_tb(DisasContext *ctx, int tb_num, target_ulong pc)
{
if (translator_use_goto_tb(&ctx->base, pc)) {
/* jump to same page: we can use a direct jump */
tcg_gen_goto_tb(tb_num);
tcg_gen_movi_tl(e2k_cs.pc, pc);
tcg_gen_exit_tb(ctx->base.tb, tb_num);
} else {
/* jump to another page: currently not optimized */
tcg_gen_movi_tl(e2k_cs.pc, pc);
tcg_gen_exit_tb(NULL, 0);
}
}
void e2k_tr_gen_exception(DisasContext *ctx, int which)
{
TCGv_i32 t = tcg_const_i32(which);
e2k_gen_save_cpu_state(ctx);
gen_helper_raise_exception(cpu_env, t);
ctx->base.is_jmp = DISAS_NORETURN;
tcg_temp_free_i32(t);
}
void e2k_tr_gen_exception_no_spill(DisasContext *ctx, int excp)
{
TCGv_i32 t0 = tcg_const_i32(excp);
e2k_gen_save_cpu_state(ctx);
gen_helper_raise_exception_no_spill(cpu_env, t0);
ctx->base.is_jmp = DISAS_NORETURN;
tcg_temp_free_i32(t0);
}
static inline void illop(DisasContext *ctx)
{
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
}
////////////////////////////////////////////////////////////////////
//// Decode
////////////////////////////////////////////////////////////////////
/* returns zero if bundle is invalid */
static size_t unpack_bundle(CPUE2KState *env, DisasContext *ctx)
{
@ -186,40 +248,251 @@ static size_t unpack_bundle(CPUE2KState *env, DisasContext *ctx)
return 8 + extract32(hs, 4, 3) * 8;
}
static void gen_goto_tb(DisasContext *ctx, int tb_num, target_ulong pc)
static inline uint8_t ss_extract_ipd(const UnpackedBundle *raw)
{
if (translator_use_goto_tb(&ctx->base, pc)) {
/* jump to same page: we can use a direct jump */
tcg_gen_goto_tb(tb_num);
tcg_gen_movi_tl(e2k_cs.pc, pc);
tcg_gen_exit_tb(ctx->base.tb, tb_num);
return raw->ss_present ? extract32(raw->ss, 30, 2) : 3;
}
static inline int32_t cs0_extract_sdisp(const UnpackedBundle *raw)
{
return sextract32(raw->cs0, 0, 28) << 3;
}
static inline void decode_cs1(DisasContext *ctx, const UnpackedBundle *raw)
{
enum {
SETR0,
SETR1,
SETEI,
WAIT,
SETBR,
CALL,
MAS_OPC,
FLUSHR,
BG
};
Bundle *bundle = &ctx->bundle2;
Cs1 *ret = &bundle->cs1;
uint32_t cs1 = raw->cs1;
int opc = extract32(cs1, 28, 4);
ret->type = CS1_NONE;
if (!raw->cs1_present) {
return;
}
if (opc == SETR0 || opc == SETR1 || opc == SETBR) {
Cs1Setr *setr = &ret->setr;
setr->type = 0;
if (opc == SETR0 || opc == SETR1) {
uint32_t lts0 = raw->lts[0];
if (!raw->lts_present[0]) {
illop(ctx);
return;
}
setr->type |= opc == SETR1 ? SETR_VFRPSZ : 0;
setr->type |= SETR_WD;
setr->wsz = extract32(lts0, 5, 7);
setr->nfx = extract32(lts0, 4, 1);
if (ctx->version >= 3) {
setr->dbl = extract32(lts0, 3, 1);
}
}
if (extract32(cs1, 26, 1)) {
setr->type |= SETR_BN;
setr->rbs = extract32(cs1, BR_RBS_OFF, BR_RBS_LEN);
setr->rsz = extract32(cs1, BR_RSZ_OFF, BR_RSZ_LEN);
setr->rcur = extract32(cs1, BR_RCUR_OFF, BR_RCUR_LEN);
}
if (extract32(cs1, 27, 1)) {
setr->type |= SETR_BP;
setr->psz = extract32(cs1, BR_PSZ_OFF, BR_PSZ_LEN);
}
ret->type = CS1_SETR;
} else if (opc == SETEI) {
if (extract32(cs1, 27, 1)) {
if (ctx->version < 2) {
illop(ctx);
return;
}
ret->type = CS1_SETSFT;
} else {
ret->type = CS1_SETEI;
ret->ei = extract32(cs1, 0, 8);
}
} else if (opc == WAIT) {
ret->type = CS1_WAIT;
ret->wait.all_c = extract32(cs1, 0, 1);
ret->wait.all_e = extract32(cs1, 1, 1);
ret->wait.st_c = extract32(cs1, 2, 1);
ret->wait.ld_c = extract32(cs1, 3, 1);
ret->wait.fl_c = extract32(cs1, 4, 1);
ret->wait.ma_c = extract32(cs1, 5, 1);
if (ctx->version >= 2) {
ret->wait.trap = extract32(cs1, 6, 1);
}
if (ctx->version >= 5) {
if (ret->wait.st_c) {
ret->wait.sas = extract32(cs1, 7, 1);
}
if (ret->wait.ld_c) {
ret->wait.sal = extract32(cs1, 8, 1);
}
}
} else if (opc == CALL) {
int ctop = extract32(raw->ss, 10, 2);
int wbs = extract32(cs1, 0, 7);
if (ctop) {
ret->type = CS1_CALL;
ret->call_wbs = wbs;
} else {
int cs1_ctopc = extract32(cs1, 7, 3);
int cs0_opc = extract32(raw->cs0, 28, 4);
int disp = extract32(raw->cs0, 1, 5);
if (cs1_ctopc != 2 || cs0_opc != 0 || !raw->cs0_present) {
illop(ctx);
return;
}
ret->type = CS1_HCALL;
ret->hcall.disp = disp;
ret->hcall.wbs = wbs;
}
} else if (opc == MAS_OPC) {
ret->type = CS1_MAS;
ret->mas[0] = extract32(cs1, 21, 7);
ret->mas[2] = extract32(cs1, 14, 7);
ret->mas[3] = extract32(cs1, 7, 7);
ret->mas[5] = extract32(cs1, 0, 7);
} else if (opc == FLUSHR) {
ret->type = CS1_FLUSH;
ret->flush.flushr = (cs1 & 1) != 0;
ret->flush.flushc = (cs1 & 2) != 0;
} else if (opc == BG) {
ret->type = CS1_VFBG;
ret->vfbg.umask = extract32(cs1, 0, 8);
ret->vfbg.dmask = extract32(cs1, 8, 8);
ret->vfbg.chkm4 = extract32(cs1, 16, 1);
} else {
/* jump to another page: currently not optimized */
tcg_gen_movi_tl(e2k_cs.pc, pc);
tcg_gen_exit_tb(NULL, 0);
illop(ctx);
}
}
void e2k_tr_gen_exception(DisasContext *ctx, int which)
static inline void decode_cs0(DisasContext *ctx, const UnpackedBundle *raw)
{
TCGv_i32 t = tcg_const_i32(which);
Bundle *bundle = &ctx->bundle2;
Cs0 *ret = &bundle->cs0;
uint32_t cs0 = raw->cs0;
int ctpr = extract32(cs0, 30, 2);
int ctp_opc = extract32(cs0, 28, 2);
int param_type = extract32(cs0, 0, 3);
e2k_gen_save_cpu_state(ctx);
gen_helper_raise_exception(cpu_env, t);
ctx->base.is_jmp = DISAS_NORETURN;
if (!raw->cs0_present) {
ret->type = CS0_NONE;
return;
} else if (ctpr > 0) {
switch(ctp_opc) {
case 0: // disp
case 1: // ldisp
if (ctp_opc == 1 && ctpr != 2) {
illop(ctx);
return;
}
ret->type = CS0_DISP;
ret->disp.opc = ctp_opc;
ret->disp.ctpr = ctpr;
ret->disp.sdisp = cs0_extract_sdisp(raw);
ret->disp.ipd = ss_extract_ipd(raw);
break;
case 2:
ret->type = CS0_SDISP;
ret->sdisp.ctpr = ctpr;
ret->sdisp.disp = extract32(cs0, 0, 28);
ret->sdisp.ipd = ss_extract_ipd(raw);
break;
case 3:
if (param_type == 0 && ctpr == 3) {
ret->type = CS0_RETURN;
} else if (param_type == 1) {
ret->type = CS0_GETTSD;
}
break;
}
} else {
switch(ctp_opc) {
case 0:
ret->type = CS0_IBRANCH;
ret->ibranch.sdisp = cs0_extract_sdisp(raw);
break;
case 1:
ret->type = CS0_PREF;
ret->pref.prefr = extract32(cs0, 0, 2);
ret->pref.ipd = extract32(cs0, 3, 1);
ret->pref.disp = extract32(cs0, 4, 24);
break;
case 2:
ret->type = CS0_PUTTSD;
break;
case 3:
if (param_type == 0) {
ret->type = CS0_DONE;
} else if (param_type == 3) {
ret->type = CS0_HRET;
} else if (param_type == 4) {
ret->type = CS0_GLAUNCH;
}
break;
}
}
tcg_temp_free_i32(t);
switch(ret->type) {
case CS0_NONE:
illop(ctx);
break;
case CS0_IBRANCH:
case CS0_DONE:
case CS0_HRET:
case CS0_GLAUNCH:
if (!raw->ss_present
|| extract32(raw->ss, 10, 2) != 0
|| extract32(raw->ss, 0, 9) == 0
|| bundle->cs1.type == CS1_CALL
|| bundle->cs1.type == CS1_HCALL)
{
ret->type = CS0_NONE;
illop(ctx);
}
break;
default:
break;
}
}
void e2k_tr_gen_exception_no_spill(DisasContext *ctx, int excp)
static inline void decode_ct_cond(DisasContext *ctx, const UnpackedBundle *raw)
{
TCGv_i32 t0 = tcg_const_i32(excp);
ctx->ct.type = CT_NONE;
ctx->ct.cond_type = 0;
int ctpr = extract32(raw->ss, 10, 2);
if (ctpr != 0) {
if (ctx->ct.type == CT_NONE) {
ctx->ct.type = CT_JUMP;
}
ctx->ct.u.ctpr = e2k_cs.ctprs[ctpr - 1];
}
ctx->ct.psrc = extract32(raw->ss, 0, 5);
ctx->ct.cond_type = extract32(raw->ss, 5, 4);
}
e2k_gen_save_cpu_state(ctx);
gen_helper_raise_exception_no_spill(cpu_env, t0);
ctx->base.is_jmp = DISAS_NORETURN;
////////////////////////////////////////////////////////////////////
//// Generate
////////////////////////////////////////////////////////////////////
tcg_temp_free_i32(t0);
static inline void gen_set_ctpr(int index, uint64_t ctpr)
{
assert(0 < index && index < 4);
tcg_gen_movi_i64(e2k_cs.ctprs[index - 1], ctpr);
}
static inline void gen_ctpr_tag(TCGv_i64 ret, TCGv_i64 ctpr)
@ -241,6 +514,394 @@ static inline void gen_goto_ctpr_disp(TCGv_i64 ctpr)
tcg_temp_free_i64(t0);
}
static inline void gen_vfrpsz(DisasContext *ctx)
{
Cs1 *cs1 = &ctx->bundle2.cs1;
Cs1Setr *setr = &cs1->setr;
if (cs1->type == CS1_SETR && (setr->type & SETR_VFRPSZ)) {
e2k_todo_illop(ctx, "vfrpsz");
}
}
static inline void gen_setwd(DisasContext *ctx)
{
Cs1 *cs1 = &ctx->bundle2.cs1;
Cs1Setr *setr = &cs1->setr;
if (cs1->type == CS1_SETR && (setr->type & SETR_WD)) {
TCGv_i32 t0 = tcg_const_i32(setr->wsz);
TCGv_i32 t1 = tcg_const_i32(setr->nfx);
TCGv_i32 t2 = tcg_const_i32(setr->dbl);
gen_helper_setwd(cpu_env, t0, t1, t2);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
}
static inline void gen_setbn(DisasContext *ctx)
{
Cs1 *cs1 = &ctx->bundle2.cs1;
Cs1Setr *setr = &cs1->setr;
if (cs1->type == CS1_SETR && (setr->type & SETR_BN)) {
tcg_gen_movi_i32(e2k_cs.boff, setr->rbs * 2);
tcg_gen_movi_i32(e2k_cs.bsize, (setr->rsz + 1) * 2);
tcg_gen_movi_i32(e2k_cs.bcur, setr->rcur * 2);
}
}
static inline void gen_setbp(DisasContext *ctx)
{
Cs1 *cs1 = &ctx->bundle2.cs1;
Cs1Setr *setr = &cs1->setr;
if (cs1->type == CS1_SETR && (setr->type & SETR_BP)) {
tcg_gen_movi_i32(e2k_cs.psize, setr->psz);
tcg_gen_movi_i32(e2k_cs.pcur, 0);
}
}
static inline void gen_setr(DisasContext *ctx)
{
gen_vfrpsz(ctx);
gen_setwd(ctx);
gen_setbn(ctx);
gen_setbp(ctx);
}
static inline void gen_cs1(DisasContext *ctx)
{
Cs1 *cs1 = &ctx->bundle2.cs1;
switch(cs1->type) {
case CS1_NONE:
case CS1_MAS:
case CS1_SETR:
break;
case CS1_CALL:
ctx->ct.type = CT_CALL;
ctx->ct.wbs = cs1->call_wbs;
break;
case CS1_WAIT:
e2k_todo(ctx, "wait");
break;
case CS1_FLUSH:
e2k_todo(ctx, "flush");
break;
default:
e2k_todo_illop(ctx, "unimplemented %d", cs1->type);
break;
}
}
static inline void gen_cs0(DisasContext *ctx)
{
Cs0 *cs0 = &ctx->bundle2.cs0;
switch(cs0->type) {
case CS0_NONE:
break;
case CS0_IBRANCH:
ctx->ct.type = CT_IBRANCH;
ctx->ct.u.target = ctx->pc + cs0->ibranch.sdisp;
break;
case CS0_DISP: {
uint64_t ctpr = ctpr_new_disp(ctx, &cs0->disp);
gen_set_ctpr(cs0->disp.ctpr, ctpr);
break;
}
case CS0_SDISP: {
// TODO: real sdisp target address
target_ulong target = (0xe2UL << 40) | cs0->sdisp.disp;
uint64_t ctpr = ctpr_new(CTPR_TAG_SDISP, 0, cs0->sdisp.ipd, target);
gen_set_ctpr(cs0->sdisp.ctpr, ctpr);
break;
}
case CS0_RETURN: {
TCGv_i32 t0 = tcg_const_i32(cs0->ret.ipd);
gen_helper_prep_return(e2k_cs.ctprs[2], cpu_env, t0);
tcg_temp_free_i32(t0);
break;
}
default:
e2k_todo_illop(ctx, "unimplemented %d", cs0->type);
break;
}
}
static inline void gen_ct_cond(DisasContext *ctx)
{
ControlTransfer *ct = &ctx->ct;
TCGv_i32 pcond, lcond;
if (ct->type == CT_NONE) {
return;
}
if (ct->cond_type == 1) {
tcg_gen_movi_i32(e2k_cs.ct_cond, 1);
return;
}
pcond = tcg_temp_new_i32();
lcond = tcg_temp_new_i32();
switch (ct->cond_type) {
case 0x2:
case 0x6:
case 0xf:
/* %predN */
e2k_gen_preg_i32(pcond, ct->psrc);
break;
case 0x3:
case 0x7:
case 0xe: {
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_preg_i32(t0, ct->psrc);
tcg_gen_setcondi_i32(TCG_COND_EQ, pcond, t0, 0);
tcg_temp_free_i32(t0);
break;
}
default:
break;
}
switch (ct->cond_type) {
case 0x4:
case 0x6:
case 0xe:
/* #LOOP_END */
e2k_gen_is_loop_end_i32(lcond);
break;
case 0x5:
case 0x7:
case 0xf: { /* #NOT_LOOP_END */
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_is_loop_end_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_EQ, lcond, t0, 0);
tcg_temp_free_i32(t0);
break;
}
}
switch (ct->cond_type) {
case 0x2:
case 0x3:
/* {,~}%predN */
tcg_gen_mov_i32(e2k_cs.ct_cond, pcond);
break;
case 0x4:
case 0x5:
/* #{,NOT_}LOOP_END */
tcg_gen_mov_i32(e2k_cs.ct_cond, lcond);
break;
case 0x6:
case 0xe: {
/* {,~}%predN || #LOOP_END */
TCGv_i32 z = tcg_const_i32(0);
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_or_i32(t0, pcond, lcond);
tcg_gen_movcond_i32(TCG_COND_EQ, e2k_cs.ct_cond, e2k_cs.lsr_pcnt, z, t0, lcond);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(z);
break;
}
case 0x7:
case 0xf: {
/* {,~}%predN && #NOT_LOOP_END */
TCGv_i32 z = tcg_const_i32(0);
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_and_i32(t0, pcond, lcond);
tcg_gen_movcond_i32(TCG_COND_EQ, e2k_cs.ct_cond, e2k_cs.lsr_pcnt, z, t0, lcond);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(z);
break;
}
case 0x8:
/* %MLOCK || %dt_alM */
if (ct->psrc & 0xf) {
// static const int conv[] = {0, 1, 3, 4};
int i;
e2k_todo(ctx, "%%MLOCK || %%dt_alM");
// %dt_al
for (i = 0; i < 4; i++) {
if (ct->psrc & (1 << i)) {
// i
}
}
} else {
/* %MLOCK */
if (ctx->mlock) {
tcg_gen_mov_i32(e2k_cs.ct_cond, ctx->mlock);
} else {
tcg_gen_movi_i32(e2k_cs.ct_cond, 0);
}
}
break;
case 0x9: {
/* `lock_cond || pl_cond' control transfer conditions. */
unsigned int type = (ct->psrc & 0x18) >> 3;
if (type == 0) {
// static const int cmp_num_to_alc[] = {0, 1, 3, 4};
// unsigned int cmp_num = (psrc & 0x6) >> 1;
// unsigned int neg = psrc & 0x1;
//
// my_printf ("%%MLOCK || %s%%cmp%d", neg ? "~" : "",
// cmp_num_to_alc[cmp_num]);
e2k_todo(ctx, "%%MLOCK || %%cmpN");
} else if (type == 1) {
// unsigned int cmp_jk = (psrc & 0x4) >> 2;
// unsigned int negj = (psrc & 0x2) >> 1;
// unsigned int negk = psrc & 0x1;
//
// my_printf ("%%MLOCK || %s%%cmp%d || %s%%cmp%d",
// negj ? "~" : "", cmp_jk == 0 ? 0 : 3,
// negk ? "~" : "", cmp_jk == 0 ? 1 : 4);
e2k_todo(ctx, "%%MLOCK || %%cmpN || %%cmpM");
} else if (type == 2) {
// unsigned int clp_num = (psrc & 0x6) >> 1;
// unsigned int neg = psrc & 0x1;
// "%%MLOCK || %s%%clp%d", neg ? "~" : "", clp_num
e2k_todo(ctx, "%%MLOCK || %%clpN");
}
break;
}
default:
e2k_todo_illop(ctx, "undefined control transfer type %#x", ct->cond_type);
break;
}
tcg_temp_free_i32(lcond);
tcg_temp_free_i32(pcond);
}
static inline TCGCond cond_from_advance(int advance)
{
switch (advance) {
case 0x01: return TCG_COND_EQ;
case 0x02: return TCG_COND_NE;
case 0x03: return TCG_COND_ALWAYS;
default: return TCG_COND_NEVER;
}
}
static void gen_movcond_flag_i32(TCGv_i32 ret, int flag, TCGv_i32 cond,
TCGv_i32 v1, TCGv_i32 v2)
{
TCGv_i32 one = tcg_const_i32(1);
TCGCond c = cond_from_advance(flag);
tcg_gen_movcond_i32(c, ret, cond, one, v1, v2);
tcg_temp_free_i32(one);
}
static inline void gen_dec_wrap(TCGv_i32 ret, TCGv_i32 cur, int n,
TCGv_i32 size)
{
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_addi_i32(t0, size, n);
tcg_gen_sub_i32(t0, t0, cur);
tcg_gen_remu_i32(t0, t0, size);
tcg_gen_sub_i32(ret, size, t0);
tcg_temp_free_i32(t0);
}
static inline void gen_cur_dec(DisasContext *ctx, TCGv_i32 ret, int cond,
TCGv_i32 cur, int n, TCGv_i32 size)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_brcondi_i32(TCG_COND_EQ, size, 0, l0);
gen_dec_wrap(t0, cur, n, size);
gen_movcond_flag_i32(ret, cond, e2k_cs.ct_cond, t0, cur);
gen_set_label(l0);
tcg_temp_free_i32(t0);
}
static void gen_dec_sat_i32(TCGv_i32 ret, TCGv_i32 arg0)
{
TCGv_i32 t0 = tcg_const_i32(0);
TCGv_i32 t1 = tcg_temp_new_i32();
tcg_gen_subi_i32(t1, arg0, 1);
tcg_gen_movcond_i32(TCG_COND_EQ, ret, arg0, t0, arg0, t1);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static void gen_advance_loop_counters(void)
{
TCGv_i32 z = tcg_const_i32(0);
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
TCGv_i32 t3 = tcg_temp_new_i32();
gen_dec_sat_i32(e2k_cs.lsr_pcnt, e2k_cs.lsr_pcnt);
gen_dec_sat_i32(e2k_cs.lsr_lcnt, e2k_cs.lsr_lcnt);
tcg_gen_setcondi_i32(TCG_COND_EQ, t0, e2k_cs.lsr_pcnt, 0);
tcg_gen_setcondi_i32(TCG_COND_EQ, t1, e2k_cs.lsr_lcnt, 0);
tcg_gen_mov_i32(e2k_cs.lsr_over, t1);
tcg_gen_and_i32(t2, t0, t1);
gen_dec_sat_i32(t3, e2k_cs.lsr_ecnt);
tcg_gen_movcond_i32(TCG_COND_NE, e2k_cs.lsr_ecnt, t2, z, t3, e2k_cs.lsr_ecnt);
tcg_temp_free_i32(t3);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(z);
}
static inline void gen_stubs(DisasContext *ctx)
{
uint32_t ss = ctx->bundle.ss;
int alc = extract32(ss, 16, 2);
int abp = extract32(ss, 18, 2);
int abn = extract32(ss, 21, 2);
int abg = extract32(ss, 23, 2);
int vfdi = extract32(ss, 26, 1);
if (alc) {
TCGLabel *l0 = gen_new_label();
TCGCond cond = cond_from_advance(alc);
tcg_gen_brcondi_i32(tcg_invert_cond(cond), e2k_cs.ct_cond, 1, l0);
gen_advance_loop_counters();
gen_set_label(l0);
}
if (abp) {
TCGv_i32 t0 = tcg_temp_local_new_i32();
tcg_gen_addi_i32(t0, e2k_cs.psize, 1);
gen_cur_dec(ctx, e2k_cs.pcur, abp, e2k_cs.pcur, 1, t0);
tcg_temp_free_i32(t0);
}
if (abn) {
gen_cur_dec(ctx, e2k_cs.bcur, abn, e2k_cs.bcur, 2, e2k_cs.bsize);
}
if (abg != 0) {
// TODO: impl abg
e2k_todo_illop(ctx, "abg");
}
if (vfdi != 0) {
// TODO: impl vfdi
e2k_todo_illop(ctx, "vfdi");
}
}
static inline target_ulong do_decode(DisasContext *ctx, CPUState *cs)
{
E2KCPU *cpu = E2K_CPU(cs);
@ -255,6 +916,10 @@ static inline target_ulong do_decode(DisasContext *ctx, CPUState *cs)
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
}
decode_cs1(ctx, &ctx->bundle);
decode_cs0(ctx, &ctx->bundle);
decode_ct_cond(ctx, &ctx->bundle);
return ctx->pc + len;
}
@ -264,35 +929,15 @@ static inline target_ulong do_decode(DisasContext *ctx, CPUState *cs)
*/
static inline void do_execute(DisasContext *ctx)
{
e2k_control_execute(ctx);
ctx->loop_mode = (ctx->bundle.hs & (1 << 10)) != 0;
gen_cs0(ctx);
gen_cs1(ctx);
e2k_alc_execute(ctx);
if (ctx->bundle.ss_present) {
e2k_decode_jmp(ctx);
}
gen_ct_cond(ctx);
e2k_aau_execute(ctx);
e2k_plu_execute(ctx);
}
static inline void do_window_bounds_check(DisasContext *ctx)
{
if (ctx->max_wreg < ctx->max_wreg_cur) {
TCGLabel *l0 = gen_new_label();
ctx->max_wreg = ctx->max_wreg_cur;
tcg_gen_brcondi_i32(TCG_COND_GT, e2k_cs.wd_size, ctx->max_wreg, l0);
e2k_gen_exception(E2K_EXCP_MAPERR);
gen_set_label(l0);
}
if (ctx->max_breg < ctx->max_breg_cur) {
TCGLabel *l0 = gen_new_label();
ctx->max_breg = ctx->max_breg_cur;
tcg_gen_brcondi_i32(TCG_COND_GT, e2k_cs.bsize, ctx->max_breg, l0);
e2k_gen_exception(E2K_EXCP_MAPERR);
gen_set_label(l0);
}
}
/*
* Writes results of instructions from a bundle to the state
*
@ -303,11 +948,11 @@ static inline void do_window_bounds_check(DisasContext *ctx)
* */
static inline void do_commit(DisasContext *ctx)
{
e2k_control_window_change(ctx);
gen_setr(ctx);
e2k_alc_commit(ctx);
e2k_aau_commit(ctx);
e2k_plu_commit(ctx);
e2k_stubs_commit(ctx);
gen_stubs(ctx);
}
static inline void do_branch(DisasContext *ctx, target_ulong pc_next)
@ -327,7 +972,7 @@ static inline void do_branch(DisasContext *ctx, target_ulong pc_next)
ctx->base.is_jmp = DISAS_NORETURN;
if (ctx->ct.is_branch) {
if (ctx->ct.cond_type > 1) {
TCGLabel *l0 = gen_new_label();
tcg_gen_brcondi_i32(TCG_COND_NE, e2k_cs.ct_cond, 0, l0);
gen_goto_tb(ctx, TB_EXIT_IDX1, pc_next);
@ -395,12 +1040,10 @@ static void e2k_tr_init_disas_context(DisasContextBase *db, CPUState *cs)
static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
{
DisasContext *ctx = container_of(db, DisasContext, base);
// DisasContext *ctx = container_of(db, DisasContext, base);
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
ctx->max_wreg = -1;
ctx->max_breg = -1;
tcg_gen_movi_i32(e2k_cs.ct_cond, 0);
if (env->is_bp) {
@ -417,10 +1060,9 @@ static void e2k_tr_insn_start(DisasContextBase *db, CPUState *cs)
tcg_gen_insn_start(ctx->base.pc_next);
ctx->max_wreg_cur = -1;
ctx->max_breg_cur = -1;
ctx->do_check_illtag = false;
memset(ctx->mas, 0, sizeof(ctx->mas));
memset(&ctx->bundle2, 0, sizeof(ctx->bundle2));
ctx->do_check_illtag = false;
ctx->illtag = e2k_get_temp_i32(ctx);
tcg_gen_movi_i32(ctx->illtag, 0);
}
@ -432,7 +1074,6 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs)
pc_next = do_decode(ctx, cs);
do_execute(ctx);
do_window_bounds_check(ctx);
do_commit(ctx);
do_branch(ctx, pc_next);
@ -506,6 +1147,12 @@ void e2k_tcg_initialize(void) {
{ &e2k_cs.pcur, offsetof(CPUE2KState, bp.cur), "pcur" },
{ &e2k_cs.is_bp, offsetof(CPUE2KState, is_bp), "is_bp" },
{ &e2k_cs.wdbl, offsetof(CPUE2KState, wdbl), "wdbl" },
{ &e2k_cs.lsr_lcnt, offsetof(CPUE2KState, lsr_lcnt), "lsr_lcnt" },
{ &e2k_cs.lsr_ecnt, offsetof(CPUE2KState, lsr_ecnt), "lsr_ecnt" },
{ &e2k_cs.lsr_vlc, offsetof(CPUE2KState, lsr_vlc), "lsr_vlc" },
{ &e2k_cs.lsr_over, offsetof(CPUE2KState, lsr_over), "lsr_over" },
{ &e2k_cs.lsr_pcnt, offsetof(CPUE2KState, lsr_pcnt), "lsr_pcnt" },
{ &e2k_cs.lsr_strmd, offsetof(CPUE2KState, lsr_strmd), "lsr_strmd" },
{ &e2k_cs.aasti_tags, offsetof(CPUE2KState, aau.sti_tags), "aasti_tags" },
{ &e2k_cs.aaind_tags, offsetof(CPUE2KState, aau.ind_tags), "aaind_tags" },
{ &e2k_cs.aaincr_tags, offsetof(CPUE2KState, aau.incr_tags), "aaincr_tags" },
@ -514,7 +1161,6 @@ void e2k_tcg_initialize(void) {
static const struct { TCGv_i64 *ptr; int off; const char *name; } r64[] = {
{ &e2k_cs.pregs, offsetof(CPUE2KState, pregs), "pregs" },
{ &e2k_cs.lsr, offsetof(CPUE2KState, lsr), "lsr" },
};
static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {

View File

@ -40,7 +40,6 @@ typedef struct CPUE2KStateTCG {
TCGv_i32 ct_cond;
TCGv_i32 is_bp; /* breakpoint flag */
TCGv_i32 wdbl;
TCGv_i64 lsr;
TCGv_i32 wd_base; /* holds wbs * 2 */
TCGv_i32 wd_size; /* holds wsz * 2 */
TCGv_i32 boff; /* holds rbs * 2 */
@ -49,6 +48,13 @@ typedef struct CPUE2KStateTCG {
TCGv_i64 pregs;
TCGv_i32 psize; /* holds psz */
TCGv_i32 pcur; /* holds pcur */
/* lsr */
TCGv_i32 lsr_lcnt;
TCGv_i32 lsr_ecnt;
TCGv_i32 lsr_vlc;
TCGv_i32 lsr_over;
TCGv_i32 lsr_pcnt;
TCGv_i32 lsr_strmd;
/* AAU */
TCGv_i32 aasti[16];
TCGv_i32 aasti_tags;
@ -63,7 +69,7 @@ typedef struct CPUE2KStateTCG {
extern struct CPUE2KStateTCG e2k_cs;
typedef struct UnpackedBundle {
typedef struct {
uint32_t hs;
uint32_t ss;
uint32_t als[6];
@ -86,6 +92,140 @@ typedef struct UnpackedBundle {
bool cds_present[3];
} UnpackedBundle;
typedef struct {
int32_t sdisp; /* CS0 28:0 */
} Cs0IBranch, Cs0Puttsd;
typedef struct {
int32_t sdisp; /* CS0 28:0 */
uint8_t ipd; /* SS 31:30 */
uint8_t ctpr; /* CS0 31:30 */
uint8_t opc;
} Cs0Disp;
typedef struct {
uint32_t disp; /* CS0 28:0 */
uint8_t ipd; /* SS 31:30 */
uint8_t ctpr; /* CS0 31:30 */
} Cs0SDisp;
typedef struct {
uint8_t ipd;
} Cs0Return;
typedef struct {
uint32_t disp; /* 28:4 */
uint8_t prefr; /* 2:0 */
uint8_t ipd; /* 3 */
} Cs0Pref;
typedef enum {
CS0_NONE,
CS0_IBRANCH,
CS0_PREF,
CS0_PUTTSD,
CS0_DONE,
CS0_HRET,
CS0_GLAUNCH,
CS0_DISP,
CS0_SDISP,
CS0_GETTSD,
CS0_RETURN,
} Cs0Type;
typedef struct {
Cs0Type type;
union {
Cs0IBranch ibranch;
Cs0Puttsd puttsd;
Cs0Disp disp;
Cs0SDisp sdisp;
Cs0Pref pref;
Cs0Return ret;
};
} Cs0;
typedef enum {
SETR_VFRPSZ = 0x01,
SETR_WD = 0x02,
SETR_BN = 0x04,
SETR_BP = 0x08,
} SetrType;
typedef struct {
SetrType type;
uint8_t rpsz;
uint8_t wsz;
bool nfx;
bool dbl;
uint8_t rbs;
uint8_t rsz;
uint8_t rcur;
uint8_t psz;
} Cs1Setr;
typedef struct {
bool ma_c;
bool fl_c;
bool ld_c;
bool st_c;
bool all_e;
bool all_c;
/* v2+ */
bool trap;
/* v5+ */
bool sal;
bool sas;
} Cs1Wait;
typedef struct {
uint8_t wbs;
uint8_t disp;
} Cs1HCall;
typedef struct {
bool flushr;
bool flushc;
} Cs1Flush;
typedef struct {
bool chkm4;
uint8_t dmask;
uint8_t umask;
} Cs1Vfbg;
typedef enum {
CS1_NONE,
CS1_SETR,
CS1_SETEI,
CS1_SETSFT,
CS1_WAIT,
CS1_CALL,
CS1_HCALL,
CS1_MAS,
CS1_FLUSH,
CS1_VFBG,
} Cs1Type;
typedef struct {
Cs1Type type;
union {
Cs1Setr setr;
uint8_t ei;
Cs1Wait wait;
uint8_t call_wbs;
Cs1HCall hcall;
uint8_t mas[6];
Cs1Flush flush;
Cs1Vfbg vfbg;
};
} Cs1;
typedef struct {
Cs0 cs0;
Cs1 cs1;
} Bundle;
typedef enum {
AL_RESULT_NONE = 0,
@ -119,7 +259,6 @@ typedef struct {
bool poison;
union {
struct {
uint8_t dst; /* %rN, 1st phase */
TCGv_i32 index;
TCGv_i32 tag;
union {
@ -180,18 +319,19 @@ typedef struct {
TCGv_i64 ctpr;
} u;
int wbs;
bool is_branch;
uint8_t cond_type;
uint8_t psrc;
} ControlTransfer;
typedef struct DisasContext {
DisasContextBase base;
UnpackedBundle bundle;
Bundle bundle2;
target_ulong pc;
int jump_ctpr;
int mmuidx;
uint8_t mas[6];
bool loop_mode;
TCGv_i32 is_prologue;
TCGv_i32 is_epilogue;
/* optional, can be NULL */
TCGv_i32 mlock;
@ -210,16 +350,16 @@ typedef struct DisasContext {
int t64_len;
int ttl_len;
/* Delayed window bounds checks */
int max_wreg;
int max_wreg_cur;
int max_breg;
int max_breg_cur;
/* Delayed illegal tag check */
TCGv_i32 illtag;
bool do_check_illtag;
/* Delayed window bounds check */
int max_r;
int max_r_cur;
int max_b;
int max_b_cur;
TCGv_i64 cond[6];
AlResult al_results[6];
TCGv_i32 al_cond[6];
@ -244,22 +384,13 @@ static inline void e2k_gen_exception(int excp)
tcg_temp_free_i32(t0);
}
#define e2k_todo(ctx, fmt, ...) \
qemu_log("%#lx: " fmt " (%s:%d)\n", ctx->pc, \
## __VA_ARGS__, __FILE__, __LINE__)
#define e2k_todo(ctx, fmt, ...) \
do { \
if (unlikely(qemu_loglevel_mask(LOG_UNIMP))) { \
qemu_log("%#lx: todo: ", ctx->pc); \
qemu_log(fmt, ## __VA_ARGS__); \
qemu_log("\n"); \
} \
} while (0)
#define e2k_todo_illop(ctx, fmt, ...) \
do { \
e2k_todo(ctx, fmt, ## __VA_ARGS__); \
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC); \
} while (0)
#define e2k_todo_illop(ctx, fmt, ...) \
e2k_todo(ctx, fmt, ## __VA_ARGS__); \
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC)
static inline void e2k_gen_mask_i64(TCGv_i64 ret, TCGv_i64 len)
{
@ -360,97 +491,9 @@ static inline void e2k_gen_save_cpu_state(DisasContext *ctx)
e2k_gen_save_pc(ctx->pc);
}
static inline void e2k_gen_lcnt_i64(TCGv_i64 ret)
{
tcg_gen_andi_i64(ret, e2k_cs.lsr, (1UL << 32) - 1);
}
static inline void e2k_gen_lcnt_i32(TCGv_i32 ret)
{
TCGv_i64 t0 = tcg_temp_new_i64();
e2k_gen_lcnt_i64(t0);
tcg_gen_extrl_i64_i32(ret, t0);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_lcnt_set_i32(TCGv_i32 value)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, value);
tcg_gen_deposit_i64(e2k_cs.lsr, e2k_cs.lsr, t0, LSR_LCNT_OFF, LSR_LCNT_LEN);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_ecnt_i64(TCGv_i64 ret)
{
tcg_gen_extract_i64(ret, e2k_cs.lsr, LSR_ECNT_OFF, LSR_ECNT_LEN);
}
static inline void e2k_gen_ecnt_i32(TCGv_i32 ret)
{
TCGv_i64 t0 = tcg_temp_new_i64();
e2k_gen_ecnt_i64(t0);
tcg_gen_extrl_i64_i32(ret, t0);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_ecnt_set_i32(TCGv_i32 value)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, value);
tcg_gen_deposit_i64(e2k_cs.lsr, e2k_cs.lsr, t0, LSR_ECNT_OFF, LSR_ECNT_LEN);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_pcnt_i32(TCGv_i32 ret)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extract_i64(t0, e2k_cs.lsr, LSR_PCNT_OFF, LSR_PCNT_LEN);
tcg_gen_extrl_i64_i32(ret, t0);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_pcnt_set_i32(TCGv_i32 value)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, value);
tcg_gen_deposit_i64(e2k_cs.lsr, e2k_cs.lsr, t0, LSR_PCNT_OFF, LSR_PCNT_LEN);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_lsr_strem_i32(TCGv_i32 ret)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extract_i64(t0, e2k_cs.lsr, LSR_STRMD_OFF, LSR_STRMD_LEN);
tcg_gen_extrl_i64_i32(ret, t0);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_lsr_strem_set_i32(TCGv_i32 value)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, value);
tcg_gen_deposit_i64(e2k_cs.lsr, e2k_cs.lsr, t0, LSR_STRMD_OFF,
LSR_STRMD_LEN);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_lcntex(TCGv_i32 ret)
{
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_extrl_i64_i32(t0, e2k_cs.lsr);
tcg_gen_setcondi_i32(TCG_COND_EQ, ret, t0, 0);
tcg_temp_free_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_EQ, ret, e2k_cs.lsr_lcnt, 0);
}
void e2k_gen_store_preg(int idx, TCGv_i32 val);
@ -493,17 +536,13 @@ void e2k_gen_reg_index_from_gregi(TCGv_i32 ret, int idx);
static inline void e2k_gen_reg_index(DisasContext *ctx, TCGv_i32 ret, uint8_t arg)
{
if (IS_BASED(arg)) {
int index = GET_BASED(arg);
ctx->max_breg_cur = MAX(ctx->max_breg_cur, index);
e2k_gen_reg_index_from_bregi(ret, index);
e2k_gen_reg_index_from_bregi(ret, GET_BASED(arg));
} else if (IS_REGULAR(arg)) {
int index = GET_REGULAR(arg);
ctx->max_wreg_cur = MAX(ctx->max_wreg_cur, index);
e2k_gen_reg_index_from_wregi(ret, index);
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 {
e2k_gen_exception(E2K_EXCP_ILLOPN);
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
}
}
@ -519,52 +558,19 @@ void e2k_gen_xreg_write_i64(TCGv_i64 value, TCGv_i32 idx);
void e2k_gen_xreg_write_i32(TCGv_i32 value, TCGv_i32 idx);
void e2k_gen_xreg_write16u_i32(TCGv_i32 value, TCGv_i32 idx);
void e2k_gen_preg_i64(TCGv_i64 ret, int reg);
void e2k_gen_preg_i32(TCGv_i32 ret, int reg);
TCGv_i64 e2k_get_preg(DisasContext *dc, int reg);
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,
uint8_t psrc)
{
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_cond_i32(ctx, t0, psrc);
tcg_gen_extu_i32_i64(ret, t0);
tcg_temp_free_i32(t0);
}
static inline void e2k_gen_is_last_iter(TCGv_i32 ret)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i64 t2 = tcg_temp_new_i64();
TCGv_i32 t3 = tcg_temp_new_i32();
e2k_gen_lcnt_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_LTU, t1, t0, 2);
tcg_gen_andi_i64(t2, e2k_cs.lsr, LSR_VLC_BIT);
tcg_gen_setcondi_i64(TCG_COND_NE, t2, t2, 0);
tcg_gen_extrl_i64_i32(t3, t2);
tcg_gen_and_i32(ret, t1, t3);
tcg_temp_free_i32(t3);
tcg_temp_free_i64(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static inline void e2k_gen_is_loop_end_i32(TCGv_i32 ret)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
e2k_gen_ecnt_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_EQ, t1, t0, 0);
e2k_gen_is_last_iter(t2);
tcg_gen_and_i32(ret, t1, t2);
tcg_gen_setcondi_i32(TCG_COND_EQ, t0, e2k_cs.lsr_ecnt, 0);
tcg_gen_setcondi_i32(TCG_COND_LTU, t1, e2k_cs.lsr_lcnt, 2);
tcg_gen_and_i32(t2, t0, t1);
tcg_gen_and_i32(ret, t2, e2k_cs.lsr_vlc);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
@ -572,8 +578,6 @@ static inline void e2k_gen_is_loop_end_i32(TCGv_i32 ret)
}
void e2k_decode_jmp(DisasContext *ctx);
void e2k_control_execute(DisasContext *ctx);
void e2k_control_window_change(DisasContext *ctx);
void e2k_stubs_commit(DisasContext *ctx);
void alc_init(DisasContext *ctx);

View File

@ -16,14 +16,14 @@ typedef struct {
uint16_t aas;
};
uint8_t dst;
} Instr;
} Mova;
static void gen_load_prefetch_program(DisasContext *ctx)
{
gen_helper_aau_load_program(cpu_env);
}
static void gen_aau_result_reg64(DisasContext *ctx, Instr *instr, TCGv_i64 dst)
static void gen_aau_result_reg64(DisasContext *ctx, Mova *instr, TCGv_i64 dst)
{
AauResult *res = &ctx->aau_results[instr->chan];
res->type = AAU_RESULT_REG64;
@ -38,7 +38,7 @@ static void gen_aau_result_reg64(DisasContext *ctx, Instr *instr, TCGv_i64 dst)
}
}
static void gen_aau_result_reg32(DisasContext *ctx, Instr *instr, TCGv_i32 dst)
static void gen_aau_result_reg32(DisasContext *ctx, Mova *instr, TCGv_i32 dst)
{
AauResult *res = &ctx->aau_results[instr->chan];
res->type = AAU_RESULT_REG32;
@ -53,7 +53,7 @@ static void gen_aau_result_reg32(DisasContext *ctx, Instr *instr, TCGv_i32 dst)
}
}
static void gen_mova_i32(DisasContext *ctx, Instr *instr, TCGv ptr)
static void gen_mova_i32(DisasContext *ctx, Mova *instr, TCGv ptr)
{
MemOp memop = instr->be ? MO_BE : MO_LE;
TCGv_i32 dst = e2k_get_temp_i32(ctx);
@ -71,7 +71,7 @@ static void gen_mova_i32(DisasContext *ctx, Instr *instr, TCGv ptr)
gen_aau_result_reg32(ctx, instr, dst);
}
static void gen_mova_i64(DisasContext *ctx, Instr *instr, TCGv ptr)
static void gen_mova_i64(DisasContext *ctx, Mova *instr, TCGv ptr)
{
TCGv_i64 dst = e2k_get_temp_i64(ctx);
@ -79,7 +79,7 @@ static void gen_mova_i64(DisasContext *ctx, Instr *instr, TCGv ptr)
gen_aau_result_reg64(ctx, instr, dst);
}
static inline void gen_mova_ptr(TCGv ret, Instr *instr)
static inline void gen_mova_ptr(TCGv ret, Mova *instr)
{
TCGv_i32 t0 = tcg_const_i32(instr->chan);
TCGv_i32 t1 = tcg_const_i32(instr->area);
@ -92,7 +92,7 @@ static inline void gen_mova_ptr(TCGv ret, Instr *instr)
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static void gen_mova(DisasContext *ctx, Instr *instr)
static void gen_mova(DisasContext *ctx, Mova *instr)
{
TCGv t5 = tcg_temp_new();
@ -142,7 +142,7 @@ void e2k_aau_execute(DisasContext *ctx)
unsigned int i;
for (i = 0; i < 4; i++) {
Instr instr = { 0 };
Mova instr = { 0 };
AauResult *res = &ctx->aau_results[i];
instr.chan = i;

View File

@ -29,6 +29,7 @@ typedef struct {
int chan;
AlesFlag ales_present;
int aaincr_len;
uint8_t mas;
union {
uint32_t als;
struct {
@ -487,10 +488,7 @@ static inline void set_al_result_reg80_tag(Instr *instr, TCGv_i64 lo,
res->reg.v64 = lo;
res->reg.x32 = hi;
res->reg.index = get_temp_i32(instr);
res->reg.dst = dst;
if (!IS_REGULAR(dst)) {
e2k_gen_reg_index(instr->ctx, res->reg.index, dst);
}
e2k_gen_reg_index(instr->ctx, res->reg.index, dst);
}
}
@ -518,12 +516,7 @@ static inline void set_al_result_reg64_tag(Instr *instr,
res->reg.v64 = value;
res->reg.tag = tag;
res->reg.index = e2k_get_temp_i32(instr->ctx);
if (IS_REGULAR(arg)) {
res->reg.dst = arg;
} else {
res->reg.dst = 0;
e2k_gen_reg_index(instr->ctx, res->reg.index, arg);
}
e2k_gen_reg_index(instr->ctx, res->reg.index, arg);
}
}
@ -557,12 +550,7 @@ static inline void set_al_result_reg32_tag(Instr *instr,
res->reg.v32 = value;
res->reg.tag = tag;
res->reg.index = e2k_get_temp_i32(instr->ctx);
if (IS_REGULAR(arg)) {
res->reg.dst = arg;
} else {
res->reg.dst = 0;
e2k_gen_reg_index(instr->ctx, res->reg.index, arg);
}
e2k_gen_reg_index(instr->ctx, res->reg.index, arg);
}
}
@ -689,16 +677,14 @@ static void gen_loop_mode_st(DisasContext *ctx, TCGLabel *l)
{
if (ctx->loop_mode) {
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_local_new_i32();
tcg_gen_brcondi_i32(TCG_COND_EQ, ctx->is_prologue, 1, l);
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_brcondi_i32(TCG_COND_NE, e2k_cs.lsr_pcnt, 0, l);
e2k_gen_is_loop_end_i32(t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
e2k_gen_lsr_strem_i32(t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l);
tcg_gen_subi_i32(t0, t0, 1);
e2k_gen_lsr_strem_set_i32(t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, e2k_cs.lsr_strmd, 0, l);
tcg_gen_subi_i32(e2k_cs.lsr_strmd, e2k_cs.lsr_strmd, 1);
gen_set_label(l0);
tcg_temp_free_i32(t0);
}
}
@ -1698,7 +1684,7 @@ ok_exit:
static MemOp gen_mas(Instr *instr, MemOp memop, TCGv_i64 addr)
{
DisasContext *ctx = instr->ctx;
uint8_t mas = ctx->mas[instr->chan];
uint8_t mas = instr->mas;
if ((mas & 0x7) == 7) {
int opc = mas >> 3;
@ -2140,11 +2126,10 @@ static void gen_aasti_incr(DisasContext *ctx, Instr *instr)
TCGLabel *l1 = gen_new_label();
TCGv_i32 t0 = tcg_temp_local_new_i32();
tcg_gen_brcondi_i32(TCG_COND_EQ, ctx->is_prologue, 1, l0);
tcg_gen_brcondi_i32(TCG_COND_NE, e2k_cs.lsr_pcnt, 0, l0);
e2k_gen_is_loop_end_i32(t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1);
e2k_gen_lsr_strem_i32(t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
tcg_gen_brcondi_i32(TCG_COND_EQ, e2k_cs.lsr_strmd, 0, l0);
gen_set_label(l1);
}
@ -2201,7 +2186,7 @@ static void gen_aad_ptr(DisasContext *ctx, TCGv ret, Instr *instr)
static void gen_staa_i64(Instr *instr)
{
DisasContext *ctx = instr->ctx;
uint8_t mas = ctx->mas[instr->chan];
uint8_t mas = instr->mas;
TCGLabel *l0 = gen_new_label();
Src64 s4 = get_src4_i64(instr);
@ -2256,7 +2241,7 @@ static void gen_staa_i64(Instr *instr)
static void gen_staa_i32(Instr *instr, MemOp memop)
{
DisasContext *ctx = instr->ctx;
uint8_t mas = ctx->mas[instr->chan];
uint8_t mas = instr->mas;
TCGLabel *l0 = gen_new_label();
Src32 s4 = get_src4_i32(instr);
@ -4509,17 +4494,12 @@ static void chan_check_preds(DisasContext *ctx, int chan, TCGLabel *l)
switch(kind) {
case 0x2: { /* %pcntN */
TCGv_i32 t3 = tcg_temp_new_i32();
has_pcnt = true;
// FIXME: slow, need to store unpacked LSR for fast field access
e2k_gen_pcnt_i32(t3);
tcg_gen_setcondi_i32(TCG_COND_LEU, t2, t3, idx);
tcg_gen_setcondi_i32(TCG_COND_LEU, t2, e2k_cs.lsr_pcnt, idx);
if (invert) {
tcg_gen_xori_i32(t2, t2, 1);
}
tcg_gen_or_i32(t0, t0, t2);
tcg_temp_free_i32(t3);
break;
}
case 0x3: /* %predN */
@ -4564,9 +4544,9 @@ static void chan_execute(DisasContext *ctx, int chan)
TCGLabel *l0 = gen_new_label();
Instr instr = { 0 };
instr.aaincr = 0;
instr.ctx = ctx;
instr.chan = chan;
instr.mas = ctx->bundle2.cs1.type == CS1_MAS ? ctx->bundle2.cs1.mas[chan] : 0;
instr.als = ctx->bundle.als[chan];
instr.ales = ctx->bundle.ales[chan];
instr.ales_present = ctx->bundle.ales_present[chan];
@ -4729,18 +4709,7 @@ static inline void gen_al_result_commit_ctpr(AlResult *res)
void e2k_alc_commit(DisasContext *ctx)
{
unsigned int i;
for (i = 0; i < 6; i++) {
AlResult *res = &ctx->al_results[i];
if (e2k_al_result_type(res->type) == AL_RESULT_REG) {
uint8_t dst = res->reg.dst;
if (IS_REGULAR(dst)) {
e2k_gen_reg_index_from_wregi(res->reg.index, GET_REGULAR(dst));
}
}
}
int i;
for (i = 0; i < 6; i++) {
TCGLabel *l0 = gen_new_label();

View File

@ -1,672 +0,0 @@
#include "qemu/osdep.h"
#include "qemu.h"
#include "exec/log.h"
#include "translate.h"
static inline TCGCond cond_from_advance(int advance)
{
switch (advance) {
case 0x01: return TCG_COND_EQ;
case 0x02: return TCG_COND_NE;
case 0x03: return TCG_COND_ALWAYS;
default: return TCG_COND_NEVER;
}
}
static void gen_movcond_flag_i32(TCGv_i32 ret, int flag, TCGv_i32 cond,
TCGv_i32 v1, TCGv_i32 v2)
{
TCGv_i32 one = tcg_const_i32(1);
TCGCond c = cond_from_advance(flag);
tcg_gen_movcond_i32(c, ret, cond, one, v1, v2);
tcg_temp_free_i32(one);
}
static inline void gen_dec_wrap(TCGv_i32 ret, TCGv_i32 cur, int n,
TCGv_i32 size)
{
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_addi_i32(t0, size, n);
tcg_gen_sub_i32(t0, t0, cur);
tcg_gen_remu_i32(t0, t0, size);
tcg_gen_sub_i32(ret, size, t0);
tcg_temp_free_i32(t0);
}
static inline void gen_cur_dec(DisasContext *ctx, TCGv_i32 ret, int cond,
TCGv_i32 cur, int n, TCGv_i32 size)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_brcondi_i32(TCG_COND_EQ, size, 0, l0);
gen_dec_wrap(t0, cur, n, size);
gen_movcond_flag_i32(ret, cond, e2k_cs.ct_cond, t0, cur);
gen_set_label(l0);
tcg_temp_free_i32(t0);
}
static void gen_advance_pcnt(TCGv_i32 ret)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_local_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
e2k_gen_pcnt_i32(t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
tcg_gen_subi_i32(t1, t0, 1);
e2k_gen_pcnt_set_i32(t1);
gen_set_label(l0);
tcg_gen_mov_i32(ret, t0);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static inline void gen_lcnt_overflow(TCGv_i32 lcnt)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, lcnt);
tcg_gen_setcondi_i64(TCG_COND_EQ, t1, t0, 0);
tcg_gen_shli_i64(t1, t1, LSR_OVER_OFF);
tcg_gen_or_i64(e2k_cs.lsr, e2k_cs.lsr, t1);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
static void gen_advance_lcnt(TCGv_i32 ret)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_local_new_i32();
e2k_gen_lcnt_i32(t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
tcg_gen_subi_i32(t0, t0, 1);
e2k_gen_lcnt_set_i32(t0);
gen_set_label(l0);
gen_lcnt_overflow(t0);
tcg_gen_mov_i32(ret, t0);
tcg_temp_free_i32(t0);
}
static void gen_advance_ecnt(void)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_local_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
e2k_gen_ecnt_i32(t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
tcg_gen_subi_i32(t1, t0, 1);
e2k_gen_ecnt_set_i32(t1);
gen_set_label(l0);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static void gen_advance_loop_counters(void)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_local_new_i32();
TCGv_i32 t1 = tcg_temp_local_new_i32();
gen_advance_pcnt(t0);
gen_advance_lcnt(t1);
tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, l0);
tcg_gen_brcondi_i32(TCG_COND_NE, t1, 0, l0);
gen_advance_ecnt();
gen_set_label(l0);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
void e2k_stubs_commit(DisasContext *ctx)
{
uint32_t ss = ctx->bundle.ss;
int alc = extract32(ss, 16, 2);
int abp = extract32(ss, 18, 2);
int abn = extract32(ss, 21, 2);
int abg = extract32(ss, 23, 2);
int vfdi = extract32(ss, 26, 1);
if (alc) {
TCGLabel *l0 = gen_new_label();
TCGCond cond = cond_from_advance(alc);
tcg_gen_brcondi_i32(tcg_invert_cond(cond), e2k_cs.ct_cond, 1, l0);
gen_advance_loop_counters();
gen_set_label(l0);
}
if (abp) {
TCGv_i32 t0 = tcg_temp_local_new_i32();
tcg_gen_addi_i32(t0, e2k_cs.psize, 1);
gen_cur_dec(ctx, e2k_cs.pcur, abp, e2k_cs.pcur, 1, t0);
tcg_temp_free_i32(t0);
}
if (abn) {
gen_cur_dec(ctx, e2k_cs.bcur, abn, e2k_cs.bcur, 2, e2k_cs.bsize);
}
if (abg != 0) {
// TODO: impl abg
e2k_todo_illop(ctx, "abg");
}
if (vfdi != 0) {
// TODO: impl vfdi
e2k_todo_illop(ctx, "vfdi");
}
}
static void gen_cs0(DisasContext *dc)
{
typedef enum {
NOTHING,
IBRANCH,
PREF,
PUTTSD,
DONE,
HRET,
GLAUNCH,
DISP,
SDISP,
GETTSD,
LDISP,
RETURN
} cs0_type;
static cs0_type cs0_ops[4][4] = {
{IBRANCH, PREF, PUTTSD, DONE},
{DISP, NOTHING, SDISP, GETTSD},
{DISP, LDISP, SDISP, GETTSD},
{DISP, NOTHING, SDISP, RETURN}
};
const UnpackedBundle *bundle = &dc->bundle;
uint32_t cs0 = bundle->cs0;
unsigned int ctpr = (cs0 & 0xc0000000) >> 30;
unsigned int ctp_opc = (cs0 & 0x30000000) >> 28;
unsigned int param_type = (cs0 & 0x00000007);
cs0_type type = cs0_ops[ctpr][ctp_opc];
if (type == RETURN && param_type == 1) {
type = GETTSD;
} else if (type == DONE) {
if (param_type == 3) {
type = HRET;
} else if (param_type == 4) {
type = GLAUNCH;
}
}
if (type == IBRANCH || type == DONE || type == HRET || type == GLAUNCH) {
if (!bundle->ss_present || (bundle->ss & 0x00000c00)) {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
} else if ((bundle->ss & 0x1ff)
&& !(bundle->cs1_present
/* CS1.opc == CALL */
&& (bundle->cs1 & 0xf0000000) >> 28 == 5
/* CS1.param.ctopc == HCALL */
&& (bundle->cs1 & 0x380) >> 7 == 2))
{
if (type == IBRANCH) {
int32_t sdisp = sextract32(cs0, 0, 28) << 3;
dc->ct.type = CT_IBRANCH;
dc->ct.u.target = dc->pc + sdisp;
} else {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
}
}
} else {
/* Note that according to Table B.4.1 it's possible to obtain
` gettsd %ctpr{1,2} with an invalid value for CS0.param.type. */
if (type == GETTSD && param_type != 1) {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
}
int ipd = bundle->ss_present ? extract32(bundle->ss, 30, 2) : 3;
if (type == DISP || type == LDISP) {
int32_t sdisp = sextract32(cs0, 0, 28) << 3;
uint64_t reg = (dc->pc + sdisp) |
((uint64_t) CTPR_TAG_DISP << CTPR_TAG_OFF) |
((uint64_t) ipd << CTPR_IPD_OFF);
if (type == LDISP) {
reg |= (uint64_t) CTPR_OPC_LDISP << CTPR_OPC_OFF;
}
tcg_gen_movi_tl(e2k_cs.ctprs[ctpr - 1], reg);
} else if (type == SDISP) {
unsigned int disp = extract32(cs0, 0, 28) << 11;
target_ulong base = ((uint64_t) 0xe2 << 40) | disp;
uint64_t reg = (dc->pc + base) |
((uint64_t) CTPR_TAG_SDISP << CTPR_TAG_OFF) |
((uint64_t) ipd << CTPR_IPD_OFF);
tcg_gen_movi_tl(e2k_cs.ctprs[ctpr - 1], reg);
}
/* Note that RETURN is said to be COPF1. I can't understand what its
`CS0.param' is needed for: all of the bits except the three
lowermost ones are undefined, while the latter also known as "type"
field should be filled in with zeroes. */
if (type == RETURN) {
TCGv_i32 t0 = tcg_const_i32(ipd);
if (ctpr != 3) {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPN);
}
gen_helper_prep_return(e2k_cs.ctprs[2], cpu_env, t0);
tcg_temp_free_i32(t0);
}
/* GETTSD has as meaningless `CS0.param' as RETURN. The only
difference is that its `CS0.param.type' should be equal to `1'. I
wonder if I should check for that and output something like
"invalid gettsd" if this turns out not to be the case . . . */
if (type == GETTSD) {
// TODO: gettsd
e2k_todo_illop(dc, "gettsd");
}
if (type == PUTTSD) {
// unsigned int disp = (cs0 & 0x0fffffff);
// int sgnd_disp = ((int) (disp << 4)) >> 1;
/* PUTTSD obviously doesn't take %ctpr{j} parameter. TODO: beware of
an optional predicate which may control its execution which is
encoded via `SS.ctcond.psrc' and `SS.ts_opc == PUTTSDC{P,N}' in
case of `SS.type == 1' (see C.21.4). I wonder if `ct %ctpr<j>'
encoded in `SS.ctop' under the same `SS.ctcond' takes an effect in
such a case. */
// my_printf ("%s0x%llx", type == PUTTSD ? "" : ", ",
/* FIXME: this way I ensure that it'll work correctly
both on 32 and 64-bit hosts. */
// (unsigned long long) (instr_addr + sgnd_disp));
// TODO: puttsd
e2k_todo_illop(dc, "puttsd");
}
if (type == PREF) {
// unsigned int pdisp = (bundle->cs0 & 0x0ffffff0) >> 4;
// unsigned int ipd = (bundle->cs0 & 0x00000008) >> 3;
// unsigned int prefr = bundle->cs0 & 0x00000007;
// TODO: pref
e2k_todo_illop(dc, "pref");
}
}
}
static void gen_cs1(DisasContext *dc)
{
enum {
SETR0,
SETR1,
SETEI,
WAIT,
SETBR,
CALL,
MAS_OPC,
FLUSHR,
BG
};
const UnpackedBundle *bundle = &dc->bundle;
unsigned int cs1 = bundle->cs1;
unsigned int opc = (cs1 & 0xf0000000) >> 28;
if (opc == SETEI) {
bool sft = GET_BIT(cs1, 27);
if (sft) {
if (dc->version >= 2) {
// TODO: setsft
e2k_todo_illop(dc, "setsft");
} else {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
}
} else {
// uint8_t eir = GET_FIELD_LEN(cs1, 0, 8);
// TODO: setei
e2k_todo_illop(dc, "setei");
}
} else if (opc == WAIT) {
// unsigned int ma_c = (cs1 & 0x00000020) >> 5;
// unsigned int fl_c = (cs1 & 0x00000010) >> 4;
unsigned int ld_c = (cs1 & 0x00000008) >> 3;
unsigned int st_c = (cs1 & 0x00000004) >> 2;
// unsigned int all_e = (cs1 & 0x00000002) >> 1;
// unsigned int all_c = cs1 & 0x00000001;
if (dc->version >= 5) {
/* `sa{l,s}' fields are `elbrus-v5'-specific. Each of them makes sense
only in the presence of `{ld,st}_c == 1' respectively. */
if (ld_c) {
// unsigned int sal = (cs1 & 0x00000100) >> 8;
// my_printf ("sal = %d, ", sal);
}
if (st_c) {
// unsigned int sas = (cs1 & 0x00000080) >> 7;
// my_printf ("sas = %d, ", sas);
}
}
if (dc->version >= 2) {
/* `trap' field was introduced starting from `elbrus-v2'. */
// unsigned int trap = (cs1 & 0x00000040) >> 6;
// my_printf ("trap = %d, ", trap);
}
// TODO: wait
e2k_todo(dc, "wait");
// my_printf ("ma_c = %d, fl_c = %d, ld_c = %d, st_c = %d, all_e = %d, "
// "all_c = %d", ma_c, fl_c, ld_c, st_c, all_e, all_c);
} else if (opc == CALL) {
unsigned int ctop = (bundle->ss & 0x00000c00) >> 10;
if (ctop) {
dc->ct.type = CT_CALL;
dc->ct.wbs = extract32(cs1, 0, 7);
} else {
unsigned int cs1_ctopc = (cs1 & 0x380) >> 7;
/* CS1.param.ctpopc == HCALL. CS0 is required to encode HCALL. */
if (cs1_ctopc == 2 && bundle->cs0_present)
{
unsigned int cs0 = bundle->cs0;
unsigned int cs0_opc = (cs0 & 0xf0000000) >> 28;
if (cs0_opc == 0) {
// unsigned int hdisp = (cs0 & 0x1e) >> 1;
// TODO: hcall hdisp, wbs ? cond
e2k_todo_illop(dc, "hcall");
}
} else {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
}
}
} else if (opc == MAS_OPC) {
dc->mas[0] = extract32(cs1, 21, 7);
dc->mas[2] = extract32(cs1, 14, 7);
dc->mas[3] = extract32(cs1, 7, 7);
dc->mas[5] = extract32(cs1, 0, 7);
} else if (opc == FLUSHR) {
if (cs1 & 0x00000001) {
// TODO: flushr
e2k_todo_illop(dc, "flushr");
}
if (cs1 & 0x00000002) {
// TODO: flushc
e2k_todo_illop(dc, "flushc");
}
} else if (opc == BG) {
// unsigned int chkm4 = (cs1 & 0x00010000) >> 16;
// unsigned int dmask = (cs1 & 0x0000ff00) >> 8;
// unsigned int umsk = cs1 & 0x000000ff;
// TODO: vfbg
e2k_todo_illop(dc, "vfbg");
}
}
void e2k_decode_jmp(DisasContext *ctx)
{
int cond_type = extract32(ctx->bundle.ss, 5, 4);
int ctpr = extract32(ctx->bundle.ss, 10, 2);
if (ctpr != 0) {
if (ctx->ct.type == CT_NONE) {
ctx->ct.type = CT_JUMP;
}
ctx->ct.u.ctpr = e2k_cs.ctprs[ctpr - 1];
}
ctx->ct.is_branch = cond_type > 1;
if (cond_type == 1) {
tcg_gen_movi_i32(e2k_cs.ct_cond, 1);
} else if (cond_type > 1) {
uint8_t psrc = extract32(ctx->bundle.ss, 0, 5);
TCGv_i32 pcond = tcg_temp_local_new_i32();
TCGv_i32 lcond = tcg_temp_local_new_i32();
switch (cond_type) {
case 0x2:
case 0x6:
case 0xf:
/* %predN */
e2k_gen_preg_i32(pcond, psrc);
break;
case 0x3:
case 0x7:
case 0xe: {
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_preg_i32(t0, psrc);
tcg_gen_setcondi_i32(TCG_COND_EQ, pcond, t0, 0);
tcg_temp_free_i32(t0);
break;
}
default:
break;
}
switch (cond_type) {
case 0x4:
case 0x6:
case 0xe:
/* #LOOP_END */
e2k_gen_is_loop_end_i32(lcond);
break;
case 0x5:
case 0x7:
case 0xf: { /* #NOT_LOOP_END */
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_is_loop_end_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_EQ, lcond, t0, 0);
tcg_temp_free_i32(t0);
break;
}
}
switch (cond_type) {
case 0x2:
case 0x3:
/* {,~}%predN */
tcg_gen_mov_i32(e2k_cs.ct_cond, pcond);
break;
case 0x4:
case 0x5:
/* #{,NOT_}LOOP_END */
tcg_gen_mov_i32(e2k_cs.ct_cond, lcond);
break;
case 0x6:
case 0xe: {
/* {,~}%predN || #LOOP_END */
TCGv_i32 z = tcg_const_i32(0);
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_or_i32(t0, pcond, lcond);
tcg_gen_movcond_i32(TCG_COND_EQ, e2k_cs.ct_cond,
ctx->is_prologue, z, t0, lcond);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(z);
break;
}
case 0x7:
case 0xf: {
/* {,~}%predN && #NOT_LOOP_END */
TCGv_i32 z = tcg_const_i32(0);
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_and_i32(t0, pcond, lcond);
tcg_gen_movcond_i32(TCG_COND_EQ, e2k_cs.ct_cond,
ctx->is_prologue, z, t0, lcond);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(z);
break;
}
case 0x8:
/* %MLOCK || %dt_alM */
if (psrc & 0xf) {
// static const int conv[] = {0, 1, 3, 4};
int i;
e2k_todo(ctx, "%%MLOCK || %%dt_alM");
// %dt_al
for (i = 0; i < 4; i++) {
if (psrc & (1 << i)) {
// i
}
}
} else {
/* %MLOCK */
if (ctx->mlock) {
tcg_gen_mov_i32(e2k_cs.ct_cond, ctx->mlock);
} else {
tcg_gen_movi_i32(e2k_cs.ct_cond, 0);
}
}
break;
case 0x9: {
/* `lock_cond || pl_cond' control transfer conditions. */
unsigned int type = (psrc & 0x18) >> 3;
if (type == 0) {
// static const int cmp_num_to_alc[] = {0, 1, 3, 4};
// unsigned int cmp_num = (psrc & 0x6) >> 1;
// unsigned int neg = psrc & 0x1;
//
// my_printf ("%%MLOCK || %s%%cmp%d", neg ? "~" : "",
// cmp_num_to_alc[cmp_num]);
e2k_todo(ctx, "%%MLOCK || %%cmpN");
} else if (type == 1) {
// unsigned int cmp_jk = (psrc & 0x4) >> 2;
// unsigned int negj = (psrc & 0x2) >> 1;
// unsigned int negk = psrc & 0x1;
// my_printf ("%%MLOCK || %s%%cmp%d || %s%%cmp%d",
// negj ? "~" : "", cmp_jk == 0 ? 0 : 3,
// negk ? "~" : "", cmp_jk == 0 ? 1 : 4);
e2k_todo(ctx, "%%MLOCK || %%cmpN || %%cmpM");
} else if (type == 2) {
// unsigned int clp_num = (psrc & 0x6) >> 1;
// unsigned int neg = psrc & 0x1;
// "%%MLOCK || %s%%clp%d", neg ? "~" : "", clp_num
e2k_todo(ctx, "%%MLOCK || %%clpN");
}
break;
}
default:
e2k_todo_illop(ctx, "undefined control transfer type %#x", cond_type);
break;
}
tcg_temp_free_i32(lcond);
tcg_temp_free_i32(pcond);
}
}
void e2k_control_window_change(DisasContext *dc)
{
enum {
SETR0,
SETR1,
SETEI,
WAIT,
SETBR,
CALL,
MAS_OPC,
FLUSHR,
BG
};
const UnpackedBundle *bundle = &dc->bundle;
uint32_t cs1 = bundle->cs1;
int opc = extract32(cs1, 28, 4);
if (!dc->bundle.cs1_present) {
return;
}
if (opc == SETR0 || opc == SETR1 || opc == SETBR) {
bool setbp = (cs1 >> 27) & 1;
bool setbn = (cs1 >> 26) & 1;
if (opc == SETR1) {
if (!bundle->lts_present[0]) {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
} else {
/* Find out if VFRPSZ is always encoded together with SETWD. This
seems to be the case even if no SETWD has been explicitly
specified. */
// unsigned int rpsz = (bundle->lts[0] & 0x0001f000) >> 12;
e2k_todo(dc, "vfrpsz");
}
}
if (opc == SETR0 || opc == SETR1) {
if (!bundle->lts_present[0]) {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
} else {
TCGv_i32 lts = tcg_const_i32(bundle->lts[0]);
gen_helper_setwd(cpu_env, lts);
tcg_temp_free_i32(lts);
}
}
if (setbn) {
int rbs = extract32(cs1, BR_RBS_OFF, BR_RBS_LEN);
int rsz = extract32(cs1, BR_RSZ_OFF, BR_RSZ_LEN);
int rcur = extract32(cs1, BR_RCUR_OFF, BR_RCUR_LEN);
tcg_gen_movi_i32(e2k_cs.boff, rbs * 2);
tcg_gen_movi_i32(e2k_cs.bsize, (rsz + 1) * 2);
tcg_gen_movi_i32(e2k_cs.bcur, rcur * 2);
}
if (setbp) {
int psz = extract32(cs1, BR_PSZ_OFF, BR_PSZ_LEN);
tcg_gen_movi_i32(e2k_cs.psize, psz);
tcg_gen_movi_i32(e2k_cs.pcur, 0);
}
}
}
static void gen_prologue_epilogue(DisasContext *ctx)
{
TCGv_i32 t0 = tcg_temp_new_i32();
ctx->is_prologue = e2k_get_temp_i32(ctx);
e2k_gen_pcnt_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_NE, ctx->is_prologue, t0, 0);
ctx->is_epilogue = e2k_get_temp_i32(ctx);
e2k_gen_lcnt_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_EQ, ctx->is_epilogue, t0, 0);
tcg_temp_free_i32(t0);
}
void e2k_control_execute(DisasContext *ctx)
{
ctx->ct.type = CT_NONE;
ctx->loop_mode = (ctx->bundle.hs & (1 << 10)) != 0;
gen_prologue_epilogue(ctx);
if (ctx->bundle.cs0_present) {
gen_cs0(ctx);
}
if (ctx->bundle.cs1_present) {
gen_cs1(ctx);
}
}

View File

@ -15,13 +15,11 @@ void e2k_gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc)
{
if (psrc & 0x80) {
if (psrc == 0xc0) {
// TODO: %bgrpred
qemu_log_mask(LOG_UNIMP, "%#lx: %%bgrpred is not implemented!\n", ctx->pc);
abort();
// %bgrpred
e2k_todo_illop(ctx, "%%bgrpred");
} else if ((psrc & 0xe0) == 0xc0) {
// TODO: %rndpredN
qemu_log_mask(LOG_UNIMP, "%#lx: %%rndpred is not implemented!\n", ctx->pc);
abort();
// %rndpred
e2k_todo_illop(ctx, "%%rndpred");
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
}
@ -31,19 +29,14 @@ void e2k_gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc)
// %lcntex
e2k_gen_lcntex(ret);
} else if ((psrc & 0x40) == 0) {
// TODO: %spredMASK
qemu_log_mask(LOG_UNIMP, "%#lx: %%spred is not implemented!\n", ctx->pc);
abort();
// %spredMASK
e2k_todo_illop(ctx, "%%spred");
} else if ((psrc & 0x60) == 0x60) {
// %predN
e2k_gen_preg_i32(ret, idx);
} else {
// %pcntN
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_pcnt_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_LEU, ret, t0, idx);
tcg_temp_free_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_LEU, ret, e2k_cs.lsr_pcnt, idx);
}
}
}
@ -163,18 +156,15 @@ void e2k_plu_execute(DisasContext *ctx)
tcg_gen_and_i32(lp[4 + i], p0, p1);
if (vdst) {
TCGv_i32 one = tcg_const_i32(1);
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 z = tcg_const_i32(0);
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_preg_i64(t0, pdst);
tcg_gen_extrl_i64_i32(t1, t0);
tcg_gen_movcond_i32(TCG_COND_EQ, ctx->pl_results[i].value,
p0, one, p1, t1);
e2k_gen_preg_i32(t0, pdst);
tcg_gen_movcond_i32(TCG_COND_NE, ctx->pl_results[i].value,
p0, z, p1, t0);
tcg_temp_free_i32(t1);
tcg_temp_free_i64(t0);
tcg_temp_free_i32(one);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(z);
}
break;
}

View File

@ -68,7 +68,7 @@ static void gen_preg_clear(TCGv_i64 ret, TCGv_i64 offset)
tcg_temp_free_i64(t0);
}
void e2k_gen_preg_i64(TCGv_i64 ret, int reg)
static inline void gen_preg_i64(TCGv_i64 ret, int reg)
{
TCGv_i64 one = tcg_const_i64(1);
TCGv_i64 t0 = tcg_temp_new_i64();
@ -90,18 +90,11 @@ void e2k_gen_preg_i32(TCGv_i32 ret, int reg)
{
TCGv_i64 t0 = tcg_temp_new_i64();
e2k_gen_preg_i64(t0, reg);
gen_preg_i64(t0, reg);
tcg_gen_extrl_i64_i32(ret, t0);
tcg_temp_free_i64(t0);
}
TCGv_i64 e2k_get_preg(DisasContext *dc, int reg)
{
TCGv_i64 ret = e2k_get_temp_i64(dc);
e2k_gen_preg_i64(ret, reg);
return ret;
}
void e2k_gen_store_preg(int idx, TCGv_i32 val)
{
TCGv_i64 t0 = tcg_temp_new_i64();