target: e2k: Add procedure stack.

This commit is contained in:
Denis Drakhnia 2020-11-16 16:26:39 +02:00 committed by Denis Drakhnia
parent 3cba18b9a5
commit ff2d059db8
8 changed files with 331 additions and 222 deletions

View File

@ -57,6 +57,7 @@ void cpu_loop(CPUE2KState *env)
);
if (ret == -TARGET_ERESTARTSYS) {
/* TODO: restart syscall */
abort();
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
unsigned int i;
@ -65,6 +66,7 @@ void cpu_loop(CPUE2KState *env)
regs[(i + offset) % WREGS_SIZE] = 0;
}
}
env->ip = env->nip;
break;
}
default:

View File

@ -73,6 +73,14 @@ static const struct e2k_def_t e2k_defs[] = {
}
};
static inline void cpu_dump_state_wd(CPUE2KState *env, FILE *f, int flags)
{
int wbs = GET_FIELD(env->cr1_lo, CR1_LO_WBS_OFF, CR1_LO_WBS_END);
int wsz = GET_FIELD(env->cr1_lo, CR1_LO_WPSZ_OFF, CR1_LO_WPSZ_END);
qemu_fprintf(f, "wbs = %#x, wsz = %#x\n", wbs, wsz);
}
static inline void cpu_dump_state_br(CPUE2KState *env, FILE *f, int flags)
{
uint32_t br = GET_FIELD(env->cr1_hi, CR1_HI_BR_OFF, CR1_HI_BR_END);
@ -106,7 +114,7 @@ void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
env->cr1_hi, env->cr1_lo);
qemu_fprintf(f, "usd_hi: %016lx, usd_lo: %016lx\n",
env->usd_hi, env->usd_lo);
/* TODO qemu_fprintf(f, "wbs: %d, wsz: %d\n", (int) env->wbs, (int) env->wsz); */
cpu_dump_state_wd(env, f, flags);
cpu_dump_state_br(env, f, flags);
qemu_fprintf(f, "lsr: %016lx\n", env->lsr);

View File

@ -70,7 +70,34 @@ void e2k_tcg_initialize(void);
#define PSP_LO_WRITE_OFF 60
#define PSP_LO_WRITE_BIT (1UL << PSP_LO_WRITE_OFF)
#define PSHTP
#define PSHTP_IND_OFF 0
#define PSHTP_IND_END 11
#define PSHTP_IND_LEN (PSHTP_IND_END - PSHTP_IND_OFF + 1)
#define PSHTP_FXIND_OFF 16
#define PSHTP_FXIND_END 26
#define PSHTP_FXIND_LEN (PSHTP_FXIND_END - PSHTP_FXIND_OFF + 1)
#define PSHTP_TIND_OFF 32
#define PSHTP_TIND_END 42
#define PSHTP_TIND_LEN (PSHTP_TIND_END - PSHTP_TIND_OFF + 1)
#define PSHTP_FX_OFF 48
#define PSHTP_FX_BIT (1UL << PSHTP_FX_OFF)
#define USD_LO_BASE_OFF 0
#define USD_LO_BASE_END 47
#define USD_LO_BASE_LEN (USD_LO_BASE_END - USD_LO_BASE_OFF + 1)
#define USD_LO_PROTECTED_OFF 58
#define USD_LO_PROTECTED_BIT (1UL << USD_LO_PROTECTED_OFF)
#define USD_LO_READ_OFF 59
#define USD_LO_READ_BIT (1UL << USD_LO_READ_OFF)
#define USD_LO_WRITE_OFF 60
#define USD_LO_WRITE_BIT (1UL << USD_LO_WRITE_OFF)
#define USD_HI_CURPTR_OFF 0
#define USD_HI_CURPTR_END 31
#define USD_HI_CURPTR_LEN (USD_HI_CURPTR_END - USD_HI_CURPTR_OFF + 1)
#define USD_HI_SIZE_OFF 32
#define USD_HI_SIZE_END 63
#define USD_HI_SIZE_LEN (USD_HI_SIZE_END - USD_HI_SIZE_OFF + 1)
#define CR1_HI_BR_OFF 0
#define CR1_HI_BR_END 27
@ -180,6 +207,13 @@ 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 */
uint32_t bsize; /* holds rsz * 2 + 2 */
uint32_t bcur; /* holds rcur * 2 */
uint32_t psize; /* holds psz */
uint32_t pcur; /* holds pcur */
uint64_t usd_lo;
uint64_t usd_hi;
@ -191,6 +225,8 @@ 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)
@ -274,6 +310,21 @@ static inline void e2k_state_pcs_size_set(CPUE2KState *env, size_t size)
PCSP_HI_SIZE_LEN);
}
static inline target_ulong e2k_state_ps_base_get(CPUE2KState *env)
{
return GET_FIELD(env->psp_lo, PSP_LO_BASE_OFF, PSP_LO_BASE_END);
}
static inline size_t e2k_state_ps_ind_get(CPUE2KState *env)
{
return GET_FIELD(env->psp_hi, PSP_HI_IND_OFF, PSP_HI_IND_LEN);
}
static inline void e2k_state_ps_ind_set(CPUE2KState *env, size_t ind)
{
env->psp_hi = SET_FIELD(env->psp_hi, ind, PSP_HI_IND_OFF, PSP_HI_IND_LEN);
}
static inline int e2k_state_wbs_get(CPUE2KState *env)
{
return GET_FIELD(env->cr1_lo, CR1_LO_WBS_OFF, CR1_LO_WBS_END);

View File

@ -6,10 +6,52 @@
#include "exec/helper-proto.h"
#include "translate.h"
static inline void save_state(CPUE2KState *env)
{
uint32_t br = 0;
br = SET_FIELD(br, env->boff / 2, BR_RBS_OFF, BR_RBS_LEN);
br = SET_FIELD(br, (env->bsize - 2) / 2, BR_RSZ_OFF, BR_RSZ_LEN);
br = SET_FIELD(br, env->bcur / 2, BR_RCUR_OFF, BR_RCUR_LEN);
br = SET_FIELD(br, env->psize, BR_PSZ_OFF, BR_PSZ_LEN);
br = SET_FIELD(br, env->pcur, BR_PCUR_OFF, BR_PCUR_LEN);
env->cr1_hi = SET_FIELD(env->cr1_hi, br, CR1_HI_BR_OFF + BR_BN_OFF,
BR_BN_LEN);
env->cr1_lo = SET_FIELD(env->cr1_lo, env->wsize / 2,
CR1_LO_WPSZ_OFF, CR1_LO_WPSZ_LEN);
}
static inline void restore_state(CPUE2KState *env)
{
uint32_t br;
int rbs, rsz, rcur, psz, pcur, wsz, wbs;
br = GET_FIELD(env->cr1_hi, CR1_HI_BR_OFF, CR1_HI_BR_LEN);
rbs = GET_FIELD(br, BR_RBS_OFF, BR_RBS_END);
rsz = GET_FIELD(br, BR_RSZ_OFF, BR_RSZ_END);
rcur = GET_FIELD(br, BR_RCUR_OFF, BR_RCUR_END);
psz = GET_FIELD(br, BR_PSZ_OFF, BR_PSZ_END);
pcur = GET_FIELD(br, BR_PCUR_OFF, BR_PCUR_END);
wbs = GET_FIELD(env->cr1_lo, CR1_LO_WBS_OFF, CR1_LO_WBS_END);
wsz = GET_FIELD(env->cr1_lo, CR1_LO_WPSZ_OFF, CR1_LO_WPSZ_END);
env->boff = rbs * 2;
env->bsize = rsz * 2 + 2;
env->bcur = rcur * 2;
env->psize = psz;
env->pcur = pcur;
env->woff = wbs * 2;
env->wsize = wsz * 2;
}
void helper_raise_exception(CPUE2KState *env, int tt)
{
CPUState *cs = env_cpu(env);
save_state(env);
cs->exception_index = tt;
cpu_loop_exit(cs);
}
@ -33,10 +75,11 @@ static void pcs_push(CPUE2KState *env)
e2k_state_pcs_index_set(env, offset + 32);
}
static void pcs_pop(CPUE2KState *env)
static uint64_t pcs_pop(CPUE2KState *env)
{
size_t offset = e2k_state_pcs_index_get(env);
uint64_t *pcsp = (uint64_t *) (e2k_state_pcs_base_get(env) + offset - 32);
uint64_t tgt;
if (offset < 32) {
/* TODO: SIGKILL */
@ -44,11 +87,47 @@ static void pcs_pop(CPUE2KState *env)
}
memcpy(&env->pf, pcsp, 8);
memcpy(&env->ip, pcsp + 1, 8);
memcpy(&tgt, pcsp + 1, 8);
memcpy(&env->cr1_lo, pcsp + 2, 8);
memcpy(&env->cr1_hi, pcsp + 3, 8);
e2k_state_pcs_index_set(env, offset - 32);
return tgt;
}
static void ps_push(CPUE2KState *env, unsigned int wbs, size_t len)
{
unsigned int i;
size_t index = e2k_state_ps_ind_get(env);
uint64_t *p = (uint64_t*) (e2k_state_ps_base_get(env) + index);
/* TODO: push FX registers */
/* TODO: stack overflow */
for (i = 0; i < len; i++) {
uint64_t reg = env->wregs[(wbs + i) % WREGS_SIZE];
memcpy(p + i, &reg, sizeof(uint64_t));
}
e2k_state_ps_ind_set(env, index + len * sizeof(uint64_t));
}
static void ps_pop(CPUE2KState *env, unsigned int wbs, size_t len)
{
unsigned int i;
size_t index = e2k_state_ps_ind_get(env) - len * sizeof(uint64_t);
uint64_t *p = (uint64_t*) (e2k_state_ps_base_get(env) + index);
/* TODO: pop FX registers */
/* TODO: stack overflow */
for (i = 0; i < len; i++) {
uint64_t *reg = &env->wregs[(wbs + i) % WREGS_SIZE];
memcpy(reg, p + i, sizeof(uint64_t));
}
e2k_state_ps_ind_set(env, index);
}
static inline void do_call(CPUE2KState *env, target_ulong ctpr)
@ -57,7 +136,7 @@ static inline void do_call(CPUE2KState *env, target_ulong ctpr)
wbs = e2k_state_wbs_get(env);
wsz = e2k_state_wsz_get(env);
new_wbs = (wbs + env->call_wbs) % WREGS_SIZE;
new_wbs = (wbs + env->call_wbs) % (WREGS_SIZE / 2);
new_wsz = wsz - env->call_wbs;
if (new_wsz < 0) {
@ -67,104 +146,101 @@ 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);
e2k_state_wbs_set(env, new_wbs);
e2k_state_wsz_set(env, new_wsz);
env->ip = GET_FIELD(ctpr, CTPR_BASE_OFF, CTPR_BASE_END);
/* restore woff, wsize, etc */
restore_state(env);
}
static void do_return(CPUE2KState *env)
static uint64_t do_return(CPUE2KState *env)
{
// uint64_t *psp = (uint64_t *) GET_FIELD(env->psp_lo, PSP_LO_BASE_OFF,
// PSP_LO_BASE_END);
int new_wbs, old_wbs;
uint64_t tgt;
old_wbs = e2k_state_wbs_get(env) * 2;
/* restore procedure chain info */
pcs_pop(env);
tgt = pcs_pop(env);
// TODO: restore regs
new_wbs = e2k_state_wbs_get(env) * 2;
if (old_wbs < new_wbs) {
old_wbs += WREGS_SIZE;
}
ps_pop(env, new_wbs, old_wbs - new_wbs);
/* restore woff, wsize, etc */
restore_state(env);
return tgt;
}
void helper_call(CPUE2KState *env, target_ulong cond, target_ulong ctpr)
static inline void reset_ctprs(CPUE2KState *env)
{
unsigned int i = 0;
if (!cond) {
env->ip = env->nip;
return;
}
unsigned int i;
for (i = 0; i < 4; i++) {
env->ctprs[i] = 0;
}
}
switch (GET_FIELD(ctpr, CTPR_TAG_OFF, CTPR_TAG_END)) {
target_ulong helper_jump(CPUE2KState *env, int i)
{
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);
switch (ctpr_tag) {
case CTPR_TAG_RETURN:
if (cond) {
tgt = do_return(env);
reset_ctprs(env);
}
break;
case CTPR_TAG_DISP: {
/* TODO: ldisp */
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: {
CPUState *cs = env_cpu(env);
env->ip = env->nip;
cs->exception_index = E2K_EXCP_SYSCALL;
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;
}
case CTPR_TAG_DISP: {
do_call(env, ctpr);
break;
}
default:
/* TODO: exception */
abort();
break;
}
}
/* FIXME: combine with helper_call? */
void helper_jump(CPUE2KState *env, target_ulong cond, target_ulong ctpr)
{
if (!cond) {
env->ip = env->nip;
return;
}
switch (GET_FIELD(ctpr, CTPR_TAG_OFF, CTPR_TAG_END)) {
case CTPR_TAG_DISP: {
env->ip = GET_FIELD(ctpr, CTPR_BASE_OFF, CTPR_BASE_END);
break;
}
case CTPR_TAG_RETURN:
do_return(env);
break;
default:
/* TODO: exception */
abort();
break;
}
}
void helper_setwd(CPUE2KState *env, uint32_t lts0)
{
int wsz = GET_FIELD(lts0, 5, 11);
/* TODO: store nfx */
// int nfx = GET_BIT(lts0, 4);
/* TODO: push wregs */
e2k_state_wsz_set(env, wsz);
if (env->version >= 3) {
// int dbl = GET_BIT(lts0, 3);
/* TODO: store dbl */
}
}
void helper_setbn(CPUE2KState *env, uint32_t cs1)
{
env->cr1_hi = SET_FIELD(
env->cr1_hi,
GET_FIELD(cs1, 0, 17),
CR1_HI_BR_OFF + BR_BN_OFF,
BR_BN_LEN
);
return tgt;
}
uint64_t helper_sxt(uint64_t x, uint64_t y)
@ -240,34 +316,14 @@ void helper_state_reg_set(CPUE2KState *env, int reg, uint64_t val)
}
}
void helper_save_rcur(CPUE2KState *env, int rcur)
{
env->cr1_hi = SET_FIELD(
env->cr1_hi,
rcur / 2,
CR1_HI_BR_OFF + BR_RCUR_OFF,
BR_RCUR_LEN
);
}
void helper_save_pcur(CPUE2KState *env, int pcur)
{
env->cr1_hi = SET_FIELD(
env->cr1_hi,
pcur,
CR1_HI_BR_OFF + BR_PCUR_OFF,
BR_PCUR_LEN
);
}
uint64_t helper_getsp(CPUE2KState *env, uint64_t src2) {
uint64_t base = GET_FIELD(env->psp_lo, PSP_LO_BASE_OFF, PSP_LO_BASE_END);
uint64_t base = GET_FIELD(env->usd_lo, USD_LO_BASE_OFF, USD_LO_BASE_END);
base += src2;
/* TODO: stack overflow */
env->psp_lo = SET_FIELD(env->psp_lo, base, PSP_LO_BASE_OFF,
PSP_LO_BASE_LEN);
env->usd_lo = SET_FIELD(env->usd_lo, base, USD_LO_BASE_OFF,
USD_LO_BASE_LEN);
return base;
}

View File

@ -1,13 +1,9 @@
DEF_HELPER_2(raise_exception, noreturn, env, int)
DEF_HELPER_3(call, void, env, tl, tl)
DEF_HELPER_3(jump, void, env, tl, tl)
DEF_HELPER_2(jump, tl, env, int)
DEF_HELPER_3(branch, tl, env, int, tl)
DEF_HELPER_2(sxt, i64, i64, i64)
DEF_HELPER_1(debug_i32, void, i32)
DEF_HELPER_1(debug_i64, void, i64)
DEF_HELPER_2(setwd, void, env, i32)
DEF_HELPER_2(setbn, void, env, i32)
DEF_HELPER_2(state_reg_get, i64, env, int)
DEF_HELPER_3(state_reg_set, void, env, int, i64)
DEF_HELPER_2(save_rcur, void, env, int)
DEF_HELPER_2(save_pcur, void, env, int)
DEF_HELPER_2(getsp, i64, env, i64) /* FIXME: return tl? */

View File

@ -190,8 +190,6 @@ static inline void save_state(DisasContext *dc)
{
tcg_gen_movi_tl(e2k_cs.pc, dc->pc);
tcg_gen_movi_tl(e2k_cs.npc, dc->npc);
gen_helper_save_rcur(cpu_env, e2k_cs.bcur);
gen_helper_save_pcur(cpu_env, e2k_cs.pcur);
}
void e2k_gen_exception(DisasContext *dc, int which)
@ -282,7 +280,8 @@ static void e2k_tr_init_disas_context(DisasContextBase *db, CPUState *cs)
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
dc->pc = dc->base.pc_first;
dc->pc = 0;
dc->npc = dc->base.pc_first;
dc->version = env->version;
}
@ -306,11 +305,12 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs)
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
UnpackedBundle *bundle = &dc->bundle;
unsigned int bundle_len;
dc->pc = dc->base.pc_next;
unsigned int bundle_len = unpack_bundle(env, dc->pc, bundle);
dc->pc = dc->npc;
bundle_len = unpack_bundle(env, dc->pc, bundle);
/* TODO: exception, check bundle_len */
dc->base.pc_next = dc->npc = dc->pc + bundle_len;
dc->npc = dc->base.pc_next = dc->pc + bundle_len;
e2k_alc_gen(dc);
e2k_control_gen(dc);
@ -334,31 +334,8 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs)
static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
{
DisasContext *dc = container_of(db, DisasContext, base);
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
uint32_t br;
int wbs, wsz, rbs, rsz, rcur, psz, pcur;
wbs = e2k_state_wbs_get(env);
wsz = e2k_state_wsz_get(env);
br = GET_FIELD(env->cr1_hi, CR1_HI_BR_OFF, CR1_HI_BR_END);
rbs = GET_FIELD(br, BR_RBS_OFF, BR_RBS_END);
rsz = GET_FIELD(br, BR_RSZ_OFF, BR_RSZ_END);
rcur = GET_FIELD(br, BR_RCUR_OFF, BR_RCUR_END);
psz = GET_FIELD(br, BR_PSZ_OFF, BR_PSZ_END);
pcur = GET_FIELD(br, BR_PCUR_OFF, BR_PCUR_END);
e2k_cs.woff = tcg_const_i32(wbs * 2);
e2k_cs.wsize = tcg_const_i32(wsz * 2);
e2k_cs.boff = tcg_const_i32(rbs * 2);
e2k_cs.bsize = tcg_const_i32((rsz + 1) * 2);
e2k_cs.bcur = tcg_const_i32(rcur * 2);
e2k_cs.psize = tcg_const_i32(psz);
e2k_cs.pcur = tcg_const_i32(pcur);
dc->is_call = false;
dc->jmp.cond = tcg_const_i64(0);
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)
@ -371,42 +348,58 @@ static void e2k_tr_tb_stop(DisasContextBase *db, CPUState *cs)
case DISAS_TOO_MANY:
break;
case DISAS_NORETURN: {
save_state(dc);
/* exception */
tcg_gen_exit_tb(NULL, 0);
break;
}
case DISAS_STATIC_JUMP:
save_state(dc);
case DISAS_JUMP_STATIC:
tcg_gen_movi_tl(e2k_cs.pc, dc->jmp.dest);
tcg_gen_exit_tb(NULL, 0);
break;
case DISAS_DYNAMIC_JUMP: {
save_state(dc);
gen_helper_jump(cpu_env, dc->jmp.cond, e2k_cs.ctprs[dc->jump_ctpr]);
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_CALL: {
case DISAS_JUMP: {
TCGv_i32 ctpr = tcg_const_i32(dc->jump_ctpr);
save_state(dc);
gen_helper_call(cpu_env, dc->jmp.cond, e2k_cs.ctprs[dc->jump_ctpr]);
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_state(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_i32(e2k_cs.woff);
tcg_temp_free_i32(e2k_cs.wsize);
tcg_temp_free_i32(e2k_cs.boff);
tcg_temp_free_i32(e2k_cs.bsize);
tcg_temp_free_i32(e2k_cs.bcur);
tcg_temp_free_i32(e2k_cs.psize);
tcg_temp_free_i32(e2k_cs.pcur);
tcg_temp_free(dc->jmp.cond);
}
static void e2k_tr_disas_log(const DisasContextBase *db,
@ -447,6 +440,13 @@ void e2k_tcg_initialize(void) {
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" },
{ &e2k_cs.bsize, offsetof(CPUE2KState, bsize), "bsize" },
{ &e2k_cs.bcur, offsetof(CPUE2KState, bcur), "bcur" },
{ &e2k_cs.psize, offsetof(CPUE2KState, psize), "psize" },
{ &e2k_cs.pcur, offsetof(CPUE2KState, pcur), "pcur" },
};
static const struct { TCGv_i64 *ptr; int off; const char *name; } r64[] = {
@ -457,6 +457,7 @@ 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

@ -4,9 +4,20 @@
#include "tcg/tcg-op.h"
#include "exec/translator.h"
#define DISAS_STATIC_JUMP DISAS_TARGET_0
#define DISAS_DYNAMIC_JUMP DISAS_TARGET_1
#define DISAS_CALL DISAS_TARGET_2
/* ibranch disp */
#define DISAS_JUMP_STATIC DISAS_TARGET_0
/* ibranch disp ? cond */
#define DISAS_BRANCH_STATIC DISAS_TARGET_1
/*
* ct %ctprN
* call %ctprN, wbs=M
* */
#define DISAS_JUMP DISAS_TARGET_2
/*
* ct %ctprN ? cond
* call %ctprN, wbs=M ? cond
*/
#define DISAS_BRANCH DISAS_TARGET_3
#define IS_BASED(i) (((i) & 0x80) == 0)
#define IS_REGULAR(i) (((i) & 0xc0) == 0x80)
@ -47,6 +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];
@ -110,7 +122,6 @@ typedef struct DisasContext {
UnpackedBundle bundle;
target_ulong pc;
target_ulong npc;
bool is_call;
int jump_ctpr;
int mmuidx;
@ -130,7 +141,6 @@ typedef struct DisasContext {
/* TODO: move to CPUE2KState */
struct {
target_ulong dest; /* ibranch dst */
TCGv_i64 cond;
} jmp;
} DisasContext;

View File

@ -36,26 +36,20 @@ static inline void gen_lcnt_dec(TCGv_i64 ret, TCGv_i64 lsr)
tcg_temp_free_i32(zero);
}
static inline void gen_pcur_inc(TCGv_i32 ret)
static inline void gen_dec_cur(TCGv_i32 ret, TCGv_i32 cur, int val,
TCGv_i32 size)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
tcg_gen_subi_i32(t0, e2k_cs.pcur, 1);
/* FIXME: terminated by signal SIGFPE (Floating point exception */
// tcg_gen_remu_i32(ret, t0, e2k_cs.psize);
/* FIXME: temp hack */
e2k_gen_wrap_i32(ret, t0, e2k_cs.psize);
tcg_temp_free_i32(t0);
}
static inline void gen_rcur_inc(TCGv_i32 ret)
{
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_subi_i32(t0, e2k_cs.bcur, 2);
tcg_gen_remu_i32(ret, t0, e2k_cs.bsize);
tcg_gen_addi_i32(t0, size, val);
tcg_gen_sub_i32(t1, t0, cur);
tcg_gen_remu_i32(t2, t1, size);
tcg_gen_sub_i32(ret, size, t2);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
@ -130,13 +124,13 @@ void e2k_win_commit(DisasContext *dc)
int abn = GET_FIELD(ss, 21, 22);
int abg = GET_FIELD(ss, 23, 24);
tcg_gen_trunc_tl_i32(cond, dc->jmp.cond);
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, dc->jmp.cond, t0, e2k_cs.lsr);
gen_movcond_flag_i64(e2k_cs.lsr, alc, e2k_cs.cond, t0, e2k_cs.lsr);
tcg_temp_free_i64(t0);
}
@ -144,7 +138,7 @@ void e2k_win_commit(DisasContext *dc)
if (abp) {
TCGv_i32 t0 = tcg_temp_new_i32();
gen_pcur_inc(t0);
gen_dec_cur(t0, e2k_cs.pcur, 1, e2k_cs.psize);
gen_movcond_flag_i32(e2k_cs.pcur, abp, cond, t0, e2k_cs.pcur);
tcg_temp_free_i32(t0);
@ -153,7 +147,7 @@ void e2k_win_commit(DisasContext *dc)
if (abn) {
TCGv_i32 t0 = tcg_temp_new_i32();
gen_rcur_inc(t0);
gen_dec_cur(t0, e2k_cs.bcur, 2, e2k_cs.bsize);
gen_movcond_flag_i32(e2k_cs.bcur, abn, cond, t0, e2k_cs.bcur);
tcg_temp_free_i32(t0);
@ -277,7 +271,7 @@ static void gen_cs0(DisasContext *dc)
/* Calculate a signed displacement in bytes. */
int sdisp = ((int) (disp << 4)) >> 1;
dc->jmp.dest = dc->pc + sdisp;
dc->base.is_jmp = DISAS_STATIC_JUMP;
dc->base.is_jmp = DISAS_JUMP_STATIC;
}
}
} else {
@ -405,8 +399,6 @@ static void gen_cs1(DisasContext *dc)
int wsz = GET_FIELD(lts0, 5, 11);
TCGv_i32 t0 = tcg_const_i32(lts0);
gen_helper_setwd(cpu_env, t0);
tcg_gen_movi_i32(e2k_cs.wsize, wsz * 2);
tcg_temp_free_i32(t0);
@ -417,18 +409,10 @@ static void gen_cs1(DisasContext *dc)
int rbs = GET_FIELD(cs1, BR_RBS_OFF, BR_RBS_END);
int rsz = GET_FIELD(cs1, BR_RSZ_OFF, BR_RSZ_END);
int rcur = GET_FIELD(cs1, BR_RCUR_OFF, BR_RCUR_END);
TCGv_ptr t0 = tcg_const_ptr(rbs * 2);
TCGv_i32 t1 = tcg_const_i32(cs1);
/* update state*/
gen_helper_setbn(cpu_env, t1);
tcg_gen_movi_i32(e2k_cs.boff, rbs * 2);
tcg_gen_movi_i32(e2k_cs.bsize, (rsz + 1) * 2);
tcg_gen_movi_i32(e2k_cs.bcur, rcur * 2);
tcg_temp_free_i32(t1);
tcg_temp_free_ptr(t0);
}
if (setbp) {
@ -485,7 +469,6 @@ static void gen_cs1(DisasContext *dc)
unsigned int wbs = cs1 & 0x7f;
if (ctop) {
dc->is_call = true;
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);
@ -547,19 +530,36 @@ 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;
}
if (cond_type == 1) {
/* TODO: optimize ibranch with no cond */
tcg_gen_movi_tl(dc->jmp.cond, 1);
} else 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;
}
/* TODO: single assign */
TCGv cond = tcg_const_tl(0);
TCGv preg = tcg_temp_new();
TCGv loop_end = tcg_temp_new();
TCGv not_loop_end = tcg_temp_new();
TCGv_i64 t0 = tcg_temp_new_i64();
dc->base.is_jmp = DISAS_DYNAMIC_JUMP;
e2k_gen_preg(t0, psrc);
tcg_gen_trunc_i64_tl(preg, t0);
gen_is_loop_end(loop_end);
@ -569,12 +569,12 @@ static void gen_jmp(DisasContext *dc)
case 0x2:
case 0x6:
case 0xf:
tcg_gen_mov_tl(cond, preg);
tcg_gen_mov_tl(e2k_cs.cond, preg);
break;
case 0x3:
case 0x7:
case 0xe:
tcg_gen_setcondi_tl(TCG_COND_NE, cond, preg, 1);
tcg_gen_setcondi_tl(TCG_COND_NE, e2k_cs.cond, preg, 1);
break;
default:
break;
@ -582,18 +582,18 @@ static void gen_jmp(DisasContext *dc)
switch (cond_type) {
case 0x4:
tcg_gen_mov_tl(cond, loop_end);
tcg_gen_mov_tl(e2k_cs.cond, loop_end);
break;
case 0x5:
tcg_gen_mov_tl(cond, not_loop_end);
tcg_gen_mov_tl(e2k_cs.cond, not_loop_end);
break;
case 0x6:
case 0xe:
tcg_gen_or_tl(cond, cond, loop_end);
tcg_gen_or_tl(e2k_cs.cond, e2k_cs.cond, loop_end);
break;
case 0x7:
case 0xf:
tcg_gen_and_tl(cond, cond, not_loop_end);
tcg_gen_and_tl(e2k_cs.cond, e2k_cs.cond, not_loop_end);
break;
default:
break;
@ -648,26 +648,11 @@ static void gen_jmp(DisasContext *dc)
abort();
}
tcg_gen_mov_tl(dc->jmp.cond, cond);
tcg_temp_free_i64(t0);
tcg_temp_free(not_loop_end);
tcg_temp_free(loop_end);
tcg_temp_free(preg);
tcg_temp_free(cond);
}
/* TODO: check CPU behavior if present ibranch and ctpr is not zero */
/* TODO: different kinds of ct */
if (ctpr != 0) {
dc->jump_ctpr = ctpr;
if (dc->is_call) {
dc->base.is_jmp = DISAS_CALL;
} else {
dc->base.is_jmp = DISAS_DYNAMIC_JUMP;
}
}
}