target: e2k: Reorg + basic gdb debugging.

This commit is contained in:
Denis Drakhnia 2020-11-17 20:58:22 +02:00 committed by Alibek Omarov
parent 8e1c3d2401
commit 17d175a2d8
10 changed files with 442 additions and 385 deletions

View File

@ -26,7 +26,7 @@ void cpu_loop(CPUE2KState *env)
{
CPUState *cs = env_cpu(env);
int trapnr; //TODO , n, sig;
//target_siginfo_t info;
target_siginfo_t info;
//target_ulong addr;
//abi_long ret;
@ -37,9 +37,16 @@ void cpu_loop(CPUE2KState *env)
process_queued_cpu_work(cs);
switch (trapnr) {
case E2K_EXCP_UNIMPL:
info.si_signo = TARGET_SIGABRT;
info.si_errno = 0;
info.si_code = 0;
info._sifields._sigfault._addr = env->ip;
queue_signal(env, info.si_signo, QEMU_SI_KILL, &info);
break;
case E2K_EXCP_SYSCALL: {
int wbs = e2k_state_wbs_get(env);
int offset = (wbs + env->call_wbs) * 2;
int offset = wbs * 2;
uint64_t *regs = env->wregs;
abi_ulong ret = do_syscall(env,
regs[(0 + offset) % WREGS_SIZE],
@ -66,13 +73,33 @@ void cpu_loop(CPUE2KState *env)
env->ip = env->nip;
break;
}
case E2K_EXCP_ILLOPC:
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPC;
info._sifields._sigfault._addr = env->ip;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case E2K_EXCP_ILLOPN:
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->ip;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case E2K_EXCP_MAPERR:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->ip;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
/* QEMU common interrupts */
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
case EXCP_DEBUG:
{
target_siginfo_t info;
info.si_signo = TARGET_SIGTRAP;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;

View File

@ -43,6 +43,8 @@ static void e2k_cpu_reset(DeviceState *dev)
memset(env, 0, offsetof(CPUE2KState, end_reset_fields));
env->wptr = &env->wregs[0];
env->woff = 0;
env->wsize = 16;
}
static bool e2k_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
@ -148,6 +150,8 @@ static void e2k_cpu_set_pc(CPUState *cs, vaddr value)
{
E2KCPU *cpu = E2K_CPU(cs);
qemu_log_mask(LOG_UNIMP, "e2k_cpu_synchronize_from_tb: not implemented\n");
cpu->env.ip = value;
}
@ -155,6 +159,8 @@ static void e2k_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
{
E2KCPU *cpu = E2K_CPU(cs);
qemu_log_mask(LOG_UNIMP, "e2k_cpu_synchronize_from_tb: not implemented\n");
cpu->env.ip = tb->pc;
}

View File

@ -14,6 +14,8 @@ void e2k_tcg_initialize(void);
#define GET_BIT(v, index) (((v) >> (index)) & 1)
#define GET_FIELD(v, start, end) \
(((v) >> (start)) & ((1UL << ((end) - (start) + 1)) - 1))
#define GET_FIELD_LEN(v, s, l) \
(((v) >> (s)) & GEN_MASK_LEN(0, l))
#define SET_FIELD(v, f, s, l) \
( \
((v) & ~GEN_MASK_LEN((s), (l))) | \
@ -41,6 +43,18 @@ void e2k_tcg_initialize(void);
#define CTPR_IPD_OFF 59
#define CTPR_IPD_END 60
#define WD_BASE_OFF 0
#define WD_BASE_END 10
#define WD_BASE_LEN (WD_BASE_END - WD_BASE_OFF + 1)
#define WD_SIZE_OFF 16
#define WD_SIZE_END 26
#define WD_SIZE_LEN (WD_SIZE_END - WD_SIZE_OFF + 1)
#define WD_PSIZE_OFF 32
#define WD_PSIZE_END 42
#define WD_PSIZE_LEN (WD_PSIZE_END - WD_PSIZE_OFF + 1)
#define WD_FX_OFF 48
#define WD_FX_BIT (1 << WD_FX_OFF)
#define PCSP_HI_IND_OFF 0 /* index for SPILL */
#define PCSP_HI_IND_END 31
#define PCSP_HI_IND_LEN (PCSP_HI_IND_END - PCSP_HI_IND_OFF + 1)
@ -177,6 +191,9 @@ void e2k_tcg_initialize(void);
typedef enum {
E2K_EXCP_UNIMPL = 0x01,
E2K_EXCP_SYSCALL = 0x02,
E2K_EXCP_ILLOPC = 0x03,
E2K_EXCP_ILLOPN = 0x04,
E2K_EXCP_MAPERR = 0x05,
} Exception;
struct e2k_def_t {
@ -207,7 +224,6 @@ typedef struct {
uint64_t lsr; /* loop status register */
uint32_t call_wbs;
uint32_t woff; /* holds wbs * 2 */
uint32_t wsize; /* holds wsz * 2 */
uint32_t boff; /* holds rbs * 2 */
@ -226,8 +242,6 @@ typedef struct {
target_ulong ip; /* instruction address */
target_ulong nip; /* next instruction address */
uint32_t cond; /* branch condition */
uint32_t pfpfr; // Packed Floating Point Flag Register (PFPFR)
uint32_t fpcr; // Floating point control register (FPCR)
uint32_t fpsr; // Floating point state register (FPSR)

View File

@ -58,7 +58,7 @@ int e2k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
case 51: return gdb_get_reg64(mem_buf, env->pshtp); // pshtp
case 52: return gdb_get_reg64(mem_buf, 0); // unk
case 53: return gdb_get_reg64(mem_buf, env->ip); // ip
case 54: return gdb_get_reg64(mem_buf, 0); // unk (mem)
case 54: return gdb_get_reg64(mem_buf, 0); // TODO: something associated with wd
case 55: return gdb_get_reg64(mem_buf, 0); // unk
case 56: return gdb_get_reg64(mem_buf, 0); // cwd
case 57: return gdb_get_reg64(mem_buf, env->pcsp_lo); // pcsp_lo

View File

@ -6,7 +6,16 @@
#include "exec/helper-proto.h"
#include "translate.h"
static inline void save_state(CPUE2KState *env)
static inline void reset_ctprs(CPUE2KState *env)
{
unsigned int i;
for (i = 0; i < 4; i++) {
env->ctprs[i] = 0;
}
}
void helper_save_cpu_state(CPUE2KState *env)
{
uint32_t br = 0;
@ -48,10 +57,18 @@ static inline void restore_state(CPUE2KState *env)
env->wsize = wsz * 2;
}
void helper_unimpl(CPUE2KState *env)
{
CPUState *cs = env_cpu(env);
cs->exception_index = E2K_EXCP_UNIMPL;
cpu_loop_exit(cs);
}
void helper_raise_exception(CPUE2KState *env, int tt)
{
CPUState *cs = env_cpu(env);
save_state(env);
helper_save_cpu_state(env);
cs->exception_index = tt;
cpu_loop_exit(cs);
}
@ -59,7 +76,7 @@ void helper_raise_exception(CPUE2KState *env, int tt)
void helper_debug(CPUE2KState *env)
{
CPUState *cs = env_cpu(env);
save_state(env);
helper_save_cpu_state(env);
cs->exception_index = EXCP_DEBUG;
cpu_loop_exit(cs);
}
@ -138,14 +155,14 @@ static void ps_pop(CPUE2KState *env, unsigned int wbs, size_t len)
e2k_state_ps_ind_set(env, index);
}
static inline void do_call(CPUE2KState *env, target_ulong ctpr)
static inline void do_call(CPUE2KState *env, int call_wbs)
{
int wbs, wsz, new_wbs, new_wsz;
wbs = e2k_state_wbs_get(env);
wsz = e2k_state_wsz_get(env);
new_wbs = (wbs + env->call_wbs) % (WREGS_SIZE / 2);
new_wsz = wsz - env->call_wbs;
new_wbs = (wbs + call_wbs) % (WREGS_SIZE / 2);
new_wsz = wsz - call_wbs;
if (new_wsz < 0) {
/* TODO: SIGSEGV */
@ -155,13 +172,14 @@ static inline void do_call(CPUE2KState *env, target_ulong ctpr)
/* save procedure chain info */
pcs_push(env);
/* save regs */
ps_push(env, wbs * 2, env->call_wbs * 2);
ps_push(env, wbs * 2, call_wbs * 2);
e2k_state_wbs_set(env, new_wbs);
e2k_state_wsz_set(env, new_wsz);
/* restore woff, wsize, etc */
restore_state(env);
reset_ctprs(env);
}
static uint64_t do_return(CPUE2KState *env)
@ -184,71 +202,63 @@ static uint64_t do_return(CPUE2KState *env)
/* restore woff, wsize, etc */
restore_state(env);
reset_ctprs(env);
return tgt;
}
static inline void reset_ctprs(CPUE2KState *env)
static inline void do_syscall(CPUE2KState *env, int call_wbs)
{
unsigned int i;
for (i = 0; i < 4; i++) {
env->ctprs[i] = 0;
}
do_call(env, call_wbs);
helper_raise_exception(env, E2K_EXCP_SYSCALL);
do_return(env);
reset_ctprs(env);
}
target_ulong helper_jump(CPUE2KState *env, int i)
target_ulong helper_jump(CPUE2KState *env, target_ulong cond, uint64_t ctpr)
{
return helper_branch(env, i, true);
}
target_ulong helper_branch(CPUE2KState *env, int i, target_ulong cond)
{
CPUState *cs = env_cpu(env);
uint64_t ctpr = env->ctprs[i];
target_ulong tgt = 0;
int ctpr_tag = GET_FIELD(ctpr, CTPR_TAG_OFF, CTPR_TAG_END);
save_state(env);
helper_save_cpu_state(env);
if (!cond) {
return env->nip;
}
switch (ctpr_tag) {
case CTPR_TAG_RETURN:
if (cond) {
tgt = do_return(env);
reset_ctprs(env);
}
break;
case CTPR_TAG_DISP: {
return do_return(env);
case CTPR_TAG_DISP:
/* TODO: ldisp */
return GET_FIELD(ctpr, CTPR_BASE_OFF, CTPR_BASE_END);
default:
helper_raise_exception(env, E2K_EXCP_UNIMPL);
return env->nip;
}
}
if (env->call_wbs != 0 && cond) {
do_call(env, ctpr);
reset_ctprs(env);
}
tgt = GET_FIELD(ctpr, CTPR_BASE_OFF, CTPR_BASE_END);
break;
}
case CTPR_TAG_SDISP: {
if (cond) {
if (env->call_wbs != 0) {
reset_ctprs(env);
cs->exception_index = E2K_EXCP_SYSCALL;
cpu_loop_exit(cs);
} else {
cs->exception_index = E2K_EXCP_UNIMPL;
cpu_loop_exit(cs);
}
}
break;
}
default: {
cs->exception_index = E2K_EXCP_UNIMPL;
cpu_loop_exit(cs);
break;
}
target_ulong helper_call(CPUE2KState *env, target_ulong cond, uint64_t ctpr,
int call_wbs)
{
int ctpr_tag = GET_FIELD(ctpr, CTPR_TAG_OFF, CTPR_TAG_END);
helper_save_cpu_state(env);
if (!cond) {
return env->nip;
}
return tgt;
switch (ctpr_tag) {
case CTPR_TAG_DISP:
do_call(env, call_wbs);
return GET_FIELD(ctpr, CTPR_BASE_OFF, CTPR_BASE_END);
case CTPR_TAG_SDISP:
do_syscall(env, call_wbs);
return env->nip;
default:
helper_raise_exception(env, E2K_EXCP_UNIMPL);
return env->nip;
}
}
uint64_t helper_sxt(uint64_t x, uint64_t y)
@ -340,8 +350,7 @@ uint32_t helper_cur_dec(CPUE2KState *env, uint32_t cur, uint32_t n,
uint32_t size)
{
if (size == 0) {
/* FIXME: SIGSEGV */
helper_raise_exception(env, E2K_EXCP_UNIMPL);
helper_raise_exception(env, E2K_EXCP_MAPERR);
}
return size - (size + n - cur) % size;

View File

@ -1,7 +1,9 @@
DEF_HELPER_1(save_cpu_state, void, env)
DEF_HELPER_1(unimpl, noreturn, env)
DEF_HELPER_2(raise_exception, noreturn, env, int)
DEF_HELPER_1(debug, void, env)
DEF_HELPER_2(jump, tl, env, int)
DEF_HELPER_3(branch, tl, env, int, tl)
DEF_HELPER_3(jump, tl, env, tl, i64)
DEF_HELPER_4(call, tl, env, tl, i64, int)
DEF_HELPER_2(sxt, i64, i64, i64)
DEF_HELPER_1(debug_i32, void, i32)
DEF_HELPER_1(debug_i64, void, i64)

View File

@ -7,7 +7,7 @@
struct CPUE2KStateTCG e2k_cs;
/* returns zero if bundle is invalid */
static target_ulong unpack_bundle(CPUE2KState *env,
static size_t unpack_bundle(CPUE2KState *env,
target_ulong pc, UnpackedBundle *bundle)
{
unsigned int gap;
@ -185,10 +185,21 @@ static target_ulong unpack_bundle(CPUE2KState *env,
return 8 + GET_FIELD(hs, 4, 6) * 8;
}
static inline void save_pc(DisasContext *dc)
static inline void gen_save_pc(target_ulong pc)
{
tcg_gen_movi_tl(e2k_cs.pc, dc->pc);
tcg_gen_movi_tl(e2k_cs.npc, dc->npc);
tcg_gen_movi_tl(e2k_cs.pc, pc);
}
static inline void gen_save_npc(target_ulong npc)
{
tcg_gen_movi_tl(e2k_cs.npc, npc);
}
static inline void gen_save_cpu_state(DisasContext *ctx)
{
gen_save_pc(ctx->pc);
gen_save_npc(ctx->npc);
gen_helper_save_cpu_state(cpu_env);
}
static inline bool use_goto_tb(DisasContext *s, target_ulong pc,
@ -206,15 +217,15 @@ static inline bool use_goto_tb(DisasContext *s, target_ulong pc,
#endif
}
static inline void gen_goto_tb(DisasContext *dc, int tb_num,
static inline void gen_goto_tb(DisasContext *ctx, int tb_num,
target_ulong pc, target_ulong npc)
{
if (use_goto_tb(dc, pc, npc)) {
if (use_goto_tb(ctx, pc, npc)) {
/* 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_movi_tl(e2k_cs.npc, npc);
tcg_gen_exit_tb(dc->base.tb, tb_num);
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);
@ -223,148 +234,210 @@ static inline void gen_goto_tb(DisasContext *dc, int tb_num,
}
}
void e2k_gen_exception(DisasContext *dc, int which)
void e2k_gen_exception(DisasContext *ctx, int which)
{
TCGv_i32 t = tcg_const_i32(which);
save_pc(dc);
gen_save_cpu_state(ctx);
gen_helper_raise_exception(cpu_env, t);
tcg_gen_exit_tb(NULL, 0);
dc->base.is_jmp = DISAS_NORETURN;
ctx->base.is_jmp = DISAS_NORETURN;
tcg_temp_free_i32(t);
}
static inline void do_decode(DisasContext *ctx, CPUState *cs)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
UnpackedBundle *bundle = &ctx->bundle;
unsigned int bundle_len;
ctx->pc = ctx->base.pc_next;
bundle_len = unpack_bundle(env, ctx->pc, bundle);
/* TODO: exception, check bundle_len */
ctx->npc = ctx->base.pc_next = ctx->pc + bundle_len;
}
/*
* Executes instructions from a bundle and store the results to
* temporary buffer.
*/
static inline void do_execute(DisasContext *ctx)
{
unsigned int i;
for (i = 0; i < 6; i++) {
if (ctx->bundle.als_present[i]) {
ctx->alc[i].tag = RESULT_NONE;
e2k_execute_alc(ctx, i);
}
}
e2k_control_gen(ctx);
}
/*
* Writes results of instructions from a bundle to the state
*
* Note
* ====
*
* Must not generate any exception.
* */
static inline void do_commit(DisasContext *ctx)
{
unsigned int i;
for (i = 0; i < 6; i++) {
Result *res = &ctx->alc[i];
if (!ctx->bundle.als_present[i]) {
continue;
}
switch(res->tag) {
case RESULT_BASED_REG:
e2k_gen_store_breg(res->u.reg.i, res->u.reg.v);
break;
case RESULT_REGULAR_REG:
e2k_gen_store_wreg(res->u.reg.i, res->u.reg.v);
break;
case RESULT_GLOBAL_REG:
e2k_gen_store_greg(res->u.reg.i, res->u.reg.v);
break;
case RESULT_PREG:
e2k_gen_store_preg(res->u.reg.i, res->u.reg.v);
break;
default:
break;
}
}
e2k_commit_stubs(ctx);
}
static inline void do_branch(DisasContext *ctx)
{
switch(ctx->ct.type) {
case CT_IBRANCH:
ctx->base.is_jmp = DISAS_NORETURN;
if (ctx->ct.has_cond) {
TCGLabel *l = gen_new_label();
tcg_gen_brcondi_tl(TCG_COND_NE, ctx->ct.cond, 0, l);
tcg_gen_movi_tl(e2k_cs.pc, ctx->npc);
tcg_gen_exit_tb(NULL, 0);
gen_set_label(l);
}
// TODO: goto_tb
tcg_gen_movi_tl(e2k_cs.pc, ctx->ct.u.target);
tcg_gen_exit_tb(NULL, 0);
break;
case CT_JUMP:
ctx->base.is_jmp = DISAS_NORETURN;
gen_save_cpu_state(ctx);
gen_helper_jump(e2k_cs.pc, cpu_env, ctx->ct.cond, ctx->ct.u.ctpr);
tcg_gen_lookup_and_goto_ptr();
break;
case CT_CALL:
{
TCGv_i32 wbs = tcg_const_i32(ctx->ct.wbs);
ctx->base.is_jmp = DISAS_NORETURN;
gen_save_cpu_state(ctx);
gen_helper_call(e2k_cs.pc, cpu_env, ctx->ct.cond, ctx->ct.u.ctpr, wbs);
tcg_temp_free_i32(wbs);
tcg_gen_lookup_and_goto_ptr();
break;
}
default:
break;
}
}
static void e2k_tr_init_disas_context(DisasContextBase *db, CPUState *cs)
{
DisasContext *dc = container_of(db, DisasContext, base);
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
dc->pc = 0;
dc->npc = dc->base.pc_first;
dc->version = env->version;
}
static bool e2k_tr_breakpoint_check(DisasContextBase *db, CPUState *cs,
const CPUBreakpoint *bp)
{
DisasContext *dc = container_of(db, DisasContext, base);
tcg_gen_movi_tl(e2k_cs.pc, dc->base.pc_next);
tcg_gen_movi_tl(e2k_cs.npc, dc->npc);
gen_helper_debug(cpu_env);
tcg_gen_exit_tb(NULL, 0);
dc->base.is_jmp = DISAS_NORETURN;
/*
* The address covered by the breakpoint must be included in
* [tb->pc, tb->pc + tb->size) in order to for it to be
* properly cleared -- thus we increment the PC here so that
* the logic setting tb->size below does the right thing.
*/
dc->base.pc_next += 1;
return true;
}
static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
{
DisasContext *ctx = container_of(db, DisasContext, base);
ctx->ct.cond = tcg_const_tl(1);
}
static void e2k_tr_insn_start(DisasContextBase *db, CPUState *cs)
{
DisasContext *dc = container_of(db, DisasContext, base);
tcg_gen_insn_start(dc->pc);
}
static bool e2k_tr_breakpoint_check(DisasContextBase *db, CPUState *cs,
const CPUBreakpoint *bp)
{
DisasContext *dc = container_of(db, DisasContext, base);
if (dc->pc != dc->base.pc_first) {
save_pc(dc);
}
gen_helper_debug(cpu_env);
tcg_gen_exit_tb(NULL, 0);
dc->base.is_jmp = DISAS_NORETURN;
dc->base.pc_next = dc->npc;
return true;
}
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;
unsigned int bundle_len;
DisasContext *ctx = container_of(db, DisasContext, base);
dc->pc = dc->npc;
bundle_len = unpack_bundle(env, dc->pc, bundle);
/* TODO: exception, check bundle_len */
dc->npc = dc->base.pc_next = dc->pc + bundle_len;
e2k_alc_gen(dc);
e2k_control_gen(dc);
e2k_alc_commit(dc);
e2k_win_commit(dc);
do_decode(ctx, cs);
do_execute(ctx);
do_commit(ctx);
do_branch(ctx);
/* Free temporary values */
while(dc->t32_len) {
tcg_temp_free_i32(dc->t32[--dc->t32_len]);
while(ctx->t32_len) {
tcg_temp_free_i32(ctx->t32[--ctx->t32_len]);
}
while(dc->t64_len) {
tcg_temp_free_i64(dc->t64[--dc->t64_len]);
while(ctx->t64_len) {
tcg_temp_free_i64(ctx->t64[--ctx->t64_len]);
}
while(dc->ttl_len) {
tcg_temp_free(dc->ttl[--dc->ttl_len]);
while(ctx->ttl_len) {
tcg_temp_free(ctx->ttl[--ctx->ttl_len]);
}
}
static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
{
tcg_gen_movi_tl(e2k_cs.cond, 0);
tcg_gen_movi_i32(e2k_cs.call_wbs, 0);
}
static void e2k_tr_tb_stop(DisasContextBase *db, CPUState *cs)
{
DisasContext *dc = container_of(db, DisasContext, base);
DisasContext *ctx = container_of(db, DisasContext, base);
/* Control transfer */
switch(dc->base.is_jmp) {
switch(ctx->base.is_jmp) {
case DISAS_NEXT:
case DISAS_TOO_MANY:
gen_goto_tb(dc, 0, dc->pc, dc->npc);
gen_helper_save_cpu_state(cpu_env);
gen_goto_tb(ctx, 0, ctx->pc, ctx->npc);
break;
case DISAS_NORETURN:
break;
case DISAS_JUMP_STATIC:
gen_goto_tb(dc, 0, dc->pc, dc->jmp.dest);
break;
case DISAS_BRANCH_STATIC: {
TCGv z = tcg_const_tl(0);
TCGv t = tcg_const_tl(dc->jmp.dest);
TCGv f = tcg_const_tl(dc->npc);
tcg_gen_movcond_tl(TCG_COND_NE, e2k_cs.pc, e2k_cs.cond, z, t, f);
tcg_gen_exit_tb(NULL, 0);
tcg_temp_free(f);
tcg_temp_free(t);
tcg_temp_free(z);
break;
}
case DISAS_JUMP: {
TCGv_i32 ctpr = tcg_const_i32(dc->jump_ctpr);
save_pc(dc);
gen_helper_jump(e2k_cs.pc, cpu_env, ctpr);
tcg_gen_exit_tb(NULL, 0);
tcg_temp_free_i32(ctpr);
break;
}
case DISAS_BRANCH: {
TCGv_i32 ctpr = tcg_const_i32(dc->jump_ctpr);
TCGv z = tcg_const_tl(0);
TCGv t = tcg_temp_new();
TCGv f = tcg_const_tl(dc->npc);
save_pc(dc);
gen_helper_branch(t, cpu_env, ctpr, e2k_cs.cond);
tcg_gen_movcond_tl(TCG_COND_NE, e2k_cs.pc, e2k_cs.cond, z, t, f);
tcg_gen_exit_tb(NULL, 0);
tcg_temp_free(f);
tcg_temp_free(t);
tcg_temp_free(z);
tcg_temp_free_i32(ctpr);
break;
}
default:
g_assert_not_reached();
break;
}
tcg_temp_free(ctx->ct.cond);
}
static void e2k_tr_disas_log(const DisasContextBase *db, CPUState *cpu)
@ -378,8 +451,8 @@ static void e2k_tr_disas_log(const DisasContextBase *db, CPUState *cpu)
static const TranslatorOps e2k_tr_ops = {
.init_disas_context = e2k_tr_init_disas_context,
.tb_start = e2k_tr_tb_start,
.insn_start = e2k_tr_insn_start,
.breakpoint_check = e2k_tr_breakpoint_check,
.insn_start = e2k_tr_insn_start,
.translate_insn = e2k_tr_translate_insn,
.tb_stop = e2k_tr_tb_stop,
.disas_log = e2k_tr_disas_log,
@ -395,6 +468,8 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
void restore_state_to_opc(CPUE2KState *env, TranslationBlock *tb,
target_ulong *data)
{
// target_ulong pc = data[0];
// target_ulong npc = data[0];
// TODO
qemu_log_mask(LOG_UNIMP, "restore_state_to_opc: not implemented\n");
}
@ -403,7 +478,6 @@ void e2k_tcg_initialize(void) {
char buf[16] = { 0 };
static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
{ &e2k_cs.call_wbs, offsetof(CPUE2KState, call_wbs), "call_wbs" },
{ &e2k_cs.woff, offsetof(CPUE2KState, woff), "woff" },
{ &e2k_cs.wsize, offsetof(CPUE2KState, wsize), "wsize" },
{ &e2k_cs.boff, offsetof(CPUE2KState, boff), "boff" },
@ -421,7 +495,6 @@ void e2k_tcg_initialize(void) {
static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {
{ &e2k_cs.pc, offsetof(CPUE2KState, ip), "pc" },
{ &e2k_cs.npc, offsetof(CPUE2KState, nip), "npc" },
{ &e2k_cs.cond, offsetof(CPUE2KState, cond), "cond" },
};
unsigned int i;

View File

@ -58,9 +58,7 @@ typedef struct CPUE2KStateTCG {
TCGv pc;
TCGv npc;
TCGv ctprs[4];
TCGv cond;
TCGv_i64 lsr;
TCGv_i32 call_wbs;
TCGv_i64 wregs[WREGS_SIZE];
TCGv_i64 gregs[GREGS_SIZE];
TCGv_ptr wptr; /* pointer to wregs */
@ -117,6 +115,24 @@ typedef struct {
} u;
} Result;
typedef enum {
CT_NONE,
CT_IBRANCH,
CT_JUMP,
CT_CALL,
} ControlTransferType;
typedef struct {
bool has_cond;
TCGv cond;
ControlTransferType type;
union {
target_ulong target;
TCGv_i64 ctpr;
} u;
int wbs;
} ControlTransfer;
typedef struct DisasContext {
DisasContextBase base;
UnpackedBundle bundle;
@ -136,12 +152,8 @@ typedef struct DisasContext {
int t64_len;
int ttl_len;
/* TODO: move to CPUE2KState */
Result alc[6];
/* TODO: move to CPUE2KState */
struct {
target_ulong dest; /* ibranch dst */
} jmp;
ControlTransfer ct;
} DisasContext;
static inline TCGv_i32 e2k_get_temp_i32(DisasContext *dc)
@ -258,9 +270,9 @@ void e2k_gen_exception(DisasContext *dc, int which);
void e2k_control_gen(DisasContext *dc);
void e2k_alc_gen(DisasContext *dc);
void e2k_execute_alc(DisasContext *ctx, int index);
void e2k_alc_commit(DisasContext *dc);
void e2k_win_commit(DisasContext *dc);
void e2k_commit_stubs(DisasContext *dc);
#endif

View File

@ -50,12 +50,14 @@ static TCGv_i64 get_src2(DisasContext *dc, uint32_t als)
} else if (IS_LIT32(src2)) {
// nop
} else if (IS_LIT64(src2) && i < 3) {
// TODO: exception
assert(dc->bundle.lts_present[i + 1]);
if (!dc->bundle.lts_present[i + 1]) {
// TODO: check what exception must be raised
e2k_gen_exception(dc, E2K_EXCP_MAPERR);
}
lit |= ((uint64_t) dc->bundle.lts[i + 1]) << 32;
} else {
// TODO: exception
abort();
// TODO: check what exception must be raised
e2k_gen_exception(dc, E2K_EXCP_MAPERR);
}
tcg_gen_movi_i64(t, lit);
return t;
@ -79,8 +81,10 @@ static TCGv_i64 get_dst(DisasContext *dc, unsigned int als)
return e2k_get_greg(dc, i);
} else {
// TODO: %empty, %ctpr, etc
abort();
gen_helper_unimpl(cpu_env);
}
// TODO: remove
return e2k_get_temp_i64(dc);
}
/* FIXME: now only %r, %b, %g */
@ -100,8 +104,8 @@ static void store_reg_alc_result(DisasContext *dc, int chan, TCGv_i64 val)
res->tag = RESULT_GLOBAL_REG;
res->u.reg.i = GET_GLOBAL(dst);
} else {
/* TODO: exception */
abort();
// TODO: %empty, %ctpr, etc
gen_helper_unimpl(cpu_env);
}
}
@ -441,11 +445,10 @@ static void gen_alopf1_mrgc_i64(DisasContext *dc, int chan)
tcg_temp_free_i64(cond);
}
static void gen_alopf_simple(DisasContext *dc, int chan)
static void execute_alopf_simple(DisasContext *dc, int chan)
{
uint32_t als = dc->bundle.als[chan];
int opc = GET_FIELD(als, 24, 30);
int sm = GET_BIT(als, 31);
switch(opc) {
case 0x00: /* ands */ gen_alopf1_i32(dc, chan, tcg_gen_and_i32); break;
@ -477,8 +480,8 @@ static void gen_alopf_simple(DisasContext *dc, int chan)
case 0x1b: /* shrd */ gen_alopf1_i64(dc, chan, tcg_gen_shr_i64); break;
case 0x1c: /* sars */ gen_alopf1_i32(dc, chan, tcg_gen_sar_i32); break;
case 0x1d: /* sard */ gen_alopf1_i64(dc, chan, tcg_gen_sar_i64); break;
case 0x1e: /* TODO: getfs */ abort(); break;
case 0x1f: /* TODO: getfd */ abort(); break;
case 0x1e: /* TODO: getfs */ gen_helper_unimpl(cpu_env); break;
case 0x1f: /* TODO: getfd */ gen_helper_unimpl(cpu_env); break;
case 0x21: { // cmp{op}db
TCGv_i64 cpu_src1 = get_src1(dc, als);
TCGv_i64 cpu_src2 = get_src2(dc, als);
@ -489,12 +492,12 @@ static void gen_alopf_simple(DisasContext *dc, int chan)
unsigned int cmp_op = GET_FIELD(als, 5, 7);
// TODO: move to separate function
switch(cmp_op) {
case 0: abort(); break;
case 0: gen_helper_unimpl(cpu_env); break;
case 1: cond = TCG_COND_LTU; break;
case 2: cond = TCG_COND_EQ; break;
case 3: cond = TCG_COND_LEU; break;
case 4: abort(); break;
case 5: abort(); break;
case 4: gen_helper_unimpl(cpu_env); break;
case 5: gen_helper_unimpl(cpu_env); break;
case 6: cond = TCG_COND_LT; break;
case 7: cond = TCG_COND_LE; break;
default: g_assert_not_reached(); break;
@ -514,8 +517,7 @@ static void gen_alopf_simple(DisasContext *dc, int chan)
if (chan == 2 || chan == 5) {
gen_st(dc, chan, MO_UB);
} else {
/* TODO: exception */
abort();
gen_helper_unimpl(cpu_env);
}
break;
}
@ -523,8 +525,7 @@ static void gen_alopf_simple(DisasContext *dc, int chan)
if (chan == 2 || chan == 5) {
gen_st(dc, chan, MO_TEUW);
} else {
/* TODO: exception */
abort();
gen_helper_unimpl(cpu_env);
}
break;
}
@ -532,8 +533,7 @@ static void gen_alopf_simple(DisasContext *dc, int chan)
if (chan == 2 || chan == 5) {
gen_st(dc, chan, MO_TEUL);
} else {
/* TODO: exception */
abort();
gen_helper_unimpl(cpu_env);
}
break;
}
@ -541,8 +541,7 @@ static void gen_alopf_simple(DisasContext *dc, int chan)
if (chan == 2 || chan == 5) {
gen_st(dc, chan, MO_TEQ);
} else {
/* TODO: exception */
abort();
gen_helper_unimpl(cpu_env);
}
break;
}
@ -551,16 +550,14 @@ static void gen_alopf_simple(DisasContext *dc, int chan)
break;
case 0x61:
if (chan == 2 || chan == 5) {
/* TODO: exception */
abort();
gen_helper_unimpl(cpu_env);
} else {
gen_movtd(dc, chan);
}
break;
case 0x64: { /* ldb */
if (chan == 2 || chan == 5) {
/* TODO: exception */
abort();
gen_helper_unimpl(cpu_env);
} else {
gen_ld(dc, chan, MO_UB);
}
@ -568,8 +565,7 @@ static void gen_alopf_simple(DisasContext *dc, int chan)
}
case 0x65: { /* ldh */
if (chan == 2 || chan == 5) {
/* TODO: exception */
abort();
gen_helper_unimpl(cpu_env);
} else {
gen_ld(dc, chan, MO_TEUW);
}
@ -577,8 +573,7 @@ static void gen_alopf_simple(DisasContext *dc, int chan)
}
case 0x66: { /* ldw */
if (chan == 2 || chan == 5) {
/* TODO: exception */
abort();
gen_helper_unimpl(cpu_env);
} else {
gen_ld(dc, chan, MO_TEUL);
}
@ -586,20 +581,19 @@ static void gen_alopf_simple(DisasContext *dc, int chan)
}
case 0x67: { /* ldd */
if (chan == 2 || chan == 5) {
/* TODO: exception */
abort();
gen_helper_unimpl(cpu_env);
} else {
gen_ld(dc, chan, MO_TEQ);
}
break;
}
default:
qemu_log_mask(LOG_UNIMP, "gen_alc: undefined instruction 0x%x %s\n", opc, sm ? "(speculative)" : "");
e2k_gen_exception(dc, E2K_EXCP_ILLOPC);
break;
}
}
static void gen_ext1(DisasContext *dc, int chan)
static void execute_ext1(DisasContext *dc, int chan)
{
uint8_t opc = GET_FIELD(dc->bundle.als[chan], 24, 30);
@ -621,26 +615,25 @@ static void gen_ext1(DisasContext *dc, int chan)
}
}
static void gen_channel(DisasContext *dc, int chan)
void e2k_execute_alc(DisasContext *ctx, int index)
{
const UnpackedBundle *bundle = &dc->bundle;
const UnpackedBundle *bundle = &ctx->bundle;
switch(bundle->ales_present[chan]) {
switch(bundle->ales_present[index]) {
case ALES_NONE:
gen_alopf_simple(dc, chan);
execute_alopf_simple(ctx, index);
break;
case ALES_ALLOCATED: // 2 or 5 channel
abort();
e2k_gen_exception(ctx, E2K_EXCP_ILLOPC);
break;
case ALES_PRESENT: {
uint8_t opc = GET_FIELD(bundle->ales[chan], 8, 15);
uint8_t opc = GET_FIELD(bundle->ales[index], 8, 15);
switch (opc) {
case 0x01:
gen_ext1(dc, chan);
execute_ext1(ctx, index);
break;
default:
/* TODO */
abort();
e2k_gen_exception(ctx, E2K_EXCP_ILLOPC);
break;
}
break;
@ -650,44 +643,3 @@ static void gen_channel(DisasContext *dc, int chan)
break;
}
}
void e2k_alc_gen(DisasContext *dc)
{
unsigned int i;
for (i = 0; i < 6; i++) {
if (!dc->bundle.als_present[i]) {
continue;
}
dc->alc[i].tag = RESULT_NONE;
gen_channel(dc, i);
}
}
void e2k_alc_commit(DisasContext *dc)
{
unsigned int i;
for (i = 0; i < 6; i++) {
Result *res = &dc->alc[i];
if (!dc->bundle.als_present[i]) {
continue;
}
switch(res->tag) {
case RESULT_BASED_REG:
e2k_gen_store_breg(res->u.reg.i, res->u.reg.v);
break;
case RESULT_REGULAR_REG:
e2k_gen_store_wreg(res->u.reg.i, res->u.reg.v);
break;
case RESULT_GLOBAL_REG:
e2k_gen_store_greg(res->u.reg.i, res->u.reg.v);
break;
case RESULT_PREG:
e2k_gen_store_preg(res->u.reg.i, res->u.reg.v);
break;
default:
break;
}
}
}

View File

@ -94,14 +94,15 @@ static inline void gen_movcond_flag_i64(TCGv_i64 ret, int flag, TCGv_i64 cond,
tcg_temp_free_i64(one);
}
static inline void gen_cur_dec(TCGv_i32 ret, int cond, TCGv_i32 cur, int n,
static inline void gen_cur_dec(DisasContext *ctx, TCGv_i32 ret, int cond,
TCGv_i32 cur, int n,
TCGv_i32 size)
{
TCGv_i32 c = tcg_temp_new_i32();
TCGv_i32 t0 = tcg_const_i32(n);
TCGv_i32 t1 = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(c, e2k_cs.cond);
tcg_gen_trunc_tl_i32(c, ctx->ct.cond);
gen_helper_cur_dec(t1, cpu_env, cur, t0, size);
gen_movcond_flag_i32(ret, cond, c, t1, cur);
@ -110,54 +111,48 @@ static inline void gen_cur_dec(TCGv_i32 ret, int cond, TCGv_i32 cur, int n,
tcg_temp_free_i32(c);
}
void e2k_win_commit(DisasContext *dc)
void e2k_commit_stubs(DisasContext *ctx)
{
TCGv_i32 cond = tcg_temp_new_i32();
// Change windowing registers after commit is done.
uint32_t ss = dc->bundle.ss;
uint32_t ss = ctx->bundle.ss;
// unsigned int vfdi = (ss & 0x04000000) >> 26;
// unsigned int abg = (ss & 0x01800000) >> 23;
int alc = GET_FIELD(ss, 16, 17);
int abp = GET_FIELD(ss, 18, 19);
int abn = GET_FIELD(ss, 21, 22);
int abg = GET_FIELD(ss, 23, 24);
int alc = GET_FIELD_LEN(ss, 16, 2);
int abp = GET_FIELD_LEN(ss, 18, 2);
int abn = GET_FIELD_LEN(ss, 21, 2);
int abg = GET_FIELD_LEN(ss, 23, 2);
tcg_gen_trunc_tl_i32(cond, e2k_cs.cond);
if (alc) {
TCGv_i64 t0 = tcg_temp_new_i64();
gen_lcnt_dec(t0, e2k_cs.lsr);
gen_movcond_flag_i64(e2k_cs.lsr, alc, e2k_cs.cond, t0, e2k_cs.lsr);
gen_movcond_flag_i64(e2k_cs.lsr, alc, ctx->ct.cond, t0, e2k_cs.lsr);
tcg_temp_free_i64(t0);
}
if (abp) {
gen_cur_dec(e2k_cs.pcur, abp, e2k_cs.pcur, 1, e2k_cs.psize);
gen_cur_dec(ctx, e2k_cs.pcur, abp, e2k_cs.pcur, 1, e2k_cs.psize);
}
if (abn) {
gen_cur_dec(e2k_cs.bcur, abn, e2k_cs.bcur, 2, e2k_cs.bsize);
gen_cur_dec(ctx, e2k_cs.bcur, abn, e2k_cs.bcur, 2, e2k_cs.bsize);
}
switch(abg) {
case 0x00:
break;
case 0x01:
/* TODO */
abort();
// TODO
gen_helper_unimpl(cpu_env);
break;
case 0x02:
/* TODO */
abort();
// TODO
gen_helper_unimpl(cpu_env);
break;
default:
/* FIXME: exception or nop? */
e2k_gen_exception(ctx, E2K_EXCP_ILLOPC);
break;
}
tcg_temp_free_i32(cond);
}
static inline void gen_is_last_iter(TCGv ret)
@ -234,15 +229,8 @@ static void gen_cs0(DisasContext *dc)
}
if (type == IBRANCH || type == DONE || type == HRET || type == GLAUNCH) {
/* IBRANCH, DONE, HRET and GLAUNCH are special because they require SS
to be properly encoded. */
if (!bundle->ss_present || (bundle->ss & 0x00000c00))
{
// TODO: exeption invalid bundle
abort();
/* Don't output either of the aforementioned instructions under "never"
condition. Don't disassemble CS0 being a part of HCALL. Unlike ldis
HCALL is currently disassembled on behalf of CS1. */
if (!bundle->ss_present || (bundle->ss & 0x00000c00)) {
e2k_gen_exception(dc, E2K_EXCP_ILLOPC);
} else if ((bundle->ss & 0x1ff)
&& !(bundle->cs1_present
/* CS1.opc == CALL */
@ -250,24 +238,25 @@ static void gen_cs0(DisasContext *dc)
/* CS1.param.ctopc == HCALL */
&& (bundle->cs1 & 0x380) >> 7 == 2))
{
if (type == IBRANCH) {
if (type == IBRANCH && dc->ct.type == CT_NONE) {
/* C0F2 has `disp' field. In `C0F1' it's called `param'. Is this
the only difference between these two formats? Funnily enough,
DONE is also C0F2 and thus has `disp', though it obviously
makes no sense for it. */
unsigned int disp = (cs0 & 0x0fffffff);
uint32_t disp = (cs0 & 0x0fffffff);
/* Calculate a signed displacement in bytes. */
int sdisp = ((int) (disp << 4)) >> 1;
dc->jmp.dest = dc->pc + sdisp;
dc->base.is_jmp = DISAS_JUMP_STATIC;
int32_t sdisp = ((int32_t) (disp << 4)) >> 1;
dc->ct.type = CT_IBRANCH;
dc->ct.u.target = dc->pc + sdisp;
} else {
e2k_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) {
// invalid
abort();
e2k_gen_exception(dc, E2K_EXCP_ILLOPC);
}
int ipd = GET_FIELD(bundle->ss, 30, 31);
if (type == DISP || type == LDISP) {
@ -283,7 +272,6 @@ static void gen_cs0(DisasContext *dc)
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) |
@ -306,15 +294,11 @@ static void gen_cs0(DisasContext *dc)
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
// TODO: gettsd
gen_helper_unimpl(cpu_env);
}
if (type == SDISP) {
// my_printf (", 0x%x", cs0 & 0x1f);
} else if (type == DISP
|| type == LDISP
|| type == PUTTSD)
{
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
@ -327,12 +311,16 @@ static void gen_cs0(DisasContext *dc)
/* 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
gen_helper_unimpl(cpu_env);
}
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
gen_helper_unimpl(cpu_env);
}
}
}
@ -359,29 +347,21 @@ static void gen_cs1(DisasContext *dc)
unsigned int setbp = (cs1 & 0x08000000) >> 27;
unsigned int setbn = (cs1 & 0x04000000) >> 26;
/* Try to follow the same order of these instructions as in LDIS.
Presumably `vfrpsz' should come first, while `setbp' should be placed
between `setwd' and `setbn', but this is to be verified. I don't have
a binary with these commands by hand right now. */
if (opc == SETR1) {
if (! bundle->lts_present[0]) {
// my_printf ("<bogus vfrpsz>");
e2k_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;
// my_printf ("vfrpsz rpsz = 0x%x", rpsz);
gen_helper_unimpl(cpu_env);
}
}
// FIXME: Should windowing registers be precomputed or not?
if (opc == SETR0 || opc == SETR1) {
if (! bundle->lts_present[0]) {
// TODO: <bogus setwd>
abort();
e2k_gen_exception(dc, E2K_EXCP_ILLOPC);
} else {
uint32_t lts0 = bundle->lts[0];
int wsz = GET_FIELD(lts0, 5, 11);
@ -410,17 +390,22 @@ static void gen_cs1(DisasContext *dc)
tcg_gen_movi_i32(e2k_cs.pcur, 0);
}
} else if (opc == SETEI) {
/* Verify that CS1.param.sft = CS1.param[27] is equal to zero as required
in C.14.3. */
unsigned int sft = (cs1 & 0x08000000) >> 27;
// unsigned int eir = (cs1 & 0x000000ff);
bool sft = GET_BIT(cs1, 27);
if (sft) {
// my_printf ("%s", mcpu >= 2 ? "setsft" : "unimp");
if (dc->version >= 2) {
// TODO: setsft
gen_helper_unimpl(cpu_env);
} else {
e2k_gen_exception(dc, E2K_EXCP_ILLOPC);
}
} else {
// my_printf ("setei 0x%x", eir);
// uint8_t eir = GET_FIELD_LEN(cs1, 0, 8);
// TODO: setei
gen_helper_unimpl(cpu_env);
}
} else if (opc == WAIT) {
// TODO: wait
// unsigned int ma_c = (cs1 & 0x00000020) >> 5;
// unsigned int fl_c = (cs1 & 0x00000010) >> 4;
unsigned int ld_c = (cs1 & 0x00000008) >> 3;
@ -448,67 +433,55 @@ static void gen_cs1(DisasContext *dc)
// my_printf ("trap = %d, ", trap);
}
gen_helper_unimpl(cpu_env);
// 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;
/* 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;
if (ctop) {
tcg_gen_movi_i32(e2k_cs.call_wbs, wbs);
// my_printf ("call %%ctpr%d, wbs = 0x%x", ctop, wbs);
// print_ctcond (info, instr->ss & 0x1ff);
dc->ct.type = CT_CALL;
dc->ct.wbs = GET_FIELD_LEN(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) {
if (cs1_ctopc == 2 && bundle->cs0_present &&
dc->ct.type == CT_NONE)
{
unsigned int cs0 = bundle->cs0;
unsigned int cs0_opc = (cs0 & 0xf0000000) >> 28;
/* CS0.opc == HCALL, which means
CS0.opc.ctpr == CS0.opc.ctp_opc == 0 */
if (cs0_opc == 0) {
// unsigned int hdisp = (cs0 & 0x1e) >> 1;
// my_printf ("hcall 0x%x, wbs = 0x%x", hdisp, wbs);
// print_ctcond (info, instr->ss & 0x1ff);
// TODO: hcall hdisp, wbs ? cond
gen_helper_unimpl(cpu_env);
}
} else {
// my_printf ("<bogus call>");
e2k_gen_exception(dc, E2K_EXCP_ILLOPC);
}
}
} else if (opc == MAS_OPC) {
/* Note that LDIS doesn't print it out as a standalone instruction. */
// TODO: mas
// unsigned int mas = cs1 & 0x0fffffff;
// my_printf ("mas 0x%x", mas);
gen_helper_unimpl(cpu_env);
} else if (opc == FLUSHR) {
/* . . . these stupid engineers off! FLUSHR seems to be responsible for
encoding both `flushr' and `flushc'. Moreover, according to their
logic it should be possible to encode them simultaneously. */
/* Check for `CS1.param.flr'. */
if (cs1 & 0x00000001) {
// my_printf ("flushr");
// TODO: flushr
gen_helper_unimpl(cpu_env);
}
/* Check for `CS1.param.flc'. */
if (cs1 & 0x00000002) {
// my_printf ("flushc");
// TODO: flushc
gen_helper_unimpl(cpu_env);
}
} else if (opc == BG) {
/* Hopefully, `vfbg' is the only instruction encoded by BG. I'm currently
unable to find other ones in `iset-v5.single' at least . . . */
// unsigned int chkm4 = (cs1 & 0x00010000) >> 16;
// unsigned int dmask = (cs1 & 0x0000ff00) >> 8;
// unsigned int umsk = cs1 & 0x000000ff;
/* Print its fields in the order proposed in C.14.10. */
// my_printf ("vfbg umask = 0x%x, dmask = 0x%x, chkm4 = 0x%x",
// umsk, dmask, chkm4);
// TODO: vfbg
gen_helper_unimpl(cpu_env);
} else {
// my_printf ("unimp");
abort();
e2k_gen_exception(dc, E2K_EXCP_ILLOPC);
}
}
@ -518,34 +491,20 @@ 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);
/* TODO: check CPU behavior if present ibranch and ctpr is not zero */
/* TODO: different kinds of ct */
if (ctpr != 0) {
dc->jump_ctpr = ctpr;
dc->base.is_jmp = DISAS_JUMP;
dc->ct.type = CT_JUMP;
dc->ct.u.ctpr = e2k_cs.ctprs[ctpr];
}
if (cond_type == 1) {
tcg_gen_movi_tl(e2k_cs.cond, 1);
} else if (cond_type > 1) {
switch (dc->base.is_jmp) {
case DISAS_JUMP:
dc->base.is_jmp = DISAS_BRANCH;
break;
case DISAS_JUMP_STATIC:
dc->base.is_jmp = DISAS_BRANCH_STATIC;
break;
default:
/* FIXME: what action to do? */
g_assert_not_reached();
break;
}
dc->ct.has_cond = !(cond_type == 1);
if (cond_type > 1) {
/* TODO: single assign */
TCGv preg = tcg_temp_new();
TCGv loop_end = tcg_temp_new();
TCGv not_loop_end = tcg_temp_new();
TCGv cond = dc->ct.cond;
TCGv_i64 t0 = tcg_temp_new_i64();
e2k_gen_preg(t0, psrc);
@ -557,12 +516,12 @@ static void gen_jmp(DisasContext *dc)
case 0x2:
case 0x6:
case 0xf:
tcg_gen_mov_tl(e2k_cs.cond, preg);
tcg_gen_mov_tl(cond, preg);
break;
case 0x3:
case 0x7:
case 0xe:
tcg_gen_setcondi_tl(TCG_COND_NE, e2k_cs.cond, preg, 1);
tcg_gen_setcondi_tl(TCG_COND_NE, cond, preg, 1);
break;
default:
break;
@ -570,18 +529,18 @@ static void gen_jmp(DisasContext *dc)
switch (cond_type) {
case 0x4:
tcg_gen_mov_tl(e2k_cs.cond, loop_end);
tcg_gen_mov_tl(cond, loop_end);
break;
case 0x5:
tcg_gen_mov_tl(e2k_cs.cond, not_loop_end);
tcg_gen_mov_tl(cond, not_loop_end);
break;
case 0x6:
case 0xe:
tcg_gen_or_tl(e2k_cs.cond, e2k_cs.cond, loop_end);
tcg_gen_or_tl(cond, cond, loop_end);
break;
case 0x7:
case 0xf:
tcg_gen_and_tl(e2k_cs.cond, e2k_cs.cond, not_loop_end);
tcg_gen_and_tl(cond, cond, not_loop_end);
break;
default:
break;
@ -646,6 +605,13 @@ static void gen_jmp(DisasContext *dc)
void e2k_control_gen(DisasContext *dc)
{
dc->ct.has_cond = false;
dc->ct.type = CT_NONE;
if (dc->bundle.ss_present) {
gen_jmp(dc);
}
if (dc->bundle.cs0_present) {
gen_cs0(dc);
}
@ -653,8 +619,4 @@ void e2k_control_gen(DisasContext *dc)
if (dc->bundle.cs1_present) {
gen_cs1(dc);
}
if (dc->bundle.ss_present) {
gen_jmp(dc);
}
}