target: e2k: Reorg + basic gdb debugging.
This commit is contained in:
parent
a97138856a
commit
c40cc30f26
@ -29,7 +29,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;
|
||||
|
||||
@ -40,9 +40,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],
|
||||
@ -69,13 +76,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;
|
||||
|
@ -45,6 +45,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;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
@ -152,6 +154,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;
|
||||
}
|
||||
|
||||
@ -159,6 +163,8 @@ static void e2k_cpu_synchronize_from_tb(CPUState *cs, const 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;
|
||||
}
|
||||
|
||||
|
@ -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 CPUArchState {
|
||||
|
||||
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 CPUArchState {
|
||||
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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -1,6 +1,8 @@
|
||||
DEF_HELPER_1(save_cpu_state, void, env)
|
||||
DEF_HELPER_1(unimpl, noreturn, env)
|
||||
DEF_HELPER_2(raise_exception, noreturn, env, int)
|
||||
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)
|
||||
|
@ -7,7 +7,7 @@
|
||||
struct CPUE2KStateTCG e2k_cs;
|
||||
|
||||
/* returns zero if bundle is invalid */
|
||||
static target_ulong unpack_bundle(CPUE2KState *env, DisasContext *ctx)
|
||||
static size_t unpack_bundle(CPUE2KState *env, DisasContext *ctx)
|
||||
{
|
||||
unsigned int gap;
|
||||
unsigned int pos = 0;
|
||||
@ -186,10 +186,21 @@ static target_ulong unpack_bundle(CPUE2KState *env, DisasContext *ctx)
|
||||
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 void gen_goto_tb(DisasContext *ctx, int tb_num, target_ulong pc)
|
||||
@ -206,88 +217,127 @@ static void gen_goto_tb(DisasContext *ctx, int tb_num, target_ulong pc)
|
||||
}
|
||||
}
|
||||
|
||||
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 target_ulong disas_e2k_insn(DisasContext *dc, CPUState *cs)
|
||||
static inline void do_decode(DisasContext *ctx, CPUState *cs)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
unsigned int bundle_len = unpack_bundle(env, dc);
|
||||
unsigned int bundle_len;
|
||||
|
||||
ctx->pc = ctx->base.pc_next;
|
||||
bundle_len = unpack_bundle(env, ctx);
|
||||
if (bundle_len == 0) {
|
||||
bundle_len = 8;
|
||||
gen_exception(dc, 1);
|
||||
return dc->pc + 8;
|
||||
}
|
||||
target_ulong pc_next = dc->pc + bundle_len;
|
||||
ctx->npc = ctx->base.pc_next = ctx->pc + bundle_len;
|
||||
}
|
||||
|
||||
dc->jmp.dest = tcg_const_i64(0);
|
||||
dc->jmp.cond = tcg_const_i64(0);
|
||||
/*
|
||||
* Executes instructions from a bundle and store the results to
|
||||
* temporary buffer.
|
||||
*/
|
||||
static inline void do_execute(DisasContext *ctx)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
e2k_alc_gen(dc);
|
||||
e2k_control_gen(dc);
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (ctx->bundle.als_present[i]) {
|
||||
ctx->alc[i].tag = RESULT_NONE;
|
||||
e2k_execute_alc(ctx, i);
|
||||
}
|
||||
}
|
||||
|
||||
e2k_alc_commit(dc);
|
||||
e2k_win_commit(dc);
|
||||
e2k_control_gen(ctx);
|
||||
}
|
||||
|
||||
/* Control transfer */
|
||||
switch(dc->base.is_jmp) {
|
||||
case DISAS_NEXT:
|
||||
case DISAS_TOO_MANY:
|
||||
dc->base.pc_next = pc_next;
|
||||
/*
|
||||
* 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_NONE:
|
||||
break;
|
||||
case DISAS_NORETURN:
|
||||
/* exception */
|
||||
tcg_gen_movi_tl(e2k_cs.pc, dc->pc);
|
||||
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 STATIC_JUMP:
|
||||
tcg_gen_mov_i64(e2k_cs.pc, dc->jmp.dest);
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
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 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);
|
||||
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:
|
||||
/* 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)
|
||||
@ -296,11 +346,16 @@ static void e2k_tr_init_disas_context(DisasContextBase *db, CPUState *cs)
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
dc->pc = 0;
|
||||
dc->npc = dc->base.pc_first;
|
||||
dc->version = env->version;
|
||||
}
|
||||
|
||||
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);
|
||||
@ -309,102 +364,45 @@ static void e2k_tr_insn_start(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;
|
||||
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->npc);
|
||||
gen_helper_save_cpu_state(cpu_env);
|
||||
gen_goto_tb(ctx, 0, ctx->npc);
|
||||
break;
|
||||
case DISAS_NORETURN:
|
||||
break;
|
||||
case DISAS_JUMP_STATIC:
|
||||
gen_goto_tb(dc, 0, 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,
|
||||
@ -435,6 +433,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");
|
||||
}
|
||||
@ -443,7 +443,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" },
|
||||
@ -461,7 +460,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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user