target: e2k: Add basic syscall support.
This commit is contained in:
parent
779fc80db4
commit
3e3508f9bd
|
@ -39,7 +39,7 @@ void cpu_loop(CPUE2KState *env)
|
|||
switch (trapnr) {
|
||||
case E2K_EXCP_SYSCALL: {
|
||||
/* TODO: wrap register indices */
|
||||
uint64_t *regs = &env->wregs[env->wbs * 2];
|
||||
uint64_t *regs = &env->wregs[env->wbs + env->syscall_wbs];
|
||||
abi_ulong ret = do_syscall(env, regs[0],
|
||||
regs[1], regs[2], regs[3], regs[4],
|
||||
regs[5], regs[6], regs[7], regs[8]);
|
||||
|
@ -62,5 +62,4 @@ void cpu_loop(CPUE2KState *env)
|
|||
void target_cpu_copy_regs(CPUE2KState *env, struct target_pt_regs *regs)
|
||||
{
|
||||
env->ip = regs->ip;
|
||||
// TODO
|
||||
}
|
||||
|
|
|
@ -14,7 +14,8 @@ void e2k_tcg_initialize(void);
|
|||
#define REG_SIZE (sizeof(target_ulong))
|
||||
|
||||
typedef enum {
|
||||
E2K_EXCP_SYSCALL = 0x01,
|
||||
E2K_EXCP_UNIMPL = 0x01,
|
||||
E2K_EXCP_SYSCALL = 0x02,
|
||||
} Exception;
|
||||
|
||||
struct e2k_def_t {
|
||||
|
@ -29,14 +30,15 @@ typedef struct {
|
|||
target_ulong wregs[WREGS_SIZE]; // window regs
|
||||
target_ulong *win_ptr;
|
||||
uint64_t pregs;
|
||||
uint32_t wbs; // window regs offset (* 2)
|
||||
uint32_t wsz; // window regs size (* 2)
|
||||
uint32_t wbs; // Real window regs offset, in bundle it comes divided by 2
|
||||
uint32_t wsz; // Real window regs size, in bundle it comes divided by 2
|
||||
uint32_t nfx; // TODO
|
||||
uint32_t dbl; // TODO
|
||||
uint32_t rbs; // based regs offset (* 2)
|
||||
uint32_t rsz; // based regs window size (* 2 + 2)
|
||||
uint32_t rcur; // based regs current index (* 2)
|
||||
uint32_t rbs; // Real based regs offset, in bundle it comes divided by 2
|
||||
uint32_t rsz; // Real based regs size, in bundle it comes divided by 2 minus 2
|
||||
uint32_t rcur; // Real based regs current index, in bundle it comes divided by 2
|
||||
uint32_t psz; // pred regs window size
|
||||
uint32_t syscall_wbs;
|
||||
|
||||
/* control registers */
|
||||
target_ulong ctprs[3]; // Control Transfer Preparation Register (CTPR)
|
||||
|
|
|
@ -13,13 +13,16 @@ void helper_raise_exception(CPUE2KState *env, int tt)
|
|||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
void helper_check_syscall_ctpr(CPUE2KState *env, uint64_t ctpr)
|
||||
void helper_call(CPUE2KState *env, uint64_t ctpr, uint64_t cond)
|
||||
{
|
||||
int tag = GET_FIELD(ctpr, CTPR_TAG_OFF, CTPR_TAG_END);
|
||||
if (tag == CTPR_TAG_SDISP) {
|
||||
if (tag == CTPR_TAG_SDISP && cond) {
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
cs->exception_index = E2K_EXCP_SYSCALL;
|
||||
cpu_loop_exit(cs);
|
||||
} else {
|
||||
/* TODO: call */
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +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)
|
||||
DEF_HELPER_3(call, void, env, i64, i64)
|
||||
|
|
|
@ -188,6 +188,7 @@ static target_ulong unpack_bundle(CPUE2KState *env,
|
|||
static inline void save_state(DisasContext *dc)
|
||||
{
|
||||
tcg_gen_movi_tl(e2k_cs.pc, dc->pc);
|
||||
tcg_gen_movi_tl(e2k_cs.pc, dc->npc);
|
||||
}
|
||||
|
||||
void e2k_gen_exception(DisasContext *dc, int which)
|
||||
|
@ -233,7 +234,7 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs)
|
|||
dc->pc = dc->base.pc_next;
|
||||
unsigned int bundle_len = unpack_bundle(env, dc->pc, bundle);
|
||||
/* TODO: exception, check bundle_len */
|
||||
dc->base.pc_next = dc->pc + bundle_len;
|
||||
dc->base.pc_next = dc->npc = dc->pc + bundle_len;
|
||||
|
||||
e2k_alc_gen(dc);
|
||||
e2k_control_gen(dc);
|
||||
|
@ -259,6 +260,7 @@ static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
|
|||
{
|
||||
DisasContext *dc = container_of(db, DisasContext, base);
|
||||
|
||||
dc->is_call = false;
|
||||
dc->jmp.dest = tcg_const_i64(0);
|
||||
dc->jmp.cond = tcg_const_i64(0);
|
||||
}
|
||||
|
@ -266,29 +268,36 @@ static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
|
|||
static void e2k_tr_tb_stop(DisasContextBase *db, CPUState *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 */
|
||||
case DISAS_CALL: {
|
||||
tcg_gen_movi_tl(e2k_cs.pc, dc->pc);
|
||||
tcg_gen_movi_tl(e2k_cs.pc, dc->npc);
|
||||
gen_helper_call(cpu_env, e2k_cs.ctprs[dc->call_ctpr], dc->jmp.cond);
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
break;
|
||||
}
|
||||
case DISAS_NORETURN: {
|
||||
/* exception */
|
||||
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 npc = tcg_const_i64(dc->npc);
|
||||
tcg_gen_movcond_i64(TCG_COND_EQ, e2k_cs.pc,
|
||||
dc->jmp.cond, one,
|
||||
dc->jmp.dest, e2k_cs.pc
|
||||
dc->jmp.dest, npc
|
||||
);
|
||||
tcg_temp_free_i64(npc);
|
||||
tcg_temp_free_i64(one);
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
break;
|
||||
|
@ -347,6 +356,7 @@ void e2k_tcg_initialize(void) {
|
|||
{ &e2k_cs.rsz, offsetof(CPUE2KState, rsz), "rsz" },
|
||||
{ &e2k_cs.rcur, offsetof(CPUE2KState, rcur), "rcur" },
|
||||
{ &e2k_cs.psz, offsetof(CPUE2KState, psz), "psz" },
|
||||
{ &e2k_cs.syscall_wbs, offsetof(CPUE2KState, syscall_wbs), "syscall_wbs" },
|
||||
};
|
||||
|
||||
static const struct { TCGv_i64 *ptr; int off; const char *name; } r64[] = {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#define STATIC_JUMP DISAS_TARGET_0
|
||||
#define DYNAMIC_JUMP DISAS_TARGET_1
|
||||
#define DISAS_CALL DISAS_TARGET_2
|
||||
|
||||
#define GEN_MASK(type, start, end) \
|
||||
((((type) 1 << ((end) - (start) + 1)) - 1) << start)
|
||||
|
@ -68,6 +69,7 @@ typedef struct CPUE2KStateTCG {
|
|||
TCGv_i32 rsz;
|
||||
TCGv_i32 rcur;
|
||||
TCGv_i32 psz;
|
||||
TCGv_i32 syscall_wbs;
|
||||
TCGv_ptr win_ptr;
|
||||
TCGv_i64 wregs[WREGS_SIZE];
|
||||
TCGv_i64 gregs[32];
|
||||
|
@ -121,12 +123,15 @@ typedef struct DisasContext {
|
|||
DisasContextBase base;
|
||||
UnpackedBundle bundle;
|
||||
target_ulong pc;
|
||||
target_ulong npc;
|
||||
bool is_call;
|
||||
int call_ctpr;
|
||||
|
||||
int version;
|
||||
|
||||
// Temporary values.
|
||||
TCGv_i32 t32[16];
|
||||
TCGv_i64 t64[16];
|
||||
TCGv_i64 t64[32];
|
||||
TCGv ttl[8];
|
||||
// Allocated temporary values count.
|
||||
int t32_len;
|
||||
|
|
|
@ -262,7 +262,7 @@ static void gen_channel(DisasContext *dc, int chan)
|
|||
break;
|
||||
}
|
||||
case 0x40: // TODO: udivs used as temporary UD
|
||||
e2k_gen_exception(dc, 1);
|
||||
e2k_gen_exception(dc, E2K_EXCP_UNIMPL);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "gen_alc: undefined instruction 0x%x %s\n", opc, sm ? "(speculative)" : "");
|
||||
|
|
|
@ -263,7 +263,8 @@ static void gen_cs1(DisasContext *dc)
|
|||
unsigned int wbs = cs1 & 0x7f;
|
||||
|
||||
if (ctop) {
|
||||
tcg_gen_movi_i32(e2k_cs.wbs, wbs);
|
||||
dc->is_call = true;
|
||||
tcg_gen_movi_i32(e2k_cs.syscall_wbs, wbs * 2);
|
||||
// my_printf ("call %%ctpr%d, wbs = 0x%x", ctop, wbs);
|
||||
// print_ctcond (info, instr->ss & 0x1ff);
|
||||
} else {
|
||||
|
@ -324,116 +325,118 @@ static void gen_jmp(DisasContext *dc)
|
|||
unsigned int cond_type = GET_FIELD(dc->bundle.ss, 5, 8);
|
||||
unsigned int ctpr = GET_FIELD(dc->bundle.ss, 10, 11);
|
||||
|
||||
if (cond_type == 1) {
|
||||
dc->base.is_jmp = STATIC_JUMP;
|
||||
tcg_gen_movi_i64(dc->jmp.cond, 1);
|
||||
} else {
|
||||
dc->base.is_jmp = DYNAMIC_JUMP;
|
||||
|
||||
if (cond_type == 2 || cond_type == 6 || cond_type == 0xf) {
|
||||
/* if pred is true */
|
||||
tcg_gen_mov_i64(dc->jmp.cond, e2k_get_preg(dc, psrc));
|
||||
} else if (cond_type == 3 || cond_type == 7 || cond_type == 0xe) {
|
||||
/* if pred is false */
|
||||
TCGv_i64 one = tcg_const_i64(1);
|
||||
TCGv_i64 zero = tcg_const_i64(0);
|
||||
tcg_gen_movcond_i64(TCG_COND_EQ, dc->jmp.cond,
|
||||
e2k_get_preg(dc, psrc), zero,
|
||||
one, zero);
|
||||
tcg_temp_free_i64(zero);
|
||||
tcg_temp_free_i64(one);
|
||||
}
|
||||
|
||||
/* TODO: other kinds of conditions */
|
||||
|
||||
if (cond_type == 4
|
||||
|| cond_type == 6
|
||||
|| cond_type == 0xe)
|
||||
{
|
||||
if (cond_type == 6 || cond_type == 0xe) {
|
||||
// or
|
||||
}
|
||||
|
||||
// %LOOP_END
|
||||
}
|
||||
|
||||
if (cond_type == 5
|
||||
|| cond_type == 7
|
||||
|| cond_type == 0xf)
|
||||
{
|
||||
if(cond_type == 7
|
||||
|| cond_type == 0xf)
|
||||
{
|
||||
// AND
|
||||
}
|
||||
// %NOT_LOOP_END
|
||||
}
|
||||
|
||||
if (cond_type == 8) {
|
||||
// %MLOCK
|
||||
/* It's not clearly said in C.17.1.2 of iset-vX.single if the uppermost
|
||||
fourth bit in `psrc' has any meaning at all. */
|
||||
if (psrc & 0xf) {
|
||||
// static const int conv[] = {0, 1, 3, 4};
|
||||
int i;
|
||||
|
||||
// %dt_al
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (psrc & (1 << i)) {
|
||||
// i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* `lock_cond || pl_cond' control transfer conditions. */
|
||||
if (cond_type == 9) {
|
||||
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]);
|
||||
} 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);
|
||||
} else if (type == 2) {
|
||||
// unsigned int clp_num = (psrc & 0x6) >> 1;
|
||||
// unsigned int neg = psrc & 0x1;
|
||||
|
||||
// "%%MLOCK || %s%%clp%d", neg ? "~" : "", clp_num
|
||||
}
|
||||
}
|
||||
|
||||
if (cond_type >= 0xa && cond_type <= 0xd) {
|
||||
// reserved condition type
|
||||
qemu_log_mask(LOG_UNIMP, "Undefined control transfer type %#x\n", cond_type);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: check CPU behavior if present ibranch and ctpr is not zero */
|
||||
|
||||
/* TODO: different kinds of ct */
|
||||
if (ctpr != 0) {
|
||||
if (dc->is_call) {
|
||||
/* TODO: call save state */
|
||||
dc->call_ctpr = ctpr;
|
||||
dc->base.is_jmp = DISAS_CALL;
|
||||
return;
|
||||
}
|
||||
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) {
|
||||
dc->base.is_jmp = STATIC_JUMP;
|
||||
tcg_gen_movi_i64(dc->jmp.cond, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
dc->base.is_jmp = DYNAMIC_JUMP;
|
||||
|
||||
if (cond_type == 2 || cond_type == 6 || cond_type == 0xf) {
|
||||
/* if pred is true */
|
||||
tcg_gen_mov_i64(dc->jmp.cond, e2k_get_preg(dc, psrc));
|
||||
} else if (cond_type == 3 || cond_type == 7 || cond_type == 0xe) {
|
||||
/* if pred is false */
|
||||
TCGv_i64 one = tcg_const_i64(1);
|
||||
TCGv_i64 zero = tcg_const_i64(0);
|
||||
tcg_gen_movcond_i64(TCG_COND_EQ, dc->jmp.cond,
|
||||
e2k_get_preg(dc, psrc), zero,
|
||||
one, zero);
|
||||
tcg_temp_free_i64(zero);
|
||||
tcg_temp_free_i64(one);
|
||||
}
|
||||
|
||||
/* TODO: other kinds of conditions */
|
||||
|
||||
if (cond_type == 4
|
||||
|| cond_type == 6
|
||||
|| cond_type == 0xe)
|
||||
{
|
||||
if (cond_type == 6 || cond_type == 0xe) {
|
||||
// or
|
||||
}
|
||||
|
||||
// %LOOP_END
|
||||
}
|
||||
|
||||
if (cond_type == 5
|
||||
|| cond_type == 7
|
||||
|| cond_type == 0xf)
|
||||
{
|
||||
if(cond_type == 7
|
||||
|| cond_type == 0xf)
|
||||
{
|
||||
// AND
|
||||
}
|
||||
// %NOT_LOOP_END
|
||||
}
|
||||
|
||||
if (cond_type == 8) {
|
||||
// %MLOCK
|
||||
/* It's not clearly said in C.17.1.2 of iset-vX.single if the uppermost
|
||||
fourth bit in `psrc' has any meaning at all. */
|
||||
if (psrc & 0xf) {
|
||||
// static const int conv[] = {0, 1, 3, 4};
|
||||
int i;
|
||||
|
||||
// %dt_al
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (psrc & (1 << i)) {
|
||||
// i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* `lock_cond || pl_cond' control transfer conditions. */
|
||||
if (cond_type == 9) {
|
||||
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]);
|
||||
} 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);
|
||||
} else if (type == 2) {
|
||||
// unsigned int clp_num = (psrc & 0x6) >> 1;
|
||||
// unsigned int neg = psrc & 0x1;
|
||||
|
||||
// "%%MLOCK || %s%%clp%d", neg ? "~" : "", clp_num
|
||||
}
|
||||
}
|
||||
|
||||
if (cond_type >= 0xa && cond_type <= 0xd) {
|
||||
// reserved condition type
|
||||
qemu_log_mask(LOG_UNIMP, "Undefined control transfer type %#x\n", cond_type);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void e2k_control_gen(DisasContext *dc)
|
||||
|
|
Loading…
Reference in New Issue