target: e2k: Add xregs.

This commit is contained in:
Denis Drakhnia 2020-12-09 21:38:16 +02:00
parent 676b4a2388
commit 1887af755a
3 changed files with 130 additions and 219 deletions

View File

@ -1530,13 +1530,13 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
regs->pcsp.is_writable = true; regs->pcsp.is_writable = true;
regs->pcsp.index = 0; regs->pcsp.index = 0;
regs->pcsp.size = TARGET_PAGE_SIZE; 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_readable = true;
regs->psp.is_writable = true; regs->psp.is_writable = true;
regs->psp.index = 0; regs->psp.index = 0;
regs->psp.size = TARGET_PAGE_SIZE * 8; 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) static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUE2KState *env)

View File

@ -287,12 +287,12 @@ typedef struct {
} E2KCr1State; } E2KCr1State;
typedef struct { typedef struct {
void *base; target_ulong base;
uint32_t index; uint32_t index;
uint32_t size; uint32_t size;
bool is_readable; bool is_readable;
bool is_writable; bool is_writable;
} E2KDescState, E2KPsState, E2KPcsState; } E2KStackState, E2KPsState, E2KPcsState;
typedef struct { typedef struct {
int16_t index; int16_t index;
@ -302,7 +302,7 @@ typedef struct {
} E2KPshtpState; } E2KPshtpState;
typedef struct { typedef struct {
uint32_t base; int32_t base;
uint32_t size; uint32_t size;
uint32_t psize; uint32_t psize;
bool fx; bool fx;
@ -454,6 +454,7 @@ typedef union {
typedef struct { typedef struct {
/* register file */ /* register file */
uint64_t regs[E2K_REG_COUNT]; /* registers */ 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 tags[E2K_TAGS_REG_COUNT]; /* registers tags */
uint64_t *rptr; /* pointer to regs */ uint64_t *rptr; /* pointer to regs */
uint64_t *tptr; /* pointer to tags */ uint64_t *tptr; /* pointer to tags */
@ -546,7 +547,7 @@ void e2k_break_save_state(CPUE2KState *env);
#define cpu_signal_handler e2k_cpu_signal_handler #define cpu_signal_handler e2k_cpu_signal_handler
#define cpu_list e2k_cpu_list #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; uint64_t lo = 0;
@ -558,7 +559,7 @@ static inline uint64_t e2k_state_desc_lo(E2KDescState *desc)
return lo; 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; uint64_t hi = 0;
@ -680,6 +681,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); 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);
}
typedef CPUE2KState CPUArchState; typedef CPUE2KState CPUArchState;
typedef E2KCPU ArchCPU; typedef E2KCPU ArchCPU;

View File

@ -15,197 +15,146 @@ static inline void reset_ctprs(CPUE2KState *env)
} }
} }
static inline void save_proc_chain_info(CPUE2KState *env, uint64_t buf[4], static inline void stack_push(CPUE2KState *env, E2KStackState *s, uint64_t value)
int wbs)
{ {
env->cr1.br = e2k_state_br(env); if ((s->index + 8) > s->size) {
env->cr1.wpsz = env->wd.psize / 2; helper_raise_exception(env, E2K_EXCP_MAPERR);
return;
}
buf[0] = env->cr0_lo; cpu_stq_le_data_ra(env, s->base + s->index, value, GETPC());
buf[1] = env->cr0_hi; s->index += 8;
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;
} }
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; env->wd.fx = env->cr1.wfx;
e2k_state_cr1_hi_set(env, buf[3]); env->pshtp.index -= wbs * 2;
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);
} }
static void pcs_push(CPUE2KState *env, int wbs) static inline void ps_spill(CPUE2KState *env, bool force, bool force_fx)
{ {
uint64_t buf[4]; while (E2K_NR_COUNT < env->pshtp.index + env->wd.size ||
(force && env->pshtp.index))
if (env->pcsp.size < (env->pcsp.index + 32)) { {
helper_raise_exception(env, E2K_EXCP_MAPERR); int i = (E2K_NR_COUNT + env->wd.base - env->pshtp.index) % E2K_NR_COUNT;
return; // TODO: push tags
} ps_push(env, env->regs[i]);
ps_push(env, env->regs[i + 1]);
save_proc_chain_info(env, buf, wbs); env->regs[i] = 0;
memcpy(env->pcsp.base + env->pcsp.index, buf, 32); env->regs[i + 1] = 0;
env->pcsp.index += 32; // 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);
static void pcs_pop(CPUE2KState *env) // TODO: push fx
{ if (force_fx) {
uint64_t buf[4]; ps_push(env, env->xregs[i]);
ps_push(env, env->xregs[i + 1]);
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;
} }
// TODO: ps_push_fx env->pshtp.index -= 2;
ps_push_nfx(env, base, len);
env->pshtp.index -= len;
} }
} }
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) { while(env->pshtp.index < 0) {
int len = required - env->pshtp.index; env->pshtp.index += 2;
// TODO: ps_pop_fx int i = (E2K_NR_COUNT + env->wd.base - env->pshtp.index) % E2K_NR_COUNT;
ps_pop_nfx(env, base, len); // TODO: pop fx
env->pshtp.index = 0; if (force_fx) {
} else { env->xregs[i + 1] = ps_pop(env);
env->pshtp.index -= required; 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) static inline void do_call(CPUE2KState *env, int wbs, target_ulong pc_next)
{ {
env->ip = pc_next; env->ip = pc_next;
env->pshtp.index += wbs * 2; // add old window to allocated registers proc_chain_save(env, wbs);
pcs_push(env, wbs);
reset_ctprs(env); 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 helper_prep_return(CPUE2KState *env, int ipd)
{ {
uint64_t pc;
E2KCtpr ret = { 0 }; E2KCtpr ret = { 0 };
void *p;
if (env->pcsp.index < 32) { if (env->pcsp.index < 32) {
helper_raise_exception(env, E2K_EXCP_MAPERR); helper_raise_exception(env, E2K_EXCP_MAPERR);
return 0; return 0;
} }
p = (void *) env->pcsp.base + env->pcsp.index - 24; ret.base = cpu_ldq_le_data(env, env->pcsp.base + env->pcsp.index - 24);
memcpy(&pc, p, 8);
ret.base = pc;
ret.tag = CTPR_TAG_RETURN; ret.tag = CTPR_TAG_RETURN;
ret.ipd = ipd; ret.ipd = ipd;
@ -214,21 +163,8 @@ uint64_t helper_prep_return(CPUE2KState *env, int ipd)
void helper_return(CPUE2KState *env) void helper_return(CPUE2KState *env)
{ {
uint32_t new_wd_size, new_wd_base, offset; proc_chain_restore(env);
ps_fill(env, false);
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;
reset_ctprs(env); reset_ctprs(env);
} }
@ -269,29 +205,18 @@ void helper_raise_exception(CPUE2KState *env, int tt)
void e2k_break_save_state(CPUE2KState *env) void e2k_break_save_state(CPUE2KState *env)
{ {
int wbs; env->is_bp = true;
proc_chain_save(env, env->wd.size / 2);
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->wd.size = 0; env->wd.size = 0;
env->wd.psize = 0; env->wd.psize = 0;
ps_spill(env, true, true);
env->is_bp = true;
} }
void helper_break_restore_state(CPUE2KState *env) 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; env->is_bp = false;
proc_chain_restore(env);
ps_fill(env, true);
} }
void helper_debug(CPUE2KState *env) void helper_debug(CPUE2KState *env)
@ -316,26 +241,3 @@ void helper_debug_ptr(void *x)
{ {
qemu_log_mask(LOG_UNIMP, "log %#lx\n", (uint64_t) 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);
}