diff --git a/linux-user/e2k/cpu_loop.c b/linux-user/e2k/cpu_loop.c index 2ffc9ef22b..ed13946e8c 100644 --- a/linux-user/e2k/cpu_loop.c +++ b/linux-user/e2k/cpu_loop.c @@ -37,6 +37,19 @@ void cpu_loop(CPUE2KState *env) process_queued_cpu_work(cs); switch (trapnr) { + case E2K_EXCP_SYSCALL: { + /* TODO: wrap register indices */ + uint64_t *regs = &env->wregs[env->wbs * 2]; + abi_ulong ret = do_syscall(env, regs[0], + regs[1], regs[2], regs[3], regs[4], + regs[5], regs[6], regs[7], regs[8]); + if (ret == -TARGET_ERESTARTSYS) { + /* TODO: restart syscall */ + } else if (ret != -TARGET_QEMU_ESIGRETURN) { + regs[0] = ret; + } + break; + } default: fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, 0); diff --git a/target/e2k/cpu.h b/target/e2k/cpu.h index c24b177fb3..c1794c1071 100644 --- a/target/e2k/cpu.h +++ b/target/e2k/cpu.h @@ -13,6 +13,10 @@ void e2k_tcg_initialize(void); // size of regular reg in bytes #define REG_SIZE (sizeof(target_ulong)) +typedef enum { + E2K_EXCP_SYSCALL = 0x01, +} Exception; + struct e2k_def_t { const char *name; uint32_t isa_version; diff --git a/target/e2k/helper.c b/target/e2k/helper.c index 267ed34f8f..924ce61db5 100644 --- a/target/e2k/helper.c +++ b/target/e2k/helper.c @@ -3,6 +3,7 @@ #include "exec/exec-all.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" +#include "translate.h" void helper_raise_exception(CPUE2KState *env, int tt) { @@ -11,3 +12,14 @@ void helper_raise_exception(CPUE2KState *env, int tt) cs->exception_index = tt; cpu_loop_exit(cs); } + +void helper_check_syscall_ctpr(CPUE2KState *env, uint64_t ctpr) +{ + int tag = GET_FIELD(ctpr, CTPR_TAG_OFF, CTPR_TAG_END); + if (tag == CTPR_TAG_SDISP) { + CPUState *cs = env_cpu(env); + + cs->exception_index = E2K_EXCP_SYSCALL; + cpu_loop_exit(cs); + } +} diff --git a/target/e2k/helper.h b/target/e2k/helper.h index df6a36e18f..1db6921d5f 100644 --- a/target/e2k/helper.h +++ b/target/e2k/helper.h @@ -1,3 +1,4 @@ // include/exec/helper-proto.h needs this file DEF_HELPER_2(raise_exception, noreturn, env, int) +DEF_HELPER_2(check_syscall_ctpr, void, env, i64) diff --git a/target/e2k/translate.c b/target/e2k/translate.c index 9baa6d1e56..a71f232432 100644 --- a/target/e2k/translate.c +++ b/target/e2k/translate.c @@ -1,7 +1,5 @@ #include "qemu/osdep.h" #include "qemu.h" -#include "tcg/tcg-op.h" -#include "exec/translator.h" #include "exec/log.h" #include "disas/disas.h" #include "translate.h" @@ -202,76 +200,6 @@ void e2k_gen_exception(DisasContext *dc, int which) dc->base.is_jmp = DISAS_NORETURN; } -static target_ulong disas_e2k_insn(DisasContext *dc, CPUState *cs) -{ - E2KCPU *cpu = E2K_CPU(cs); - CPUE2KState *env = &cpu->env; - UnpackedBundle *bundle = &dc->bundle; - unsigned int bundle_len = unpack_bundle(env, dc->pc, bundle); - /* TODO: exception, check bundle_len */ - target_ulong pc_next = dc->pc + bundle_len; - - dc->jmp.dest = tcg_const_i64(0); - dc->jmp.cond = tcg_const_i64(0); - - e2k_alc_gen(dc); - e2k_control_gen(dc); - - e2k_alc_commit(dc); - e2k_win_commit(dc); - - /* Control transfer */ - switch(dc->base.is_jmp) { - case DISAS_NEXT: - case DISAS_TOO_MANY: - dc->base.pc_next = pc_next; - break; - case DISAS_NORETURN: - /* exception */ - tcg_gen_movi_tl(e2k_cs.pc, dc->pc); - tcg_gen_exit_tb(NULL, 0); - break; - case STATIC_JUMP: - tcg_gen_mov_i64(e2k_cs.pc, dc->jmp.dest); - tcg_gen_exit_tb(NULL, 0); - break; - case DYNAMIC_JUMP: { - TCGv_i64 one = tcg_const_i64(1); - TCGv_i64 next = tcg_const_i64(pc_next); - tcg_gen_movcond_i64(TCG_COND_EQ, e2k_cs.pc, - dc->jmp.cond, one, - dc->jmp.dest, next - ); - tcg_temp_free_i64(next); - tcg_temp_free_i64(one); - tcg_gen_exit_tb(NULL, 0); - break; - } - default: - /* TODO: unreachable */ - abort(); - break; - } - - tcg_temp_free_i64(dc->jmp.dest); - tcg_temp_free_i64(dc->jmp.cond); - - /* Free temporary values */ - while(dc->t32_len) { - tcg_temp_free_i32(dc->t32[--dc->t32_len]); - } - - while(dc->t64_len) { - tcg_temp_free_i64(dc->t64[--dc->t64_len]); - } - - while(dc->ttl_len) { - tcg_temp_free(dc->ttl[--dc->ttl_len]); - } - - return pc_next; -} - static void e2k_tr_init_disas_context(DisasContextBase *db, CPUState *cs) { DisasContext *dc = container_of(db, DisasContext, base); @@ -299,19 +227,80 @@ static bool e2k_tr_breakpoint_check(DisasContextBase *db, CPUState *cs, static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs) { DisasContext *dc = container_of(db, DisasContext, base); + E2KCPU *cpu = E2K_CPU(cs); + CPUE2KState *env = &cpu->env; + UnpackedBundle *bundle = &dc->bundle; dc->pc = dc->base.pc_next; - disas_e2k_insn(dc, cs); + unsigned int bundle_len = unpack_bundle(env, dc->pc, bundle); + /* TODO: exception, check bundle_len */ + dc->base.pc_next = dc->pc + bundle_len; + + e2k_alc_gen(dc); + e2k_control_gen(dc); + + e2k_alc_commit(dc); + e2k_win_commit(dc); + + /* Free temporary values */ + while(dc->t32_len) { + tcg_temp_free_i32(dc->t32[--dc->t32_len]); + } + + while(dc->t64_len) { + tcg_temp_free_i64(dc->t64[--dc->t64_len]); + } + + while(dc->ttl_len) { + tcg_temp_free(dc->ttl[--dc->ttl_len]); + } } static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs) { + DisasContext *dc = container_of(db, DisasContext, base); + + dc->jmp.dest = tcg_const_i64(0); + dc->jmp.cond = tcg_const_i64(0); } static void e2k_tr_tb_stop(DisasContextBase *db, CPUState *cs) { -// DisasContext *dc = container_of(db, DisasContext, base); -// E2KCPU *cpu = E2K_CPU(cs); + DisasContext *dc = container_of(db, DisasContext, base); + E2KCPU *cpu = E2K_CPU(cs); // CPUE2KState *env = &cpu->env; + + /* Control transfer */ + switch(dc->base.is_jmp) { + case DISAS_NEXT: + case DISAS_TOO_MANY: + break; + case DISAS_NORETURN: + /* exception */ + tcg_gen_movi_tl(e2k_cs.pc, dc->pc); + tcg_gen_exit_tb(NULL, 0); + break; + case STATIC_JUMP: + tcg_gen_mov_i64(e2k_cs.pc, dc->jmp.dest); + tcg_gen_exit_tb(NULL, 0); + break; + case DYNAMIC_JUMP: { + TCGv_i64 one = tcg_const_i64(1); + tcg_gen_movcond_i64(TCG_COND_EQ, e2k_cs.pc, + dc->jmp.cond, one, + dc->jmp.dest, e2k_cs.pc + ); + tcg_temp_free_i64(one); + tcg_gen_exit_tb(NULL, 0); + break; + } + default: + /* TODO: unreachable */ + abort(); + break; + } + + tcg_temp_free_i64(dc->jmp.dest); + tcg_temp_free_i64(dc->jmp.cond); } static void e2k_tr_disas_log(const DisasContextBase *db, CPUState *cpu) diff --git a/target/e2k/translate.h b/target/e2k/translate.h index 007f2bab8b..24b6c79538 100644 --- a/target/e2k/translate.h +++ b/target/e2k/translate.h @@ -1,15 +1,17 @@ #ifndef E2K_TRANSLATE_H #define E2K_TRANSLATE_H +#include "tcg/tcg-op.h" #include "exec/translator.h" #define STATIC_JUMP DISAS_TARGET_0 #define DYNAMIC_JUMP DISAS_TARGET_1 -#define GEN_MASK(start, end) (((1 << ((end) - (start) + 1)) - 1) << start) +#define GEN_MASK(type, start, end) \ + ((((type) 1 << ((end) - (start) + 1)) - 1) << start) #define GET_BIT(v, index) (((v) >> (index)) & 1) #define GET_FIELD(v, start, end) \ - (((v) & GEN_MASK(start, end)) >> (start)) + (((v) >> (start)) & ((1 << ((end) - (start) + 1)) - 1)) #define IS_BASED(i) (((i) & 0x80) == 0) #define IS_REGULAR(i) (((i) & 0xc0) == 0x80) @@ -29,7 +31,27 @@ #define GET_LIT(i) ((i) & 0x03) #define GET_GLOBAL(i) ((i) & 0x1f) -typedef enum AlesFlag { +#define CTPR_BASE_OFF 0 +#define CTPR_BASE_END 47 +#define CTPR_TAG_OFF 54 +#define CTPR_TAG_END 56 +#define CTPR_OPC_OFF 57 +#define CTPR_OPC_END 58 +#define CTPR_IPD_OFF 59 +#define CTPR_IPD_END 60 + +typedef enum { + CTPR_TAG_RETURN = 0x2, + CTPR_TAG_DISP = 0x3, + CTPR_TAG_LDISP = 0x3, + CTPR_TAG_SDISP = 0x5, +} CtprTag; + +typedef enum { + CTPR_OPC_LDISP = 0x1, +} CtprOpc; + +typedef enum { ALES_NONE = 0x00, ALES_PRESENT = 0x01, ALES_ALLOCATED = 0x02, @@ -38,7 +60,6 @@ typedef enum AlesFlag { typedef struct CPUE2KStateTCG { TCGv pc; TCGv ctprs[3]; - TCGv_i32 is_jmp; TCGv_i32 wbs; TCGv_i32 wsz; TCGv_i32 nfx; @@ -153,7 +174,7 @@ static inline void e2k_gen_get_field_i64(TCGv_i64 ret, TCGv_i64 val, { TCGv_i64 t0 = tcg_temp_new_i64(); - tcg_gen_and_i64(t0, val, GEN_MASK(start, end)); + tcg_gen_andi_i64(t0, val, GEN_MASK(uint64_t, start, end)); tcg_gen_shli_i64(ret, t0, start); tcg_temp_free_i64(t0); @@ -162,7 +183,7 @@ static inline void e2k_gen_get_field_i64(TCGv_i64 ret, TCGv_i64 val, static inline void e2k_gen_set_field_i64(TCGv_i64 ret, TCGv_i64 val, uint64_t field, unsigned int start, unsigned int end) { - uint64_t mask = GEN_MASK(start, end); + uint64_t mask = GEN_MASK(uint64_t, start, end); TCGv_i64 t0 = tcg_const_i64(~mask); TCGv_i64 t1 = tcg_const_i64((field << start) & mask); TCGv_i64 t2 = tcg_temp_new_i64(); diff --git a/target/e2k/translate/alc.c b/target/e2k/translate/alc.c index 8ac5a67d50..af58b63b83 100644 --- a/target/e2k/translate/alc.c +++ b/target/e2k/translate/alc.c @@ -1,8 +1,6 @@ #include "qemu/osdep.h" #include "qemu.h" -#include "tcg/tcg-op.h" #include "exec/log.h" -#include "exec/translator.h" #include "translate.h" static TCGv_i64 get_src1(DisasContext *dc, unsigned int als) diff --git a/target/e2k/translate/control.c b/target/e2k/translate/control.c index da6003c379..6ce4475a3c 100644 --- a/target/e2k/translate/control.c +++ b/target/e2k/translate/control.c @@ -1,8 +1,6 @@ #include "qemu/osdep.h" #include "qemu.h" -#include "tcg/tcg-op.h" #include "exec/log.h" -#include "exec/translator.h" #include "translate.h" static void gen_cs0(DisasContext *dc) @@ -82,14 +80,26 @@ static void gen_cs0(DisasContext *dc) // invalid abort(); } - - if (type == DISP || type == SDISP || type == LDISP) { - /* TODO: SDISP tag */ + int ipd = GET_FIELD(bundle->ss, 30, 31); + if (type == DISP || type == LDISP) { unsigned int disp = GET_FIELD(cs0, 0, 27); /* Calculate a signed displacement in bytes. */ int sdisp = ((int) (disp << 4)) >> 1; - target_ulong tgt = dc->pc + sdisp; - tcg_gen_movi_tl(e2k_cs.ctprs[ctpr], tgt); + 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], reg); + } else if (type == SDISP) { + unsigned int disp = GET_FIELD(cs0, 0, 27) << 11; + /* FIXME: trap address */ + 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], reg); } if (/* Note that RETURN is said to be COPF1. I can't understand what its @@ -250,9 +260,10 @@ static void gen_cs1(DisasContext *dc) unsigned int ctop = (bundle->ss & 0x00000c00) >> 10; /* In C.17.4 it's said that other bits in CS1.param except for the seven lowermost ones are ignored. */ -// unsigned int wbs = cs1 & 0x7f; + unsigned int wbs = cs1 & 0x7f; if (ctop) { + tcg_gen_movi_i32(e2k_cs.wbs, wbs); // my_printf ("call %%ctpr%d, wbs = 0x%x", ctop, wbs); // print_ctcond (info, instr->ss & 0x1ff); } else { @@ -315,8 +326,17 @@ static void gen_jmp(DisasContext *dc) /* TODO: check CPU behavior if present ibranch and ctpr is not zero */ + /* TODO: different kinds of ct */ if (ctpr != 0) { - tcg_gen_mov_tl(dc->jmp.dest, e2k_cs.ctprs[ctpr]); + TCGv_i64 t0 = tcg_temp_new_i64(); + + /* TODO: use save_state */ + tcg_gen_movi_i64(e2k_cs.pc, dc->pc); + gen_helper_check_syscall_ctpr(cpu_env, e2k_cs.ctprs[ctpr]); + tcg_gen_andi_i64(t0, e2k_cs.ctprs[ctpr], GEN_MASK(uint64_t, 0, 47)); + tcg_gen_mov_tl(dc->jmp.dest, t0); + + tcg_temp_free_i64(t0); } if (cond_type == 1) { diff --git a/target/e2k/translate/state.c b/target/e2k/translate/state.c index 3f815c8229..e425eb9cc1 100644 --- a/target/e2k/translate/state.c +++ b/target/e2k/translate/state.c @@ -1,8 +1,6 @@ #include "qemu/osdep.h" #include "qemu.h" -#include "tcg/tcg-op.h" #include "exec/log.h" -#include "exec/translator.h" #include "translate.h" TCGv_i64 e2k_get_preg(DisasContext *dc, int reg) diff --git a/target/e2k/translate/win.c b/target/e2k/translate/win.c index e9f5a79874..e039cdb65a 100644 --- a/target/e2k/translate/win.c +++ b/target/e2k/translate/win.c @@ -1,8 +1,6 @@ #include "qemu/osdep.h" #include "qemu.h" -#include "tcg/tcg-op.h" #include "exec/log.h" -#include "exec/translator.h" #include "translate.h" static inline void gen_abn_inc(DisasContext *dc, TCGCond cond)