e2k: Remove control.c
This commit is contained in:
parent
0b7f461be7
commit
23a0139ee6
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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',
|
||||
))
|
||||
|
@ -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[] = {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user