2020-11-10 13:06:44 +01:00
|
|
|
#include "qemu/osdep.h"
|
2020-11-13 15:49:28 +01:00
|
|
|
#include "qemu/log.h"
|
2020-11-10 13:06:44 +01:00
|
|
|
#include "cpu.h"
|
|
|
|
#include "exec/exec-all.h"
|
|
|
|
#include "qemu/host-utils.h"
|
|
|
|
#include "exec/helper-proto.h"
|
2020-11-12 14:52:51 +01:00
|
|
|
#include "translate.h"
|
2020-11-10 13:06:44 +01:00
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
static inline void reset_ctprs(CPUE2KState *env)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
2020-11-22 08:37:45 +01:00
|
|
|
for (i = 0; i < 3; i++) {
|
2020-11-22 10:44:28 +01:00
|
|
|
env->ctprs[i] = SET_FIELD(env->ctprs[i], CTPR_TAG_NONE,
|
|
|
|
CTPR_TAG_OFF, CTPR_TAG_LEN);
|
2020-11-17 19:58:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void helper_save_cpu_state(CPUE2KState *env)
|
2020-11-16 15:26:39 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2020-11-22 10:44:28 +01:00
|
|
|
env->cr1_lo = SET_FIELD(env->cr1_lo, env->wd_psize / 2,
|
2020-11-16 15:26:39 +01:00
|
|
|
CR1_LO_WPSZ_OFF, CR1_LO_WPSZ_LEN);
|
|
|
|
}
|
|
|
|
|
2020-11-22 10:44:28 +01:00
|
|
|
static inline void restore_br_state(CPUE2KState *env)
|
2020-11-16 15:26:39 +01:00
|
|
|
{
|
|
|
|
uint32_t br;
|
2020-11-22 10:44:28 +01:00
|
|
|
int rbs, rsz, rcur, psz, pcur;
|
2020-11-16 15:26:39 +01:00
|
|
|
|
2020-11-22 10:44:28 +01:00
|
|
|
// FIXME: cr1_hi.br does not modified after return, find a way to restore it
|
2020-11-16 15:26:39 +01:00
|
|
|
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);
|
|
|
|
|
|
|
|
env->boff = rbs * 2;
|
|
|
|
env->bsize = rsz * 2 + 2;
|
|
|
|
env->bcur = rcur * 2;
|
|
|
|
env->psize = psz;
|
|
|
|
env->pcur = pcur;
|
|
|
|
}
|
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
void helper_unimpl(CPUE2KState *env)
|
|
|
|
{
|
|
|
|
CPUState *cs = env_cpu(env);
|
|
|
|
|
|
|
|
cs->exception_index = E2K_EXCP_UNIMPL;
|
|
|
|
cpu_loop_exit(cs);
|
|
|
|
}
|
|
|
|
|
2020-11-10 13:06:44 +01:00
|
|
|
void helper_raise_exception(CPUE2KState *env, int tt)
|
|
|
|
{
|
|
|
|
CPUState *cs = env_cpu(env);
|
2020-11-17 19:58:22 +01:00
|
|
|
helper_save_cpu_state(env);
|
2020-11-10 13:06:44 +01:00
|
|
|
cs->exception_index = tt;
|
|
|
|
cpu_loop_exit(cs);
|
|
|
|
}
|
2020-11-12 14:52:51 +01:00
|
|
|
|
2020-11-16 17:54:28 +01:00
|
|
|
void helper_debug(CPUE2KState *env)
|
|
|
|
{
|
|
|
|
CPUState *cs = env_cpu(env);
|
2020-11-17 19:58:22 +01:00
|
|
|
helper_save_cpu_state(env);
|
2020-11-16 17:54:28 +01:00
|
|
|
cs->exception_index = EXCP_DEBUG;
|
|
|
|
cpu_loop_exit(cs);
|
|
|
|
}
|
|
|
|
|
2020-11-15 17:39:30 +01:00
|
|
|
static void pcs_push(CPUE2KState *env)
|
|
|
|
{
|
|
|
|
size_t size = e2k_state_pcs_size_get(env);
|
|
|
|
size_t offset = e2k_state_pcs_index_get(env);
|
|
|
|
uint64_t *pcsp = (uint64_t *) (e2k_state_pcs_base_get(env) + offset);
|
|
|
|
|
|
|
|
if (offset + 32 > size) {
|
|
|
|
/* TODO: allocate more memory */
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(pcsp, &env->pf, 8);
|
|
|
|
memcpy(pcsp + 1, &env->nip, 8);
|
|
|
|
memcpy(pcsp + 2, &env->cr1_lo, 8);
|
|
|
|
memcpy(pcsp + 3, &env->cr1_hi, 8);
|
|
|
|
|
|
|
|
e2k_state_pcs_index_set(env, offset + 32);
|
|
|
|
}
|
|
|
|
|
2020-11-16 15:26:39 +01:00
|
|
|
static uint64_t pcs_pop(CPUE2KState *env)
|
2020-11-15 17:39:30 +01:00
|
|
|
{
|
|
|
|
size_t offset = e2k_state_pcs_index_get(env);
|
|
|
|
uint64_t *pcsp = (uint64_t *) (e2k_state_pcs_base_get(env) + offset - 32);
|
2020-11-16 15:26:39 +01:00
|
|
|
uint64_t tgt;
|
2020-11-15 17:39:30 +01:00
|
|
|
|
|
|
|
if (offset < 32) {
|
|
|
|
/* TODO: SIGKILL */
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&env->pf, pcsp, 8);
|
2020-11-16 15:26:39 +01:00
|
|
|
memcpy(&tgt, pcsp + 1, 8);
|
2020-11-15 17:39:30 +01:00
|
|
|
memcpy(&env->cr1_lo, pcsp + 2, 8);
|
|
|
|
memcpy(&env->cr1_hi, pcsp + 3, 8);
|
|
|
|
|
|
|
|
e2k_state_pcs_index_set(env, offset - 32);
|
2020-11-16 15:26:39 +01:00
|
|
|
|
|
|
|
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, ®, 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);
|
2020-11-15 17:39:30 +01:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
static inline void do_call(CPUE2KState *env, int call_wbs)
|
2020-11-12 14:52:51 +01:00
|
|
|
{
|
2020-11-22 10:44:28 +01:00
|
|
|
int call_wpsz = env->wd_size / 2 - call_wbs;
|
2020-11-15 17:39:30 +01:00
|
|
|
|
2020-11-22 10:44:28 +01:00
|
|
|
helper_save_cpu_state(env);
|
2020-11-15 17:39:30 +01:00
|
|
|
pcs_push(env);
|
2020-11-22 10:44:28 +01:00
|
|
|
ps_push(env, env->wd_base, call_wbs * 2);
|
2020-11-15 16:05:27 +01:00
|
|
|
|
2020-11-22 10:44:28 +01:00
|
|
|
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;
|
2020-11-15 17:39:30 +01:00
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
reset_ctprs(env);
|
2020-11-15 16:05:27 +01:00
|
|
|
}
|
|
|
|
|
2020-11-19 22:20:03 +01:00
|
|
|
target_ulong helper_return(CPUE2KState *env)
|
2020-11-15 16:05:27 +01:00
|
|
|
{
|
2020-11-22 10:44:28 +01:00
|
|
|
int new_wd_size, new_wd_base, wbs;
|
2020-11-19 22:20:03 +01:00
|
|
|
target_ulong tgt;
|
2020-11-16 15:26:39 +01:00
|
|
|
|
2020-11-22 10:44:28 +01:00
|
|
|
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;
|
2020-11-15 16:05:27 +01:00
|
|
|
|
2020-11-22 10:44:28 +01:00
|
|
|
if (env->wd_base < new_wd_base) {
|
|
|
|
env->wd_base += WREGS_SIZE;
|
|
|
|
}
|
2020-11-15 16:05:27 +01:00
|
|
|
|
2020-11-22 10:44:28 +01:00
|
|
|
tgt = pcs_pop(env);
|
2020-11-16 15:26:39 +01:00
|
|
|
|
2020-11-22 10:44:28 +01:00
|
|
|
ps_pop(env, new_wd_base, env->wd_base - new_wd_base);
|
2020-11-16 15:26:39 +01:00
|
|
|
|
2020-11-22 10:44:28 +01:00
|
|
|
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;
|
2020-11-16 15:26:39 +01:00
|
|
|
|
2020-11-22 10:44:28 +01:00
|
|
|
restore_br_state(env);
|
2020-11-17 19:58:22 +01:00
|
|
|
reset_ctprs(env);
|
2020-11-16 15:26:39 +01:00
|
|
|
|
|
|
|
return tgt;
|
2020-11-15 16:05:27 +01:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:58:22 +01:00
|
|
|
static inline void do_syscall(CPUE2KState *env, int call_wbs)
|
2020-11-16 15:26:39 +01:00
|
|
|
{
|
2020-11-17 19:58:22 +01:00
|
|
|
do_call(env, call_wbs);
|
|
|
|
helper_raise_exception(env, E2K_EXCP_SYSCALL);
|
2020-11-19 22:20:03 +01:00
|
|
|
helper_return(env);
|
2020-11-17 19:58:22 +01:00
|
|
|
reset_ctprs(env);
|
2020-11-15 16:05:27 +01:00
|
|
|
}
|
|
|
|
|
2020-11-19 21:59:16 +01:00
|
|
|
target_ulong helper_call(CPUE2KState *env, uint64_t ctpr,
|
2020-11-17 19:58:22 +01:00
|
|
|
int call_wbs)
|
|
|
|
{
|
|
|
|
int ctpr_tag = GET_FIELD(ctpr, CTPR_TAG_OFF, CTPR_TAG_END);
|
|
|
|
|
|
|
|
helper_save_cpu_state(env);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2020-11-15 16:05:27 +01:00
|
|
|
}
|
|
|
|
|
2020-11-12 22:46:57 +01:00
|
|
|
uint64_t helper_sxt(uint64_t x, uint64_t y)
|
|
|
|
{
|
|
|
|
int size;
|
|
|
|
|
|
|
|
switch (x & 3) {
|
|
|
|
case 0:
|
|
|
|
size = 8;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
size = 16;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
size = 32;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x & 4) {
|
2020-11-13 10:53:21 +01:00
|
|
|
return y & GEN_MASK(0, size);
|
2020-11-12 22:46:57 +01:00
|
|
|
} else {
|
|
|
|
return (((int64_t) y) << (64 - size) >> (64 - size));
|
|
|
|
}
|
|
|
|
}
|
2020-11-13 15:49:28 +01:00
|
|
|
|
|
|
|
void helper_debug_i32(uint32_t x)
|
|
|
|
{
|
|
|
|
qemu_log_mask(LOG_UNIMP, "log %#x\n", x);
|
|
|
|
}
|
|
|
|
|
|
|
|
void helper_debug_i64(uint64_t x)
|
|
|
|
{
|
|
|
|
qemu_log_mask(LOG_UNIMP, "log %#lx\n", x);
|
|
|
|
}
|
2020-11-15 16:05:27 +01:00
|
|
|
|
|
|
|
uint64_t helper_state_reg_get(CPUE2KState *env, int reg)
|
|
|
|
{
|
|
|
|
switch (reg) {
|
|
|
|
case 0x2c: /* %usd.hi */
|
|
|
|
return env->usd_hi;
|
|
|
|
break;
|
|
|
|
case 0x2d: /* %usd.lo */
|
|
|
|
return env->usd_lo;
|
|
|
|
break;
|
|
|
|
case 0x83: /* %lsr */
|
|
|
|
return env->lsr;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* TODO: exception */
|
|
|
|
abort();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void helper_state_reg_set(CPUE2KState *env, int reg, uint64_t val)
|
|
|
|
{
|
|
|
|
switch (reg) {
|
|
|
|
case 0x2c: /* %usd.hi */
|
|
|
|
/* FIXME: user cannot write */
|
|
|
|
env->usd_hi = val;
|
|
|
|
break;
|
|
|
|
case 0x2d: /* %usd.lo */
|
|
|
|
/* FIXME: user cannot write */
|
|
|
|
env->usd_lo = val;
|
|
|
|
break;
|
|
|
|
case 0x83: /* %lsr */
|
|
|
|
env->lsr = val;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* TODO: exception */
|
|
|
|
abort();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-15 19:25:40 +01:00
|
|
|
uint64_t helper_getsp(CPUE2KState *env, uint64_t src2) {
|
2020-11-16 15:26:39 +01:00
|
|
|
uint64_t base = GET_FIELD(env->usd_lo, USD_LO_BASE_OFF, USD_LO_BASE_END);
|
2020-11-15 19:25:40 +01:00
|
|
|
|
|
|
|
base += src2;
|
|
|
|
|
|
|
|
/* TODO: stack overflow */
|
2020-11-16 15:26:39 +01:00
|
|
|
env->usd_lo = SET_FIELD(env->usd_lo, base, USD_LO_BASE_OFF,
|
|
|
|
USD_LO_BASE_LEN);
|
2020-11-15 19:25:40 +01:00
|
|
|
|
|
|
|
return base;
|
|
|
|
}
|
2020-11-16 17:16:27 +01:00
|
|
|
|
|
|
|
uint32_t helper_cur_dec(CPUE2KState *env, uint32_t cur, uint32_t n,
|
|
|
|
uint32_t size)
|
|
|
|
{
|
|
|
|
if (size == 0) {
|
2020-11-17 19:58:22 +01:00
|
|
|
helper_raise_exception(env, E2K_EXCP_MAPERR);
|
2020-11-16 17:16:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return size - (size + n - cur) % size;
|
|
|
|
}
|