target: e2k: Fix call/return.

This commit is contained in:
Denis Drakhnia 2020-11-22 11:44:28 +02:00 committed by Denis Drakhnia
parent 3b5241ad15
commit dc5905c3ab
5 changed files with 37 additions and 48 deletions

View File

@ -45,8 +45,9 @@ 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;
env->wd_base = 0;
env->wd_size = 8;
env->wd_psize = 8;
}
#ifdef CONFIG_SOFTMMU

View File

@ -228,8 +228,9 @@ typedef struct CPUArchState {
uint64_t lsr; /* loop status register */
uint32_t woff; /* holds wbs * 2 */
uint32_t wsize; /* holds wsz * 2 */
uint32_t wd_base;
uint32_t wd_size;
uint32_t wd_psize;
uint32_t boff; /* holds rbs * 2 */
uint32_t bsize; /* holds rsz * 2 + 2 */
uint32_t bcur; /* holds rcur * 2 */
@ -359,12 +360,12 @@ static inline void e2k_state_wbs_set(CPUE2KState *env, int wbs)
CR1_LO_WBS_OFF, CR1_LO_WBS_LEN);
}
static inline int e2k_state_wsz_get(CPUE2KState *env)
static inline int e2k_state_wpsz_get(CPUE2KState *env)
{
return GET_FIELD(env->cr1_lo, CR1_LO_WPSZ_OFF, CR1_LO_WPSZ_END);
}
static inline void e2k_state_wsz_set(CPUE2KState *env, int wsz)
static inline void e2k_state_wpsz_set(CPUE2KState *env, int wsz)
{
env->cr1_lo = SET_FIELD(env->cr1_lo, wsz,
CR1_LO_WPSZ_OFF, CR1_LO_WPSZ_LEN);

View File

@ -11,7 +11,8 @@ static inline void reset_ctprs(CPUE2KState *env)
unsigned int i;
for (i = 0; i < 3; i++) {
env->ctprs[i] = 0;
env->ctprs[i] = SET_FIELD(env->ctprs[i], CTPR_TAG_NONE,
CTPR_TAG_OFF, CTPR_TAG_LEN);
}
}
@ -28,15 +29,16 @@ void helper_save_cpu_state(CPUE2KState *env)
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,
env->cr1_lo = SET_FIELD(env->cr1_lo, env->wd_psize / 2,
CR1_LO_WPSZ_OFF, CR1_LO_WPSZ_LEN);
}
static inline void restore_state(CPUE2KState *env)
static inline void restore_br_state(CPUE2KState *env)
{
uint32_t br;
int rbs, rsz, rcur, psz, pcur, wsz, wbs;
int rbs, rsz, rcur, psz, pcur;
// FIXME: cr1_hi.br does not modified after return, find a way to restore it
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);
@ -44,17 +46,11 @@ static inline void restore_state(CPUE2KState *env)
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_unimpl(CPUE2KState *env)
@ -157,51 +153,41 @@ static void ps_pop(CPUE2KState *env, unsigned int wbs, size_t len)
static inline void do_call(CPUE2KState *env, int call_wbs)
{
int wbs, wsz, new_wbs, new_wsz;
int call_wpsz = env->wd_size / 2 - call_wbs;
wbs = e2k_state_wbs_get(env);
wsz = e2k_state_wsz_get(env);
new_wbs = (wbs + call_wbs) % (WREGS_SIZE / 2);
new_wsz = wsz - call_wbs;
if (new_wsz < 0) {
/* TODO: SIGSEGV */
abort();
}
/* save procedure chain info */
helper_save_cpu_state(env);
pcs_push(env);
/* save regs */
ps_push(env, wbs * 2, call_wbs * 2);
ps_push(env, env->wd_base, call_wbs * 2);
e2k_state_wbs_set(env, new_wbs);
e2k_state_wsz_set(env, new_wsz);
e2k_state_wbs_set(env, call_wbs);
env->wd_base = (env->wd_base + call_wbs * 2) % WREGS_SIZE;
env->wd_size = env->wd_psize = call_wpsz * 2;
/* restore woff, wsize, etc */
restore_state(env);
reset_ctprs(env);
}
target_ulong helper_return(CPUE2KState *env)
{
int new_wbs, old_wbs;
int new_wd_size, new_wd_base, wbs;
target_ulong tgt;
old_wbs = e2k_state_wbs_get(env) * 2;
wbs = GET_FIELD(env->cr1_lo, CR1_LO_WBS_OFF, CR1_LO_WBS_END);
new_wd_size = env->wd_psize + wbs * 2;
new_wd_base = (env->wd_base - wbs * 2) % WREGS_SIZE;
/* restore procedure chain info */
tgt = pcs_pop(env);
new_wbs = e2k_state_wbs_get(env) * 2;
if (old_wbs < new_wbs) {
old_wbs += WREGS_SIZE;
if (env->wd_base < new_wd_base) {
env->wd_base += WREGS_SIZE;
}
ps_pop(env, new_wbs, old_wbs - new_wbs);
tgt = pcs_pop(env);
/* restore woff, wsize, etc */
restore_state(env);
ps_pop(env, new_wd_base, env->wd_base - new_wd_base);
env->wd_base = new_wd_base;
env->wd_size = new_wd_size;
env->wd_psize = GET_FIELD(env->cr1_lo, CR1_LO_WPSZ_OFF, CR1_LO_WPSZ_END) * 2;
restore_br_state(env);
reset_ctprs(env);
return tgt;

View File

@ -478,8 +478,8 @@ void e2k_tcg_initialize(void) {
char buf[16] = { 0 };
static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
{ &e2k_cs.woff, offsetof(CPUE2KState, woff), "woff" },
{ &e2k_cs.wsize, offsetof(CPUE2KState, wsize), "wsize" },
{ &e2k_cs.woff, offsetof(CPUE2KState, wd_base), "woff" },
{ &e2k_cs.wsize, offsetof(CPUE2KState, wd_size), "wsize" },
{ &e2k_cs.boff, offsetof(CPUE2KState, boff), "boff" },
{ &e2k_cs.bsize, offsetof(CPUE2KState, bsize), "bsize" },
{ &e2k_cs.bcur, offsetof(CPUE2KState, bcur), "bcur" },

View File

@ -38,6 +38,7 @@
#define GET_GLOBAL(i) ((i) & 0x1f)
typedef enum {
CTPR_TAG_NONE = 0x0,
CTPR_TAG_RETURN = 0x2,
CTPR_TAG_DISP = 0x3,
CTPR_TAG_LDISP = 0x3,