diff --git a/linux-user/elfload.c b/linux-user/elfload.c index fce745c49b..6deaeb3086 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1649,13 +1649,13 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i regs->pcsp.is_writable = true; regs->pcsp.index = 0; regs->pcsp.size = TARGET_PAGE_SIZE; - regs->pcsp.base = (void *) e2k_mmap(regs->pcsp.size); + regs->pcsp.base = e2k_mmap(regs->pcsp.size); regs->psp.is_readable = true; regs->psp.is_writable = true; regs->psp.index = 0; regs->psp.size = TARGET_PAGE_SIZE * 8; - regs->psp.base = (void *) e2k_mmap(regs->psp.size); + regs->psp.base = e2k_mmap(regs->psp.size); } static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUE2KState *env) diff --git a/target/e2k/cpu.h b/target/e2k/cpu.h index afdcfd8906..c46fb35f3c 100644 --- a/target/e2k/cpu.h +++ b/target/e2k/cpu.h @@ -287,12 +287,12 @@ typedef struct { } E2KCr1State; typedef struct { - void *base; + target_ulong base; uint32_t index; uint32_t size; bool is_readable; bool is_writable; -} E2KDescState, E2KPsState, E2KPcsState; +} E2KStackState, E2KPsState, E2KPcsState; typedef struct { int16_t index; @@ -302,7 +302,7 @@ typedef struct { } E2KPshtpState; typedef struct { - uint32_t base; + int32_t base; uint32_t size; uint32_t psize; bool fx; @@ -455,6 +455,7 @@ typedef struct { typedef struct CPUArchState { /* register file */ uint64_t regs[E2K_REG_COUNT]; /* registers */ + uint16_t xregs[E2K_REG_COUNT]; /* x part of registers */ uint64_t tags[E2K_TAGS_REG_COUNT]; /* registers tags */ uint64_t *rptr; /* pointer to regs */ uint64_t *tptr; /* pointer to tags */ @@ -556,7 +557,7 @@ void e2k_break_save_state(CPUE2KState *env); #define cpu_signal_handler e2k_cpu_signal_handler #define cpu_list e2k_cpu_list -static inline uint64_t e2k_state_desc_lo(E2KDescState *desc) +static inline uint64_t e2k_state_desc_lo(E2KStackState *desc) { uint64_t lo = 0; @@ -568,7 +569,7 @@ static inline uint64_t e2k_state_desc_lo(E2KDescState *desc) return lo; } -static inline uint64_t e2k_state_desc_hi(E2KDescState *env) +static inline uint64_t e2k_state_desc_hi(E2KStackState *env) { uint64_t hi = 0; @@ -690,6 +691,14 @@ static inline void e2k_state_cr1_hi_set(CPUE2KState *env, uint64_t hi) cr1->ussz = extract64(hi, CR1_HI_USSZ_OFF, CR1_HI_USSZ_LEN); } +static inline void e2k_state_reg_tag_set_i64(CPUE2KState *env, int tag, int idx) +{ + int i = idx / E2K_TAGS_PER_REG, offset; + + offset = (idx & (E2K_TAGS_PER_REG - 1)) * E2K_REG_TAGS_SIZE; + env->tags[i] = deposit64(env->tags[i], offset, E2K_REG_TAGS_SIZE, tag); +} + #include "exec/cpu-all.h" #endif diff --git a/target/e2k/helper.c b/target/e2k/helper.c index deef8a9fda..5c3b914c61 100644 --- a/target/e2k/helper.c +++ b/target/e2k/helper.c @@ -15,197 +15,146 @@ static inline void reset_ctprs(CPUE2KState *env) } } -static inline void save_proc_chain_info(CPUE2KState *env, uint64_t buf[4], - int wbs) +static inline void stack_push(CPUE2KState *env, E2KStackState *s, uint64_t value) { - env->cr1.br = e2k_state_br(env); - env->cr1.wpsz = env->wd.psize / 2; + if ((s->index + 8) > s->size) { + helper_raise_exception(env, E2K_EXCP_MAPERR); + return; + } - buf[0] = env->cr0_lo; - buf[1] = env->cr0_hi; - buf[2] = e2k_state_cr1_lo(env); - buf[3] = e2k_state_cr1_hi(env); - - env->cr1.wfx = env->wd.fx; - env->cr1.wbs = wbs; - env->wd.base = (env->wd.base + wbs * 2) % E2K_NR_COUNT; - env->wd.psize = env->wd.size -= wbs * 2; + cpu_stq_le_data_ra(env, s->base + s->index, value, GETPC()); + s->index += 8; } -static inline void restore_proc_chain_info(CPUE2KState *env, uint64_t buf[4]) +static inline uint64_t stack_pop(CPUE2KState *env, E2KStackState *s) { + if (s->index < 8) { + helper_raise_exception(env, E2K_EXCP_MAPERR); + return 0; + } + + s->index -= 8; + return cpu_ldq_le_data(env, s->base + s->index); +} + +#define pcs_push(env, value) stack_push(env, &env->pcsp, (value)) +#define pcs_pop(env) stack_pop(env, &env->pcsp) +#define ps_push(env, value) stack_push(env, &env->psp, (value)) +#define ps_pop(env) stack_pop(env, &env->psp) + +static void proc_chain_save(CPUE2KState *env, int wbs) +{ + env->pshtp.index += wbs * 2; + + env->cr1.wbs = wbs; + env->cr1.wpsz = env->wd.psize / 2; + env->cr1.wfx = env->wd.fx; + env->cr1.br = e2k_state_br(env); + + pcs_push(env, env->cr0_lo); + pcs_push(env, env->cr0_hi); + pcs_push(env, e2k_state_cr1_lo(env)); + pcs_push(env, e2k_state_cr1_hi(env)); + + env->wd.fx = true; + env->wd.base = (E2K_NR_COUNT + env->wd.base + wbs * 2) % E2K_NR_COUNT; + env->wd.size -= wbs * 2; + env->wd.psize = env->wd.size; +} + +static inline void proc_chain_restore(CPUE2KState *env) +{ + int wbs; + + e2k_state_cr1_hi_set(env, pcs_pop(env)); + e2k_state_cr1_lo_set(env, pcs_pop(env)); + env->cr0_hi = pcs_pop(env); // FIXME: is it necessary to restore ip? + env->cr0_lo = pcs_pop(env); + + wbs = env->cr1.wbs; + e2k_state_br_set(env, env->cr1.br); + env->wd.size = env->wd.psize + wbs * 2; + env->wd.psize = env->cr1.wpsz * 2; + env->wd.base = (E2K_NR_COUNT + env->wd.base - wbs * 2) % E2K_NR_COUNT; env->wd.fx = env->cr1.wfx; - e2k_state_cr1_hi_set(env, buf[3]); - e2k_state_cr1_lo_set(env, buf[2]); - env->cr0_hi = buf[1]; // FIXME: is it necessary to restore ip? - env->cr0_lo = buf[0]; - - env->wd.psize = env->cr1.wpsz * 2; - e2k_state_br_set(env, env->cr1.br); + env->pshtp.index -= wbs * 2; } -static void pcs_push(CPUE2KState *env, int wbs) +static inline void ps_spill(CPUE2KState *env, bool force, bool force_fx) { - uint64_t buf[4]; - - if (env->pcsp.size < (env->pcsp.index + 32)) { - helper_raise_exception(env, E2K_EXCP_MAPERR); - return; - } - - save_proc_chain_info(env, buf, wbs); - memcpy(env->pcsp.base + env->pcsp.index, buf, 32); - env->pcsp.index += 32; -} - -static void pcs_pop(CPUE2KState *env) -{ - uint64_t buf[4]; - - if (env->pcsp.index < 32) { - helper_raise_exception(env, E2K_EXCP_MAPERR); - return; - } - - env->pcsp.index -= 32; - memcpy(buf, env->pcsp.base + env->pcsp.index, 32); - restore_proc_chain_info(env, buf); -} - -static void ps_push_nfx(CPUE2KState *env, unsigned int base, size_t len) -{ - unsigned int i; - size_t size = len * sizeof(uint64_t); - uint64_t *p; - - if (env->psp.size < (env->psp.index + size)) { - helper_raise_exception(env, E2K_EXCP_MAPERR); - return; - } - - p = (uint64_t *) (env->psp.base + env->psp.index); - for (i = 0; i < len; i++) { - int idx = (base + i) % E2K_NR_COUNT; - memcpy(p + i, &env->regs[idx], sizeof(uint64_t)); - } - - env->psp.index += size; -} - -static void ps_pop_nfx(CPUE2KState *env, unsigned int base, size_t len) -{ - unsigned int i; - size_t size = len * sizeof(uint64_t); - uint64_t *p; - - if (env->psp.index < size) { - // TODO: check where to raise exception - helper_raise_exception(env, E2K_EXCP_MAPERR); - return; - } - - env->psp.index -= size; - p = (uint64_t *) (env->psp.base + env->psp.index); - for (i = 0; i < len; i++) { - int idx = (base + i) % E2K_NR_COUNT; - memcpy(&env->regs[idx], p + i, sizeof(uint64_t)); - } -} - -static void ps_push_fx(CPUE2KState *env, unsigned int base, size_t len) -{ - unsigned int i; - size_t size = len * 2 * sizeof(uint64_t); - uint64_t *p, zeros[2] = { 0 }; - - if (env->psp.size < (env->psp.index + size)) { - helper_raise_exception(env, E2K_EXCP_MAPERR); - return; - } - - p = (uint64_t *) (env->psp.base + env->psp.index); - for (i = 0; i < len; i += 2) { - int idx = (base + i) % E2K_NR_COUNT; - memcpy(p + i * 2, &env->regs[idx], 2 * sizeof(uint64_t)); - // TODO: save fx part - memcpy(p + i * 2 + 2, zeros, 2 * sizeof(uint64_t)); - } - - env->psp.index += size; -} - -static void ps_pop_fx(CPUE2KState *env, unsigned int base, size_t len) -{ - unsigned int i; - size_t size = len * 2 * sizeof(uint64_t); - uint64_t *p; - - if (env->psp.index < size) { - // TODO: check where to raise exception - helper_raise_exception(env, E2K_EXCP_MAPERR); - return; - } - - env->psp.index -= size; - p = (uint64_t *) (env->psp.base + env->psp.index); - for (i = 0; i < len; i += 2) { - int idx = (base + i) % E2K_NR_COUNT; - memcpy(&env->regs[idx], p + i * 2, sizeof(uint64_t)); - // TODO: restore fx part - } -} - -static inline void ps_push(CPUE2KState *env) -{ - int occupied = env->wd.size + env->pshtp.index; - if (E2K_NR_COUNT < occupied) { - int len = occupied - E2K_NR_COUNT; - int base = (int) env->wd.base - env->pshtp.index; - if (base < 0) { - base += E2K_NR_COUNT; + while (E2K_NR_COUNT < env->pshtp.index + env->wd.size || + (force && env->pshtp.index)) + { + int i = (E2K_NR_COUNT + env->wd.base - env->pshtp.index) % E2K_NR_COUNT; + // TODO: push tags + ps_push(env, env->regs[i]); + ps_push(env, env->regs[i + 1]); + env->regs[i] = 0; + env->regs[i + 1] = 0; + // TODO: set invalid reg tags +// e2k_state_reg_tag_set_i64(env, E2K_TAG_NON_NUMBER64, i); +// e2k_state_reg_tag_set_i64(env, E2K_TAG_NON_NUMBER64, i + 1); + // TODO: push fx + if (force_fx) { + ps_push(env, env->xregs[i]); + ps_push(env, env->xregs[i + 1]); } - // TODO: ps_push_fx - ps_push_nfx(env, base, len); - env->pshtp.index -= len; + env->pshtp.index -= 2; } } -static inline void ps_pop(CPUE2KState *env, int base, int required) +static inline void ps_fill(CPUE2KState *env, bool force_fx) { - if (env->pshtp.index < required) { - int len = required - env->pshtp.index; - // TODO: ps_pop_fx - ps_pop_nfx(env, base, len); - env->pshtp.index = 0; - } else { - env->pshtp.index -= required; + while(env->pshtp.index < 0) { + env->pshtp.index += 2; + int i = (E2K_NR_COUNT + env->wd.base - env->pshtp.index) % E2K_NR_COUNT; + // TODO: pop fx + if (force_fx) { + env->xregs[i + 1] = ps_pop(env); + env->xregs[i] = ps_pop(env); + } + // TODO: restore tags + env->regs[i + 1] = ps_pop(env); + env->regs[i] = ps_pop(env); } } static inline void do_call(CPUE2KState *env, int wbs, target_ulong pc_next) { env->ip = pc_next; - env->pshtp.index += wbs * 2; // add old window to allocated registers - pcs_push(env, wbs); + proc_chain_save(env, wbs); reset_ctprs(env); } +void helper_setwd(CPUE2KState *env, uint32_t lts) +{ + env->wd.size = extract32(lts, 5, 7) * 2; + env->wd.fx = extract32(lts, 4, 1) == 0; + + if (env->version >= 3) { + bool dbl = extract32(lts, 3, 1); + // TODO: set dbl + if (dbl != false) { + qemu_log_mask(LOG_UNIMP, "0x%lx: dbl is not implemented!\n", + env->ip); + } + env->cr1.wdbl = dbl; + } + + ps_spill(env, false, true); +} + uint64_t helper_prep_return(CPUE2KState *env, int ipd) { - uint64_t pc; E2KCtpr ret = { 0 }; - void *p; if (env->pcsp.index < 32) { helper_raise_exception(env, E2K_EXCP_MAPERR); return 0; } - p = (void *) env->pcsp.base + env->pcsp.index - 24; - memcpy(&pc, p, 8); - - ret.base = pc; + ret.base = cpu_ldq_le_data(env, env->pcsp.base + env->pcsp.index - 24); ret.tag = CTPR_TAG_RETURN; ret.ipd = ipd; @@ -214,21 +163,8 @@ uint64_t helper_prep_return(CPUE2KState *env, int ipd) void helper_return(CPUE2KState *env) { - uint32_t new_wd_size, new_wd_base, offset; - - offset = env->cr1.wbs * 2; - new_wd_size = env->wd.psize + offset; - new_wd_base = env->wd.base; - if (new_wd_base < offset) { - new_wd_base += E2K_NR_COUNT; - } - new_wd_base = (new_wd_base - offset) % E2K_NR_COUNT; - - ps_pop(env, new_wd_base, offset); - pcs_pop(env); - env->wd.base = new_wd_base; - env->wd.size = new_wd_size; - + proc_chain_restore(env); + ps_fill(env, false); reset_ctprs(env); } @@ -269,29 +205,18 @@ void helper_raise_exception(CPUE2KState *env, int tt) void e2k_break_save_state(CPUE2KState *env) { - int wbs; - - wbs = env->wd.size / 2; - ps_push_fx(env, env->wd.base, env->wd.size); - pcs_push(env, wbs); - - env->wd.base = (env->wd.base + env->wd.size) % E2K_NR_COUNT; + env->is_bp = true; + proc_chain_save(env, env->wd.size / 2); env->wd.size = 0; env->wd.psize = 0; - - env->is_bp = true; + ps_spill(env, true, true); } void helper_break_restore_state(CPUE2KState *env) { - int wbs = env->cr1.wbs; - - pcs_pop(env); - env->wd.size = wbs * 2; - env->wd.base = (env->wd.base - env->wd.size) % E2K_NR_COUNT; - ps_pop_fx(env, env->wd.base, env->wd.size); - env->is_bp = false; + proc_chain_restore(env); + ps_fill(env, true); } @@ -309,26 +234,3 @@ void helper_debug_ptr(void *x) { qemu_log_mask(LOG_UNIMP, "log %#lx\n", (uint64_t) x); } - -void helper_setwd(CPUE2KState *env, uint32_t lts) -{ - env->wd.size = extract32(lts, 5, 7) * 2; - env->wd.fx = extract32(lts, 4, 1) == 0; - - if (env->wd.fx) { - qemu_log_mask(LOG_UNIMP, "0x%lx: wd.fx is not implemented!\n", - env->ip); - } - - if (env->version >= 3) { - bool dbl = extract32(lts, 3, 1); - // TODO: set dbl - if (dbl != false) { - qemu_log_mask(LOG_UNIMP, "0x%lx: dbl is not implemented!\n", - env->ip); - } - env->cr1.wdbl = dbl; - } - - ps_push(env); -}