qemu-e2k/target/e2k/helper.c

329 lines
7.9 KiB
C
Raw Normal View History

#include "qemu/osdep.h"
2020-11-13 15:49:28 +01:00
#include "qemu/log.h"
#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"
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-26 21:02:34 +01:00
static inline void save_proc_chain_info(CPUE2KState *env, uint64_t buf[4],
int wbs)
2020-11-26 20:14:40 +01:00
{
env->cr1.br = e2k_state_br(env);
env->cr1.wpsz = env->wd.psize / 2;
buf[0] = env->cr0_lo;
buf[1] = env->cr0_hi;
buf[2] = e2k_state_cr1_lo(env);
buf[3] = e2k_state_cr1_hi(env);
2020-11-26 21:02:34 +01:00
env->cr1.wfx = env->wd.fx;
env->cr1.wbs = wbs;
2020-12-01 13:00:12 +01:00
env->wd.base = (env->wd.base + wbs * 2) % E2K_NR_COUNT;
2020-11-26 21:02:34 +01:00
env->wd.psize = env->wd.size -= wbs * 2;
2020-11-26 20:14:40 +01:00
}
static inline void restore_proc_chain_info(CPUE2KState *env, uint64_t buf[4])
{
2020-11-26 21:02:34 +01:00
env->wd.fx = env->cr1.wfx;
2020-11-26 20:14:40 +01:00
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?
2020-11-26 20:14:40 +01:00
env->cr0_lo = buf[0];
env->wd.psize = env->cr1.wpsz * 2;
e2k_state_br_set(env, env->cr1.br);
}
2020-11-23 07:14:26 +01:00
static void pcs_push(CPUE2KState *env, int wbs)
2020-11-15 17:39:30 +01:00
{
2020-11-26 20:14:40 +01:00
uint64_t buf[4];
2020-11-15 17:39:30 +01:00
2020-11-26 20:14:40 +01:00
if (env->pcsp.size < (env->pcsp.index + 32)) {
2020-11-26 17:31:25 +01:00
helper_raise_exception(env, E2K_EXCP_MAPERR);
return;
2020-11-15 17:39:30 +01:00
}
2020-11-26 21:02:34 +01:00
save_proc_chain_info(env, buf, wbs);
2020-11-26 20:14:40 +01:00
memcpy(env->pcsp.base + env->pcsp.index, buf, 32);
env->pcsp.index += 32;
2020-11-15 17:39:30 +01:00
}
2020-11-23 07:14:26 +01:00
static void pcs_pop(CPUE2KState *env)
2020-11-15 17:39:30 +01:00
{
2020-11-26 20:14:40 +01:00
uint64_t buf[4];
2020-11-15 17:39:30 +01:00
2020-11-26 20:14:40 +01:00
if (env->pcsp.index < 32) {
2020-11-26 17:31:25 +01:00
helper_raise_exception(env, E2K_EXCP_MAPERR);
return;
2020-11-15 17:39:30 +01:00
}
2020-11-26 20:14:40 +01:00
env->pcsp.index -= 32;
memcpy(buf, env->pcsp.base + env->pcsp.index, 32);
restore_proc_chain_info(env, buf);
2020-11-16 15:26:39 +01:00
}
2020-11-26 16:02:49 +01:00
static void ps_push_nfx(CPUE2KState *env, unsigned int base, size_t len)
2020-11-16 15:26:39 +01:00
{
unsigned int i;
2020-11-26 16:02:49 +01:00
size_t size = len * sizeof(uint64_t);
uint64_t *p;
2020-11-16 15:26:39 +01:00
2020-11-26 16:02:49 +01:00
if (env->psp.size < (env->psp.index + size)) {
helper_raise_exception(env, E2K_EXCP_MAPERR);
return;
}
2020-11-16 15:26:39 +01:00
2020-11-26 16:02:49 +01:00
p = (uint64_t *) (env->psp.base + env->psp.index);
2020-11-16 15:26:39 +01:00
for (i = 0; i < len; i++) {
2020-12-01 13:00:12 +01:00
int idx = (base + i) % E2K_NR_COUNT;
memcpy(p + i, &env->regs[idx], sizeof(uint64_t));
2020-11-16 15:26:39 +01:00
}
2020-11-26 16:02:49 +01:00
env->psp.index += size;
2020-11-16 15:26:39 +01:00
}
2020-11-26 16:02:49 +01:00
static void ps_pop_nfx(CPUE2KState *env, unsigned int base, size_t len)
2020-11-16 15:26:39 +01:00
{
unsigned int i;
2020-11-26 16:02:49 +01:00
size_t size = len * sizeof(uint64_t);
uint64_t *p;
2020-11-16 15:26:39 +01:00
2020-11-26 16:02:49 +01:00
if (env->psp.index < size) {
// TODO: check where to raise exception
helper_raise_exception(env, E2K_EXCP_MAPERR);
return;
}
2020-11-16 15:26:39 +01:00
2020-11-26 16:02:49 +01:00
env->psp.index -= size;
p = (uint64_t *) (env->psp.base + env->psp.index);
2020-11-16 15:26:39 +01:00
for (i = 0; i < len; i++) {
2020-12-01 13:00:12 +01:00
int idx = (base + i) % E2K_NR_COUNT;
memcpy(&env->regs[idx], p + i, sizeof(uint64_t));
2020-11-26 16:02:49 +01:00
}
}
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) {
2020-12-01 13:00:12 +01:00
int idx = (base + i) % E2K_NR_COUNT;
memcpy(p + i * 2, &env->regs[idx], 2 * sizeof(uint64_t));
2020-11-26 16:02:49 +01:00
// 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;
2020-11-16 15:26:39 +01:00
}
2020-11-26 16:02:49 +01:00
env->psp.index -= size;
p = (uint64_t *) (env->psp.base + env->psp.index);
for (i = 0; i < len; i += 2) {
2020-12-01 13:00:12 +01:00
int idx = (base + i) % E2K_NR_COUNT;
memcpy(&env->regs[idx], p + i * 2, sizeof(uint64_t));
2020-11-26 16:02:49 +01:00
// TODO: restore fx part
}
2020-11-15 17:39:30 +01:00
}
2020-11-26 23:03:54 +01:00
static inline void ps_push(CPUE2KState *env)
{
int occupied = env->wd.size + env->pshtp.index;
2020-12-01 13:00:12 +01:00
if (E2K_NR_COUNT < occupied) {
int len = occupied - E2K_NR_COUNT;
2020-11-26 23:03:54 +01:00
int base = (int) env->wd.base - env->pshtp.index;
if (base < 0) {
2020-12-01 13:00:12 +01:00
base += E2K_NR_COUNT;
2020-11-26 23:03:54 +01:00
}
// TODO: ps_push_fx
ps_push_nfx(env, base, len);
env->pshtp.index -= len;
}
}
static inline void ps_pop(CPUE2KState *env, int base, int required)
{
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;
}
}
2020-11-28 08:44:53 +01:00
static inline void do_call(CPUE2KState *env, int wbs, target_ulong pc_next)
2020-11-12 14:52:51 +01:00
{
2020-11-28 08:44:53 +01:00
env->ip = pc_next;
2020-11-26 23:03:54 +01:00
env->pshtp.index += wbs * 2; // add old window to allocated registers
2020-11-26 21:02:34 +01:00
pcs_push(env, wbs);
reset_ctprs(env);
}
2020-11-28 10:32:50 +01:00
uint64_t helper_prep_return(CPUE2KState *env, int ipd)
{
uint64_t pc, 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 |= deposit64(ret, CTPR_BASE_OFF, CTPR_BASE_LEN, pc);
ret |= deposit64(ret, CTPR_TAG_OFF, CTPR_TAG_LEN, CTPR_TAG_RETURN);
ret |= deposit64(ret, CTPR_IPD_OFF, CTPR_IPD_LEN, ipd);
return ret;
}
2020-11-23 07:14:26 +01:00
void helper_return(CPUE2KState *env)
{
2020-11-26 23:03:54 +01:00
uint32_t new_wd_size, new_wd_base, offset;
2020-11-26 23:03:54 +01:00
offset = env->cr1.wbs * 2;
new_wd_size = env->wd.psize + offset;
new_wd_base = env->wd.base;
if (new_wd_base < offset) {
2020-12-01 13:00:12 +01:00
new_wd_base += E2K_NR_COUNT;
2020-11-22 10:44:28 +01:00
}
2020-12-01 13:00:12 +01:00
new_wd_base = (new_wd_base - offset) % E2K_NR_COUNT;
2020-11-26 23:03:54 +01:00
ps_pop(env, new_wd_base, offset);
2020-11-23 07:14:26 +01:00
pcs_pop(env);
2020-11-26 19:35:07 +01:00
env->wd.base = new_wd_base;
env->wd.size = new_wd_size;
2020-11-16 15:26:39 +01:00
reset_ctprs(env);
}
2020-11-28 08:44:53 +01:00
static inline void do_syscall(CPUE2KState *env, int call_wbs,
target_ulong pc_next)
2020-11-16 15:26:39 +01:00
{
2020-11-28 08:44:53 +01:00
env->ip = pc_next;
2020-11-23 12:35:04 +01:00
env->syscall_wbs = call_wbs;
reset_ctprs(env);
2020-11-23 12:35:04 +01:00
helper_raise_exception(env, E2K_EXCP_SYSCALL);
}
2020-11-28 08:44:53 +01:00
void helper_call(CPUE2KState *env, uint64_t ctpr, int call_wbs,
target_ulong pc_next)
{
2020-11-28 08:44:53 +01:00
int ctpr_tag = extract64(ctpr, CTPR_TAG_OFF, CTPR_TAG_LEN);
switch (ctpr_tag) {
case CTPR_TAG_DISP:
2020-11-28 08:44:53 +01:00
do_call(env, call_wbs, pc_next);
env->ip = extract64(ctpr, CTPR_BASE_OFF, CTPR_BASE_LEN);
break;
case CTPR_TAG_SDISP:
2020-11-28 08:44:53 +01:00
do_syscall(env, call_wbs, pc_next);
break;
default:
2020-11-24 21:50:33 +01:00
abort();
break;
2020-11-23 07:14:26 +01:00
}
}
void helper_raise_exception(CPUE2KState *env, int tt)
{
CPUState *cs = env_cpu(env);
cs->exception_index = tt;
cpu_loop_exit(cs);
}
2020-11-27 07:22:19 +01:00
void e2k_break_save_state(CPUE2KState *env)
2020-11-23 07:14:26 +01:00
{
2020-11-26 16:02:49 +01:00
int wbs;
2020-11-26 19:35:07 +01:00
wbs = env->wd.size / 2;
ps_push_fx(env, env->wd.base, env->wd.size);
2020-11-26 16:02:49 +01:00
pcs_push(env, wbs);
2020-11-23 07:14:26 +01:00
2020-12-01 13:00:12 +01:00
env->wd.base = (env->wd.base + env->wd.size) % E2K_NR_COUNT;
2020-11-26 19:35:07 +01:00
env->wd.size = 0;
env->wd.psize = 0;
2020-11-23 07:14:26 +01:00
env->is_bp = true;
}
void helper_break_restore_state(CPUE2KState *env)
{
2020-11-26 20:14:40 +01:00
int wbs = env->cr1.wbs;
2020-11-23 07:14:26 +01:00
pcs_pop(env);
2020-11-26 19:35:07 +01:00
env->wd.size = wbs * 2;
2020-12-01 13:00:12 +01:00
env->wd.base = (env->wd.base - env->wd.size) % E2K_NR_COUNT;
2020-11-26 19:35:07 +01:00
ps_pop_fx(env, env->wd.base, env->wd.size);
2020-11-23 07:14:26 +01:00
env->is_bp = false;
}
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-28 17:43:24 +01:00
void helper_debug_ptr(void *x)
{
qemu_log_mask(LOG_UNIMP, "log %#lx\n", (uint64_t) x);
}
2020-11-26 21:02:34 +01:00
void helper_setwd(CPUE2KState *env, uint32_t lts)
{
2020-11-26 23:03:54 +01:00
env->wd.size = extract32(lts, 5, 7) * 2;
env->wd.fx = extract32(lts, 4, 1) == 0;
2020-11-26 21:02:34 +01:00
if (env->version >= 3) {
bool dbl = extract32(lts, 3, 1);
// TODO: set dbl
if (dbl != false) {
2020-12-05 13:32:22 +01:00
qemu_log_mask(LOG_UNIMP, "0x%lx: dbl is not implemented!\n",
env->ip);
2020-11-26 21:02:34 +01:00
}
2020-12-05 13:32:22 +01:00
env->cr1.wdbl = dbl;
2020-11-26 21:02:34 +01:00
}
2020-11-26 23:03:54 +01:00
ps_push(env);
2020-11-26 21:02:34 +01:00
}