target: e2k: Add basic syscall support.

This commit is contained in:
Denis Drakhnia 2020-11-12 19:12:18 +02:00 committed by Alibek Omarov
parent 779fc80db4
commit 3e3508f9bd
8 changed files with 141 additions and 119 deletions

View File

@ -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
}

View File

@ -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)

View File

@ -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();
}
}

View File

@ -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)

View File

@ -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[] = {

View File

@ -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;

View File

@ -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)" : "");

View File

@ -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)