e2k: Basic impl of e2k32-linux-user.

Fix target_stat64 field types in 32-bit mode.
Basic impl of getpl.
Basic impl of ldgd{b,h,w,d}.
Basic impl of stgd{b,h,w,d}.
Add e2k exceptions.
Add Dynamic hw stacks expansion.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
This commit is contained in:
Denis Drakhnia 2021-02-18 20:51:45 +02:00 committed by Denis Drakhnia
parent 7198f44549
commit e440ebc3db
15 changed files with 460 additions and 367 deletions

View File

@ -26,11 +26,44 @@
#include "cpu_loop-common.h"
#include "target_elf.h"
static void gen_signal(CPUE2KState *env, int signo, int code, abi_ulong addr)
{
target_siginfo_t info = {
.si_signo = signo,
.si_code = code,
._sifields._sigfault._addr = addr,
// TODO: ._sifields._sigfault._trapno = trapnr
};
queue_signal(env, signo, QEMU_SI_FAULT, &info);
}
static void stack_expand(CPUE2KState *env, E2KStackState *s)
{
abi_ulong new_size, new_size_tag;
abi_long new_base, new_base_tag = 0;
new_size = s->size * 2;
new_size_tag = new_size / 8;
new_base = target_mremap(s->base, s->size, new_size, MREMAP_MAYMOVE, 0);
if (s->base_tag) {
new_base_tag = target_mremap(s->base_tag, s->size / 8, new_size_tag,
MREMAP_MAYMOVE, 0);
}
if (new_base == -1 || new_base_tag == -1) {
gen_signal(env, TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->ip);
return;
}
s->base = new_base;
s->base_tag = new_base_tag;
s->size = new_size;
}
void cpu_loop(CPUE2KState *env)
{
CPUState *cs = env_cpu(env);
int trapnr;
target_siginfo_t info;
while (1) {
cpu_exec_start(cs);
@ -39,7 +72,7 @@ void cpu_loop(CPUE2KState *env)
process_queued_cpu_work(cs);
switch (trapnr) {
case E2K_EXCP_SYSCALL: {
case EXCP_SYSCALL: {
abi_ullong args[E2K_SYSCALL_MAX_ARGS] = { 0 };
int psize = MIN(E2K_SYSCALL_MAX_ARGS, env->wd.size);
abi_ulong ret;
@ -62,41 +95,35 @@ void cpu_loop(CPUE2KState *env)
}
break;
}
case E2K_EXCP_ILLOPC:
case E2K_EXCP_ILLOPN:
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = trapnr == E2K_EXCP_ILLOPC ?
TARGET_ILL_ILLOPC : TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->ip;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
case EXCP_ILLEGAL_OPCODE:
gen_signal(env, TARGET_SIGILL, TARGET_ILL_ILLOPC, env->ip);
break;
case E2K_EXCP_MAPERR:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->ip;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
case EXCP_ILLEGAL_OPERAND:
gen_signal(env, TARGET_SIGILL, TARGET_ILL_ILLOPN, env->ip);
break;
case E2K_EXCP_DIV:
info.si_signo = TARGET_SIGFPE;
info.si_errno = 0;
info.si_code = 0;
info._sifields._sigfault._addr = env->ip;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
case EXCP_CHAIN_STACK_BOUNDS:
stack_expand(env, &env->pcsp);
break;
case EXCP_PROC_STACK_BOUNDS:
stack_expand(env, &env->psp);
break;
case EXCP_WINDOW_BOUNDS:
case EXCP_ARRAY_BOUNDS:
case EXCP_DATA_PAGE:
gen_signal(env, TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->ip);
break;
case EXCP_DIV:
gen_signal(env, TARGET_SIGFPE, 0, env->ip);
break;
/* QEMU common interrupts */
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
case EXCP_DEBUG:
{
info.si_signo = TARGET_SIGTRAP;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
env->is_bp = true;
e2k_proc_call(env, env->wd.size, env->ip, true);
gen_signal(env, TARGET_SIGTRAP, TARGET_TRAP_BRKPT, 0);
break;
}
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;

View File

@ -3,6 +3,7 @@
*
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2020 Alibek Omarov
* Copyright (c) 2021 Denis Drakhnya
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -205,8 +206,8 @@ static void target_setup_frame(int sig, struct target_sigaction *ka,
if (setup_ucontext(&frame->uc, env)) {
goto fail;
}
copy_to_user((abi_ulong) &frame->uc.uc_sigmask, set, sizeof(*set));
copy_to_user((abi_ulong) &frame->aau, &env->aau, sizeof(env->aau));
copy_to_user((uintptr_t) &frame->uc.uc_sigmask, set, sizeof(*set));
copy_to_user((uintptr_t) &frame->aau, &env->aau, sizeof(env->aau));
if (ka->sa_flags & TARGET_SA_RESTORER) {
// TODO: sa_restorer?
@ -262,7 +263,7 @@ static abi_long target_restore_sigframe(CPUE2KState *env,
__get_user(env->ctprs[1].raw, &frame->uc.uc_extra.ctpr2);
__get_user(env->ctprs[2].raw, &frame->uc.uc_extra.ctpr3);
copy_from_user(&env->aau, (abi_ulong) &frame->aau, sizeof(env->aau));
copy_from_user(&env->aau, (uintptr_t) &frame->aau, sizeof(env->aau));
return 0;
}

View File

@ -17,6 +17,9 @@
#define E2K_MAXSR_d (E2K_MAXSR * 2) /* The total number of stack */
/* double-NRs */
#define E2K_DEFAULT_PCS_SIZE (TARGET_PAGE_SIZE)
#define E2K_DEFAULT_PS_SIZE (TARGET_PAGE_SIZE * 4)
typedef uint64_t e2k_greg_t; // double word
struct target_pt_regs {

View File

@ -1594,17 +1594,17 @@ struct target_stat {
#define TARGET_HAS_STRUCT_STAT64
struct target_stat64 {
abi_ulong st_dev;
abi_ulong st_ino;
abi_ullong st_dev;
abi_ullong st_ino;
abi_uint st_mode;
abi_uint st_nlink;
abi_uint st_uid;
abi_uint st_gid;
abi_ulong st_rdev;
abi_ulong st_size;
abi_ullong st_rdev;
abi_ullong st_size;
abi_uint st_blksize;
abi_uint __unused1;
abi_ulong st_blocks;
abi_ullong st_blocks;
abi_int target_st_atime;
abi_uint target_st_atime_nsec;
abi_int target_st_mtime;

View File

@ -7,10 +7,14 @@
#ifndef E2K_CPU_PARAM_H
#define E2K_CPU_PARAM_H 1
#ifdef TARGET_E2K32
# define TARGET_LONG_BITS 32
#else
# define TARGET_LONG_BITS 64
# define TARGET_PAGE_BITS 12 /* 4k */
# define TARGET_PHYS_ADDR_SPACE_BITS 40
# define TARGET_VIRT_ADDR_SPACE_BITS 48
# define NB_MMU_MODES 4
#endif
#define TARGET_PAGE_BITS 12 /* 4k */
#define TARGET_PHYS_ADDR_SPACE_BITS 40
#define TARGET_VIRT_ADDR_SPACE_BITS 48
#define NB_MMU_MODES 4
#endif

View File

@ -151,7 +151,7 @@ void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
CPUE2KState *env = &cpu->env;
unsigned int i;
qemu_fprintf(f, " ip = 0x%016lx\n", env->ip);
qemu_fprintf(f, " ip = " TARGET_FMT_lx "\n", env->ip);
qemu_fprintf(f, " pregs = 0x%016lx\n", env->pregs);
qemu_fprintf(f, " pcsp_lo = 0x%016lx\n", e2k_state_pcsp_lo(env));
qemu_fprintf(f, " pcsp_hi = 0x%016lx\n", e2k_state_pcsp_hi(env));

View File

@ -33,8 +33,6 @@ void e2k_tcg_initialize(void);
#define MMU_USER_IDX 1
#define CPU_RESOLVING_TYPE TYPE_E2K_CPU
#define E2K_DEFAULT_PCS_SIZE (TARGET_PAGE_SIZE * 4)
#define E2K_DEFAULT_PS_SIZE (TARGET_PAGE_SIZE * 16)
#define E2K_TAG_SIZE 2 /* 2-bit tag for 32-bit value */
#define E2K_REG_LEN sizeof(uint64_t)
@ -90,15 +88,24 @@ typedef enum {
} CtprOpc;
#ifdef CONFIG_USER_ONLY
#define E2K_SYSCALL_MAX_ARGS 10
# define E2K_SYSCALL_MAX_ARGS 10
/* fake kernel addresses */
#define E2K_FAKE_KERN_START 0xe20000000000
#define E2K_FAKE_KERN_END 0xe30000000000
#define E2K_SYSCALL_ADDR3 0xe20000001800
#define E2K_SYSCALL_ADDR6 0xe20000003000
#define E2K_SYSRET_ADDR 0xe28000000000
#define E2K_SYSRET_ADDR_CTPR 0xe2fffffffff8
#define E2K_SIGRET_ADDR 0xe20000015800
# if TARGET_LONG_BITS == 64
# define E2K_FAKE_KERN_START 0xe20000000000
# define E2K_FAKE_KERN_END 0xe30000000000
# define E2K_SYSRET_ADDR (E2K_FAKE_KERN_START + 0x8000000000)
# define E2K_SYSRET_ADDR_CTPR (E2K_FAKE_KERN_START + 0xfffffffff8)
# define E2K_SYSCALL_ADDR3 (E2K_FAKE_KERN_START + 0x800 * 3)
# define E2K_SYSCALL_ADDR6 (E2K_FAKE_KERN_START + 0x800 * 6)
# else /* TARGET_LONG_BITS == 32 */
# define E2K_FAKE_KERN_START 0xe0000000
# define E2K_FAKE_KERN_END 0xe3000000
# define E2K_SYSRET_ADDR (E2K_FAKE_KERN_START + 0x800000)
# define E2K_SYSRET_ADDR_CTPR (E2K_FAKE_KERN_START + 0xfffff8)
# define E2K_SYSCALL_ADDR1 (E2K_FAKE_KERN_START + 0x800 * 1)
# define E2K_SYSCALL_ADDR4 (E2K_FAKE_KERN_START + 0x800 * 4)
# endif
# define E2K_SIGRET_ADDR (E2K_FAKE_KERN_START + 0x15800)
#endif
#define WD_BASE_OFF 0
@ -280,11 +287,55 @@ typedef enum {
#define IDR_WBL_TO_BYTES(wbl) ((wbl) ? (1 << ((wbs) + 4)) : 1)
typedef enum {
E2K_EXCP_SYSCALL = 0x02,
E2K_EXCP_ILLOPC = 0x03,
E2K_EXCP_ILLOPN = 0x04,
E2K_EXCP_MAPERR = 0x05,
E2K_EXCP_DIV = 0x06,
EXCP_ILLEGAL_OPCODE = 0,
EXCP_PRIV_ACTION = 1,
EXCP_FP_DISABLED = 2,
EXCP_FP_STACK_U = 3,
EXCP_D_INTERRUPT = 4,
EXCP_DIAG_CT_COND = 5,
EXCP_DIAG_INSTR_ADDR = 6,
EXCP_ILLEGAL_INSTR_ADDR = 7,
EXCP_INSTR_DEBUG = 8,
EXCP_WINDOW_BOUNDS = 9,
EXCP_USER_STACK_BOUNDS = 10,
EXCP_PROC_STACK_BOUNDS = 11,
EXCP_CHAIN_STACK_BOUNDS = 12,
EXCP_FP_STACK_O = 13,
EXCP_DIAG_COND = 14,
EXCP_DIAG_OPERAND = 15,
EXCP_ILLEGAL_OPERAND = 16,
EXCP_ARRAY_BOUNDS = 17,
EXCP_ACCESS_RIGHTS = 18,
EXCP_ADDR_NOT_ALIGNED = 19,
EXCP_INSTR_PAGE_MISS = 20,
EXCP_INSTR_PAGE_PROT = 21,
EXCP_AINSTR_PAGE_MISS = 22,
EXCP_AINSTR_PAGE_PROT = 23,
EXCP_LAST_WISH = 24,
EXCP_BASE_NOT_ALIGNED = 25,
EXCP_DATA_DEBUG = 28,
EXCP_DATA_PAGE = 29,
EXCP_RECOVERY_POINT = 31,
EXCP_INTERRUPT = 32,
EXCP_NM_INTERRUPT = 33,
EXCP_DIV = 34,
EXCP_FP = 35,
EXCP_MEM_LOCK = 36,
EXCP_MEM_LOCK_AS = 37,
EXCP_MEM_ERROR_OUT_CPU = 38,
EXCP_MEM_ERROR_MAU = 39,
EXCP_MEM_ERROR_L2 = 40,
EXCP_MEM_ERROR_L1_35 = 41,
EXCP_MEM_ERROR_L1_02 = 42,
EXCP_MEM_ERROR_ICACHE = 43,
EXCP_MAX = 43,
#ifdef CONFIG_USER_ONLY
EXCP_SYSCALL = 100,
#endif
} Exception;
struct e2k_def_t {
@ -384,8 +435,8 @@ typedef struct {
typedef struct {
int32_t base;
uint32_t size;
uint32_t psize;
int32_t size;
int32_t psize;
bool fx;
} E2KWdState;

View File

@ -1,13 +1,9 @@
#include "qemu/osdep.h"
#include "helper-tcg.h"
#include "qemu/log.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "translate.h"
#define PS_FORCE_FX true
void helper_signal_frame(CPUE2KState *env, int wbs, target_ulong ret_ip);
static inline void reset_ctprs(CPUE2KState *env)
@ -19,41 +15,29 @@ static inline void reset_ctprs(CPUE2KState *env)
}
}
static inline void stack_push(CPUE2KState *env, E2KStackState *s, uint64_t value)
{
if ((s->index + 8) > s->size) {
helper_raise_exception(env, E2K_EXCP_MAPERR);
return;
}
cpu_stq_le_data_ra(env, s->base + s->index, value, GETPC());
s->index += 8;
}
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);
}
static inline void ps_push(CPUE2KState *env, uint64_t value, uint8_t tag)
{
#ifndef CONFIG_USER_ONLY
if ((env->psp.index + 8) > env->psp.size) {
raise_exception(env, EXCP_PROC_STACK_BOUNDS);
}
#endif
cpu_stq_le_data(env, env->psp.base + env->psp.index, value);
cpu_stb_data(env, env->psp.base_tag + env->psp.index / 8, tag);
stack_push(env, &env->psp, value);
env->psp.index += 8;
}
static inline uint64_t ps_pop(CPUE2KState *env, uint8_t *ret_tag)
{
uint64_t ret = stack_pop(env, &env->psp);
if (env->psp.index < 8) {
raise_exception(env, EXCP_PROC_STACK_BOUNDS);
}
env->psp.index -= 8;
if (ret_tag != NULL) {
*ret_tag = cpu_ldub_data(env, env->psp.base_tag + env->psp.index / 8);
}
return ret;
return cpu_ldq_le_data(env, env->psp.base + env->psp.index);
}
static void ps_spill(CPUE2KState *env, int n, bool fx)
@ -119,11 +103,11 @@ static void crs_read(CPUE2KState *env, target_ulong addr, E2KCrs *crs)
static void pcs_push(CPUE2KState *env, E2KCrs *crs)
{
#ifndef CONFIG_USER_ONLY
if ((env->pcsp.index + sizeof(E2KCrs) * 2) > env->pcsp.size) {
// TODO: stack expand (switch to next stack)
qemu_log_mask(LOG_UNIMP, "e2k stack expand\n");
helper_raise_exception(env, E2K_EXCP_MAPERR);
raise_exception(env, EXCP_CHAIN_STACK_BOUNDS);
}
#endif
env->pcsp.index += sizeof(E2KCrs);
crs_write(env, env->pcsp.base + env->pcsp.index, crs);
@ -134,8 +118,7 @@ static void pcs_pop(CPUE2KState *env, E2KCrs *crs)
crs_read(env, env->pcsp.base + env->pcsp.index, crs);
if (env->pcsp.index < sizeof(E2KCrs)) {
// TODO: stack shrink (switch to previous stack)
qemu_log_mask(LOG_UNIMP, "e2k stack shrink\n");
raise_exception(env, EXCP_CHAIN_STACK_BOUNDS);
} else {
env->pcsp.index -= sizeof(E2KCrs);
}
@ -203,7 +186,7 @@ static inline void do_call(CPUE2KState *env, int wbs, target_ulong ret_ip)
void HELPER(syscall)(CPUE2KState *env)
{
CPUState *cs = env_cpu(env);
cs->exception_index = E2K_EXCP_SYSCALL;
cs->exception_index = EXCP_SYSCALL;
cpu_loop_exit(cs);
}
@ -219,11 +202,24 @@ void HELPER(call)(CPUE2KState *env, uint64_t ctpr_raw, int call_wbs,
env->ip = ctpr.base;
break;
default:
helper_raise_exception(env, E2K_EXCP_ILLOPC);
raise_exception(env, EXCP_ILLEGAL_OPCODE);
break;
}
}
#ifdef CONFIG_USER_ONLY
void HELPER(expand_stacks)(CPUE2KState *env)
{
if ((env->psp.size - env->psp.index) <= (E2K_REG_LEN * E2K_NR_COUNT * 4)) {
raise_exception_ra(env, EXCP_PROC_STACK_BOUNDS, GETPC());
}
if ((env->pcsp.size - env->pcsp.index) <= (sizeof(E2KCrs) * 2)) {
raise_exception_ra(env, EXCP_CHAIN_STACK_BOUNDS, GETPC());
}
}
#endif /* CONFIG_USER_ONLY */
uint64_t HELPER(prep_return)(CPUE2KState *env, int ipd)
{
E2KCtpr ret = { 0 };
@ -252,11 +248,11 @@ void HELPER(return)(CPUE2KState *env)
env->wd.psize = 2;
env->regs[0] = 119; /* TARGET_NR_sigreturn */
env->tags[0] = E2K_TAG_NUMBER64;
cs->exception_index = E2K_EXCP_SYSCALL;
cs->exception_index = EXCP_SYSCALL;
cpu_loop_exit(cs);
} else {
if (opc != 0) {
qemu_log("%#lx: unknown return ctpr opc %d\n", env->ip, opc);
qemu_log(TARGET_FMT_lx ": unknown return ctpr opc %d\n", env->ip, opc);
}
proc_return(env, false);
@ -264,31 +260,51 @@ void HELPER(return)(CPUE2KState *env)
}
}
void HELPER(raise_exception)(CPUE2KState *env, int tt)
void G_NORETURN raise_exception(CPUE2KState *env, int exception_index)
{
CPUState *cs = env_cpu(env);
cs->exception_index = tt;
proc_call(env, env->wd.size, env->ip, true);
cpu_loop_exit(cs);
raise_exception_ra(env, exception_index, 0);
}
void HELPER(raise_exception_no_spill)(CPUE2KState *env, int tt)
void G_NORETURN raise_exception_ra(CPUE2KState *env, int exception_index,
uintptr_t retaddr)
{
CPUState *cs = env_cpu(env);
cs->exception_index = tt;
cpu_loop_exit(cs);
switch (exception_index) {
case EXCP_PROC_STACK_BOUNDS:
case EXCP_CHAIN_STACK_BOUNDS:
/* ignore */
break;
default:
proc_call(env, env->wd.size, env->ip, true);
break;
}
cs->exception_index = exception_index;
cpu_loop_exit_restore(cs, retaddr);
}
void HELPER(raise_exception)(CPUE2KState *env, int exception_index)
{
raise_exception(env, exception_index);
}
void HELPER(setwd)(CPUE2KState *env, int wsz, int nfx, int dbl)
{
int i, size = wsz * 2;
int size, diff;
size = wsz * 2;
diff = size - env->wd.size;
if (size < env->wd.psize) {
helper_raise_exception(env, E2K_EXCP_ILLOPN);
raise_exception(env, EXCP_ILLEGAL_OPCODE);
}
for (i = env->wd.size; i < size; i++) {
env->tags[i] = E2K_TAG_NON_NUMBER64;
if (diff > 0) {
// FIXME: zeroing registers is not needed, but useful for debugging
#if 1
memset(&env->regs[env->wd.size], 0, diff * sizeof(env->regs[0]));
memset(&env->xregs[env->wd.size], 0, diff * sizeof(env->xregs[0]));
#endif
memset(&env->tags[env->wd.size], E2K_TAG_NON_NUMBER64, diff);
}
env->wd.size = size;
@ -303,8 +319,7 @@ bool e2k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
CPUE2KState *env = &cpu->env;
proc_call(env, env->wd.size, env->ip, true);
cs->exception_index = E2K_EXCP_MAPERR;
cs->exception_index = EXCP_DATA_PAGE;
cpu_loop_exit_restore(cs, retaddr);
}
@ -313,19 +328,3 @@ void HELPER(break_restore_state)(CPUE2KState *env)
proc_return(env, true);
env->is_bp = false;
}
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);
}
void HELPER(debug_ptr)(void *x)
{
qemu_log_mask(LOG_UNIMP, "log %p\n", x);
}

View File

@ -1,3 +1,5 @@
// TODO: set helper call flags
#define dh_alias_Reg ptr
#define dh_alias_f80 ptr
#define dh_ctype_Reg E2KReg *
@ -8,16 +10,13 @@
#define dh_is_signed_f80 dh_is_signed_ptr
DEF_HELPER_2(raise_exception, noreturn, env, int)
DEF_HELPER_2(raise_exception_no_spill, noreturn, env, int)
DEF_HELPER_2(prep_return, i64, env, int)
DEF_HELPER_1(return, void, env)
DEF_HELPER_1(signal_return, void, env)
DEF_HELPER_4(call, void, env, i64, int, tl)
DEF_HELPER_1(expand_stacks, void, env)
DEF_HELPER_1(syscall, void, env)
DEF_HELPER_2(sxt, i64, i64, i32)
DEF_HELPER_1(debug_i32, void, i32)
DEF_HELPER_1(debug_i64, void, i64)
DEF_HELPER_1(debug_ptr, void, ptr)
DEF_HELPER_2(state_reg_read_i64, i64, env, int)
DEF_HELPER_2(state_reg_read_i32, i32, env, int)
DEF_HELPER_3(state_reg_write_i64, void, env, int, i64)

View File

@ -26,8 +26,7 @@ void HELPER(aau_load_program)(CPUE2KState *env)
E2KCtpr ctpr = env->ctprs[1];
if (ctpr.tag != CTPR_TAG_DISP || ctpr.opc != CTPR_OPC_LDISP) {
helper_raise_exception(env, E2K_EXCP_ILLOPC);
return;
helper_raise_exception(env, EXCP_ILLEGAL_OPCODE);
}
for (i = 0; i < 32; i++) {

View File

@ -37,33 +37,6 @@ static void gen_goto_tb(DisasContext *ctx, int tb_num, target_ulong pc)
}
}
void e2k_tr_gen_exception(DisasContext *ctx, int which)
{
TCGv_i32 t = tcg_const_i32(which);
e2k_gen_save_cpu_state(ctx);
gen_helper_raise_exception(cpu_env, t);
ctx->base.is_jmp = DISAS_NORETURN;
tcg_temp_free_i32(t);
}
void e2k_tr_gen_exception_no_spill(DisasContext *ctx, int excp)
{
TCGv_i32 t0 = tcg_const_i32(excp);
e2k_gen_save_cpu_state(ctx);
gen_helper_raise_exception_no_spill(cpu_env, t0);
ctx->base.is_jmp = DISAS_NORETURN;
tcg_temp_free_i32(t0);
}
static inline void illop(DisasContext *ctx)
{
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
}
////////////////////////////////////////////////////////////////////
//// Decode
////////////////////////////////////////////////////////////////////
@ -288,7 +261,7 @@ static inline void decode_cs1(DisasContext *ctx, const UnpackedBundle *raw)
if (opc == SETR0 || opc == SETR1) {
uint32_t lts0 = raw->lts[0];
if (!raw->lts_present[0]) {
illop(ctx);
gen_tr_excp_illopc(ctx);
return;
}
setr->type |= opc == SETR1 ? SETR_VFRPSZ : 0;
@ -313,7 +286,7 @@ static inline void decode_cs1(DisasContext *ctx, const UnpackedBundle *raw)
} else if (opc == SETEI) {
if (extract32(cs1, 27, 1)) {
if (ctx->version < 2) {
illop(ctx);
gen_tr_excp_illopc(ctx);
return;
}
ret->type = CS1_SETSFT;
@ -353,7 +326,7 @@ static inline void decode_cs1(DisasContext *ctx, const UnpackedBundle *raw)
int cs0_opc = extract32(raw->cs0, 28, 4);
int disp = extract32(raw->cs0, 1, 5);
if (cs1_ctopc != 2 || cs0_opc != 0 || !raw->cs0_present) {
illop(ctx);
gen_tr_excp_illopc(ctx);
return;
}
ret->type = CS1_HCALL;
@ -376,7 +349,7 @@ static inline void decode_cs1(DisasContext *ctx, const UnpackedBundle *raw)
ret->vfbg.dmask = extract32(cs1, 8, 8);
ret->vfbg.chkm4 = extract32(cs1, 16, 1);
} else {
illop(ctx);
gen_tr_excp_illopc(ctx);
}
}
@ -397,7 +370,7 @@ static inline void decode_cs0(DisasContext *ctx, const UnpackedBundle *raw)
case 0: // disp
case 1: // ldisp
if (ctp_opc == 1 && ctpr != 2) {
illop(ctx);
gen_tr_excp_illopc(ctx);
return;
}
ret->type = CS0_DISP;
@ -449,7 +422,7 @@ static inline void decode_cs0(DisasContext *ctx, const UnpackedBundle *raw)
switch(ret->type) {
case CS0_NONE:
illop(ctx);
gen_tr_excp_illopc(ctx);
break;
case CS0_IBRANCH:
case CS0_DONE:
@ -462,7 +435,7 @@ static inline void decode_cs0(DisasContext *ctx, const UnpackedBundle *raw)
|| bundle->cs1.type == CS1_HCALL)
{
ret->type = CS0_NONE;
illop(ctx);
gen_tr_excp_illopc(ctx);
}
break;
default:
@ -619,7 +592,7 @@ static inline void gen_cs0(DisasContext *ctx)
}
case CS0_SDISP: {
// TODO: real sdisp target address
target_ulong target = 0xe2UL << 40;
target_ulong target = E2K_FAKE_KERN_START;
target = deposit64(target, 11, 17, cs0->sdisp.disp);
uint64_t ctpr = ctpr_new(CTPR_TAG_SDISP, 0, cs0->sdisp.ipd, target);
gen_set_ctpr(cs0->sdisp.ctpr, ctpr);
@ -918,8 +891,8 @@ static inline target_ulong do_decode(DisasContext *ctx, CPUState *cs)
len = unpack_bundle(env, ctx);
if (len == 0) {
len = 8;
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
gen_tr_excp_illopc(ctx);
return ctx->pc + 8;
}
decode_cs1(ctx, &ctx->bundle);
@ -930,11 +903,12 @@ static inline target_ulong do_decode(DisasContext *ctx, CPUState *cs)
return ctx->pc + len;
}
static inline void gen_maperr_condi_i32(TCGCond cond, TCGv_i32 arg1, int arg2)
static inline void gen_window_bounds_checki_i32(TCGCond cond, TCGv_i32 arg1,
int arg2)
{
TCGLabel *l0 = gen_new_label();
tcg_gen_brcondi_i32(tcg_invert_cond(cond), arg1, arg2, l0);
e2k_gen_exception(E2K_EXCP_MAPERR);
gen_excp_window_bounds();
gen_set_label(l0);
}
@ -946,45 +920,46 @@ static inline void do_checks(DisasContext *ctx)
if (ctx->wd_size != DYNAMIC) {
/* %rN src static check */
if (ctx->wd_size <= ctx->max_r_src) {
e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR);
gen_tr_excp_window_bounds(ctx);
}
/* %rN dst static check */
if (b->cs1.type == CS1_SETR && (setr->type & SETR_WD)) {
if (setr->wsz * 2 <= ctx->max_r_dst) {
e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR);
gen_tr_excp_window_bounds(ctx);
}
} else if (ctx->wd_size <= ctx->max_r_dst) {
e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR);
gen_tr_excp_window_bounds(ctx);
}
} else if (b->cs1.type == CS1_SETR && (setr->type & SETR_WD)) {
/* %rN src dynamic check */
if (ctx->max_r < ctx->max_r_src) {
ctx->max_r = ctx->max_r_src;
gen_maperr_condi_i32(TCG_COND_LE, e2k_cs.wd_size, ctx->max_r_src);
gen_window_bounds_checki_i32(TCG_COND_LE, e2k_cs.wd_size,
ctx->max_r_src);
}
/* %rN dst static check */
if (setr->wsz * 2 <= ctx->max_r_dst) {
e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR);
gen_tr_excp_window_bounds(ctx);
}
} else {
/* %rN src/dst dynamic check */
int max = MAX(ctx->max_r_src, ctx->max_r_dst);
if (ctx->max_r < max) {
ctx->max_r = max;
gen_maperr_condi_i32(TCG_COND_LE, e2k_cs.wd_size, max);
gen_window_bounds_checki_i32(TCG_COND_LE, e2k_cs.wd_size, max);
}
}
if (ctx->bsize != DYNAMIC) {
/* %b[N] src/dst static check */
if (ctx->bsize <= ctx->max_b_cur) {
e2k_tr_gen_exception(ctx, E2K_EXCP_MAPERR);
gen_tr_excp_window_bounds(ctx);
}
} else if (ctx->max_b < ctx->max_b_cur) {
/* %b[N] src/dst dynamic check */
ctx->max_b = ctx->max_b_cur;
gen_maperr_condi_i32(TCG_COND_LE, e2k_cs.bsize, ctx->max_b);
gen_window_bounds_checki_i32(TCG_COND_LE, e2k_cs.bsize, ctx->max_b);
}
}
@ -1026,12 +1001,12 @@ static inline void do_branch(DisasContext *ctx, target_ulong pc_next)
if (ctx->do_check_illtag) {
tcg_gen_brcondi_i32(TCG_COND_EQ, ctx->illtag, 0, l0);
e2k_gen_exception(E2K_EXCP_ILLOPC);
gen_excp_illopc();
gen_set_label(l0);
}
if (ctx->ct.type == CT_NONE) {
e2k_gen_save_pc(ctx->base.pc_next);
gen_save_pc(ctx->base.pc_next);
return;
}
@ -1060,8 +1035,8 @@ static inline void do_branch(DisasContext *ctx, target_ulong pc_next)
tcg_gen_brcondi_i64(TCG_COND_EQ, t0, CTPR_TAG_RETURN, l1);
tcg_temp_free_i64(t0);
// TODO: ldisp, sdisp
e2k_gen_exception(0);
// TODO: ldisp or sdisp
gen_excp_illopc();
gen_set_label(l1);
gen_helper_return(cpu_env);
@ -1152,8 +1127,13 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs)
switch (ctx->base.pc_next) {
#ifdef CONFIG_USER_ONLY
# ifdef TARGET_E2K32
case E2K_SYSCALL_ADDR1:
case E2K_SYSCALL_ADDR4:
# else /* !TARGET_E2K32 */
case E2K_SYSCALL_ADDR3:
case E2K_SYSCALL_ADDR6:
# endif
/* fake enter into syscall handler */
ctx->base.is_jmp = DISAS_NORETURN;
/* force non-zero tb size */
@ -1180,9 +1160,15 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs)
gen_helper_signal_return(cpu_env);
tcg_gen_exit_tb(NULL, TB_EXIT_IDX0);
break;
#endif
#endif /* CONFIG_USER_ONLY */
default: {
pc_next = do_decode(ctx, cs);
#ifdef CONFIG_USER_ONLY
if (ctx->bundle2.cs1.type == CS1_CALL) {
gen_save_cpu_state(ctx);
gen_helper_expand_stacks(cpu_env);
}
#endif /* CONFIG_USER_ONLY */
do_execute(ctx);
do_checks(ctx);
do_commit(ctx);

View File

@ -403,87 +403,62 @@ typedef struct DisasContext {
ControlTransfer ct;
} DisasContext;
/* exception generated in translation time */
void e2k_tr_gen_exception(DisasContext *dc, int which);
void e2k_tr_gen_exception_no_spill(DisasContext *ctx, int excp);
static inline void gen_save_pc(target_ulong pc)
{
tcg_gen_movi_tl(e2k_cs.pc, pc);
}
/* exception generated in runtime */
static inline void e2k_gen_exception(int excp)
static inline void gen_save_cpu_state(DisasContext *ctx)
{
gen_save_pc(ctx->pc);
}
static inline void gen_tr_exception(DisasContext *ctx, int exception_index)
{
TCGv_i32 t0 = tcg_const_i32(exception_index);
ctx->base.is_jmp = DISAS_NORETURN;
gen_save_cpu_state(ctx);
gen_helper_raise_exception(cpu_env, t0);
tcg_temp_free_i32(t0);
}
#define IMPL_GEN_TR_EXCP(name, excp) \
static inline void name(DisasContext *ctx) \
{ \
gen_tr_exception(ctx, excp); \
}
IMPL_GEN_TR_EXCP(gen_tr_excp_illopc, EXCP_ILLEGAL_OPCODE)
IMPL_GEN_TR_EXCP(gen_tr_excp_illopn, EXCP_ILLEGAL_OPERAND)
IMPL_GEN_TR_EXCP(gen_tr_excp_window_bounds, EXCP_WINDOW_BOUNDS)
IMPL_GEN_TR_EXCP(gen_tr_excp_array_bounds, EXCP_ARRAY_BOUNDS)
static inline void gen_exception(int excp)
{
TCGv_i32 t0 = tcg_const_i32(excp);
// TODO: check if need to save state
gen_helper_raise_exception(cpu_env, t0);
tcg_temp_free_i32(t0);
}
#define IMPL_GEN_EXCP(name, excp) \
static inline void name(void) \
{ \
gen_exception(excp); \
}
IMPL_GEN_EXCP(gen_excp_illopc, EXCP_ILLEGAL_OPCODE)
IMPL_GEN_EXCP(gen_excp_window_bounds, EXCP_WINDOW_BOUNDS)
#define e2k_todo(ctx, fmt, ...) \
qemu_log("%#lx: " fmt " (%s:%d)\n", ctx->pc, \
qemu_log(TARGET_FMT_lx ": " fmt " (%s:%d)\n", ctx->pc, \
## __VA_ARGS__, __FILE__, __LINE__)
#define e2k_todo_illop(ctx, fmt, ...) \
e2k_todo(ctx, fmt, ## __VA_ARGS__); \
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC)
static inline void e2k_gen_mask_i64(TCGv_i64 ret, TCGv_i64 len)
{
TCGv_i64 one = tcg_const_i64(1);
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_shl_i64(t0, one, len);
tcg_gen_subi_i64(ret, t0, 1);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(one);
}
static inline void e2k_gen_maski_i64(TCGv_i64 ret, int len)
{
TCGv_i64 t0 = tcg_const_i64(len);
e2k_gen_mask_i64(ret, t0);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg1,
TCGv_i64 offset, TCGv_i64 len)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
tcg_gen_shr_i64(t0, arg1, offset);
e2k_gen_mask_i64(t1, len);
tcg_gen_and_i64(ret, t0, t1);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1,
TCGv_i64 arg2, TCGv_i64 offset, TCGv_i64 len)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
TCGv_i64 t3 = tcg_temp_new_i64();
TCGv_i64 t4 = tcg_temp_new_i64();
TCGv_i64 t5 = tcg_temp_new_i64();
e2k_gen_mask_i64(t0, len);
tcg_gen_shl_i64(t1, t0, offset);
tcg_gen_not_i64(t2, t1);
tcg_gen_and_i64(t3, arg1, t2);
tcg_gen_and_i64(t4, arg2, t0);
tcg_gen_shl_i64(t5, t4, offset);
tcg_gen_or_i64(ret, t3, t5);
tcg_temp_free_i64(t5);
tcg_temp_free_i64(t4);
tcg_temp_free_i64(t3);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
gen_tr_excp_illopc(ctx)
static inline TCGv_i32 e2k_get_temp_i32(DisasContext *dc)
{
@ -515,14 +490,10 @@ static inline TCGv e2k_get_temp(DisasContext *dc)
return dc->ttl[dc->ttl_len++] = tcg_temp_local_new();
}
static inline void e2k_gen_save_pc(target_ulong pc)
static inline TCGv e2k_get_const(DisasContext *dc, target_ulong value)
{
tcg_gen_movi_tl(e2k_cs.pc, pc);
}
static inline void e2k_gen_save_cpu_state(DisasContext *ctx)
{
e2k_gen_save_pc(ctx->pc);
assert(dc->ttl_len < ARRAY_SIZE(dc->ttl));
return dc->ttl[dc->ttl_len++] = tcg_const_local_tl(value);
}
static inline void e2k_gen_lcntex(TCGv_i32 ret)
@ -576,7 +547,7 @@ static inline void e2k_gen_reg_index(DisasContext *ctx, TCGv_i32 ret, uint8_t ar
} else if (IS_GLOBAL(arg)) {
e2k_gen_reg_index_from_gregi(ret, GET_GLOBAL(arg));
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
gen_tr_exception(ctx, EXCP_ILLEGAL_OPERAND);
}
}

View File

@ -108,7 +108,7 @@ static void gen_mova(DisasContext *ctx, Mova *instr)
e2k_todo_illop(ctx, "movaqp");
break;
default:
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
gen_tr_excp_illopc(ctx);
break;
}

View File

@ -197,7 +197,7 @@ static inline void gen_literal_i64(DisasContext *ctx, Src64 *ret, uint8_t arg)
uint64_t lit = ctx->bundle.lts[i];
if (!ctx->bundle.lts_present[i]) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
gen_tr_excp_illopn(ctx);
} else if (IS_LIT16_LO(arg) && i < 2) {
lit = ((int64_t) lit << 48) >> 48;
} else if (IS_LIT16_HI(arg) && i < 2) {
@ -206,11 +206,11 @@ static inline void gen_literal_i64(DisasContext *ctx, Src64 *ret, uint8_t arg)
lit = ((int64_t) lit << 32) >> 32;
} else if (IS_LIT64(arg) && i < 3) {
if (!ctx->bundle.lts_present[i + 1]) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
gen_tr_excp_illopn(ctx);
}
lit |= (uint64_t) ctx->bundle.lts[i + 1] << 32;
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
gen_tr_excp_illopn(ctx);
}
ret->tag = e2k_get_const_i32(ctx, 0);
@ -223,7 +223,7 @@ static inline void gen_literal_i32(DisasContext *ctx, Src32 *ret, uint8_t arg)
int32_t lit = ctx->bundle.lts[i];
if (!ctx->bundle.lts_present[i]) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
gen_tr_excp_illopn(ctx);
} else if (IS_LIT16_LO(arg) && i < 2) {
lit = (lit << 16) >> 16;
} else if (IS_LIT16_HI(arg) && i < 2) {
@ -233,10 +233,10 @@ static inline void gen_literal_i32(DisasContext *ctx, Src32 *ret, uint8_t arg)
} else if (IS_LIT64(arg) && i < 3) {
// FIXME: check CPU behavior in such situation
if (!ctx->bundle.lts_present[i + 1]) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
gen_tr_excp_illopn(ctx);
}
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
gen_tr_excp_illopn(ctx);
}
ret->tag = e2k_get_const_i32(ctx, 0);
@ -912,7 +912,7 @@ static void gen_sm_i32(bool sm, TCGv_i32 ret, TCGv_i32 ret_tag, Exception excp)
tcg_gen_movi_i32(ret_tag, E2K_TAG_NON_NUMBER32);
tcg_gen_movi_i32(ret, 0);
} else {
e2k_gen_exception(excp);
gen_exception(excp);
}
}
@ -943,7 +943,7 @@ static void gen_brchecki_i32_i64(bool sm, TCGv_i32 ret, TCGv_i32 ret_tag,
TCGv_i64 t0 = tcg_temp_new_i64(); \
TCGv_i64 t1 = tcg_temp_local_new_i64(); \
gen_brchecki_i32(sm, ret, ret_tag, \
TCG_COND_NE, src2, 0, l0, E2K_EXCP_DIV); \
TCG_COND_NE, src2, 0, l0, EXCP_DIV); \
tcg_gen_extu_i32_i64(t0, src2); \
op(t1, src1, t0); \
checks \
@ -955,13 +955,13 @@ static void gen_brchecki_i32_i64(bool sm, TCGv_i32 ret, TCGv_i32 ret_tag,
GEN_OP_DIVX(udivx, tcg_gen_divu_i64, { \
gen_brchecki_i32_i64(sm, ret, ret_tag, \
TCG_COND_LEU, t1, UINT32_MAX, l0, E2K_EXCP_DIV); \
TCG_COND_LEU, t1, UINT32_MAX, l0, EXCP_DIV); \
})
GEN_OP_DIVX(sdivx, tcg_gen_div_i64, { \
gen_brchecki_i32_i64(sm, ret, ret_tag, \
TCG_COND_LE, t1, INT32_MAX, l0, E2K_EXCP_DIV); \
TCG_COND_LE, t1, INT32_MAX, l0, EXCP_DIV); \
gen_brchecki_i32_i64(sm, ret, ret_tag, \
TCG_COND_GE, t1, INT32_MIN, l0, E2K_EXCP_DIV); \
TCG_COND_GE, t1, INT32_MIN, l0, EXCP_DIV); \
})
#define GEN_OP_MODX(name, op) \
@ -971,7 +971,7 @@ GEN_OP_DIVX(sdivx, tcg_gen_div_i64, { \
TCGv_i64 t0 = tcg_temp_new_i64(); \
TCGv_i64 t1 = tcg_temp_new_i64(); \
gen_brchecki_i32(sm, ret, ret_tag, \
TCG_COND_NE, src2, 0, l0, E2K_EXCP_DIV); \
TCG_COND_NE, src2, 0, l0, EXCP_DIV); \
tcg_gen_extu_i32_i64(t0, src2); \
/* FIXME: must gen exception/tag on overflow */ \
op(t1, src1, t0); \
@ -1151,7 +1151,7 @@ static inline void gen_cmpand_i64(TCGv_i64 ret, int opc, TCGv_i64 src1,
tcg_gen_setcondi_i64(TCG_COND_LE, ret, t0, 0);
break;
default:
e2k_gen_exception(E2K_EXCP_ILLOPC);
g_assert_not_reached();
break;
}
@ -1187,7 +1187,7 @@ static inline void gen_cmpand_i32(TCGv_i32 ret, int opc, TCGv_i32 src1,
tcg_gen_setcondi_i32(TCG_COND_LE, ret, t0, 0);
break;
default:
e2k_gen_exception(E2K_EXCP_ILLOPC);
g_assert_not_reached();
break;
}
@ -1244,7 +1244,7 @@ WRAP_FCMP_HELPER(fcmpod)
f = glue4(pre, suf, cmpod, post); \
break; \
default: \
e2k_gen_exception(E2K_EXCP_ILLOPC); \
g_assert_not_reached(); \
break; \
}
@ -1605,7 +1605,7 @@ static inline void gen_rr_i64(Instr *instr)
TCGv_i64 dst = get_temp_i64(instr);
TCGv_i32 t0 = tcg_const_i32(instr->src1);
e2k_gen_save_cpu_state(instr->ctx);
gen_save_cpu_state(instr->ctx);
gen_helper_state_reg_read_i64(dst, cpu_env, t0);
set_al_result_reg64(instr, dst);
tcg_temp_free_i32(t0);
@ -1616,7 +1616,7 @@ static inline void gen_rr_i32(Instr *instr)
TCGv_i32 dst = get_temp_i32(instr);
TCGv_i32 t0 = tcg_const_i32(instr->src1);
e2k_gen_save_cpu_state(instr->ctx);
gen_save_cpu_state(instr->ctx);
gen_helper_state_reg_read_i32(dst, cpu_env, t0);
set_al_result_reg32(instr, dst);
tcg_temp_free_i32(t0);
@ -1696,7 +1696,7 @@ static void gen_movtq_inner(Instr *instr, Src64 src)
if (check_qr(instr->src2, instr->chan) && check_qr(instr->dst, instr->chan)) {
set_al_result_reg64_tag(instr, src.value, src.tag, false);
} else {
e2k_tr_gen_exception(instr->ctx, E2K_EXCP_ILLOPN);
gen_tr_excp_illopn(instr->ctx);
}
}
@ -1712,6 +1712,23 @@ static void gen_movtcq(Instr *instr)
gen_movtq_inner(instr, s2);
}
static void gen_getpl(Instr *instr)
{
#ifdef TARGET_E2K32
Src32 s2 = get_src2_i32(instr);
TCGv_i32 tag = get_temp_i32(instr);
TCGv_i64 dst = get_temp_i64(instr);
// TODO: CUD
gen_tag1_i64(tag, s2.tag);
tcg_gen_extu_i32_i64(dst, s2.value);
set_al_result_reg64_tag(instr, dst, tag, true);
#else /* !TARGET_E2K32 */
// TODO: getpl 64-bit
e2k_todo_illop(instr->ctx, "getpl");
#endif
}
static inline bool gen_ld_mas_mod(DisasContext *ctx, Instr *instr, uint8_t mod)
{
switch (mod) {
@ -1795,84 +1812,122 @@ static MemOp gen_mas(Instr *instr, MemOp memop)
return memop;
}
static void gen_ld(Instr *instr, MemOp memop)
static void gen_ld_tl(Instr *instr, TCGv_i64 ret, TCGv_i32 ret_tag, TCGv addr,
MemOp memop)
{
TCGv_i32 tag = get_temp_i32(instr);
TCGv_i64 dst = get_temp_i64(instr);
memop = gen_mas(instr, memop);
if (memop == 0) {
/* ignore load */
tcg_gen_movi_i32(tag, E2K_TAG_NON_NUMBER64);
tcg_gen_movi_i64(dst, E2K_LD_RESULT_INVALID);
} else {
if (instr->sm) {
TCGLabel *l0 = gen_new_label();
TCGLabel *l1 = gen_new_label();
Src64 s1 = get_src1_i64(instr);
Src64 s2 = get_src2_i64(instr);
TCGv_i64 t0 = tcg_temp_local_new_i64();
TCGv t0 = tcg_temp_local_new();
TCGv_i32 t1 = tcg_temp_new_i32();
gen_tag2_i64(tag, s1.tag, s2.tag);
tcg_gen_add_i64(t0, s1.value, s2.value);
tcg_gen_mov_tl(t0, addr);
gen_helper_probe_read_access(t1, cpu_env, t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 1, l0);
if (instr->sm) {
TCGv_i32 t1 = tcg_temp_new_i32();
gen_helper_probe_read_access(t1, cpu_env, t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 1, l0);
tcg_gen_movi_i32(tag, E2K_TAG_NON_NUMBER64);
tcg_gen_movi_i64(dst, E2K_LD_RESULT_INVALID);
tcg_gen_br(l1);
tcg_temp_free_i32(t1);
}
/* address is not available */
tcg_gen_movi_i32(ret_tag, E2K_TAG_NON_NUMBER64);
tcg_gen_movi_i64(ret, E2K_LD_RESULT_INVALID);
tcg_gen_br(l1);
/* address is available */
gen_set_label(l0);
tcg_gen_qemu_ld_i64(dst, t0, instr->ctx->mmuidx, memop);
tcg_gen_qemu_ld_i64(ret, t0, instr->ctx->mmuidx, memop);
gen_set_label(l1);
tcg_temp_free_i64(t0);
tcg_temp_free_i32(t1);
tcg_temp_free(t0);
} else {
tcg_gen_qemu_ld_i64(ret, addr, instr->ctx->mmuidx, memop);
}
gen_al_result_i64(instr, dst, tag);
}
#define IMPL_ST(NAME, S) \
#define IMPL_GEN_LD(name, S, cast) \
static void name(Instr *instr, TCGv_i64 ret, TCGv_i32 ret_tag, \
MemOp memop) \
{ \
glue(Src, S) s1 = glue(get_src1_i, S)(instr); \
glue(Src, S) s2 = glue(get_src2_i, S)(instr); \
glue(TCGv_i, S) t0 = glue(tcg_temp_new_i, S)(); \
TCGv t1 = tcg_temp_local_new(); \
\
glue(gen_tag2_i, S)(ret_tag, s1.tag, s2.tag); \
glue(tcg_gen_add_i, S)(t0, s1.value, s2.value); \
cast(t1, t0); \
gen_ld_tl(instr, ret, ret_tag, t1, memop); \
}
IMPL_GEN_LD(gen_ld_i64, 64, tcg_gen_trunc_i64_tl)
#define IMPL_GEN_LD_MAS(name, load) \
static void name(Instr *instr, MemOp memop) \
{ \
TCGv_i32 tag = get_temp_i32(instr); \
TCGv_i64 dst = get_temp_i64(instr); \
\
memop = gen_mas(instr, memop); \
\
if (memop == 0) { \
/* ignore load */ \
tcg_gen_movi_i32(tag, E2K_TAG_NON_NUMBER64); \
tcg_gen_movi_i64(dst, E2K_LD_RESULT_INVALID); \
} else { \
load(instr, dst, tag, memop); \
} \
\
gen_al_result_i64(instr, dst, tag); \
}
IMPL_GEN_LD_MAS(gen_ld_mas_i64, gen_ld_i64)
#ifdef TARGET_E2K32
// TODO: ldgd ops must use GD.base
IMPL_GEN_LD(gen_ld_i32, 32, tcg_gen_extu_i32_tl)
IMPL_GEN_LD_MAS(gen_ld_mas_i32, gen_ld_i32)
#endif
#define IMPL_ST(NAME, S, N, cast) \
static void NAME(Instr *instr, MemOp memop) \
{ \
memop = gen_mas(instr, memop); \
\
if (memop != 0) { \
TCGLabel *l0 = gen_new_label(); \
Src64 s1 = get_src1_i64(instr); \
Src64 s2 = get_src2_i64(instr); \
glue(Src, N) s1 = glue(get_src1_i, N)(instr); \
glue(Src, N) s2 = glue(get_src2_i, N)(instr); \
glue(Src, S) s4 = glue(get_src4_i, S)(instr); \
TCGv_i64 t0 = tcg_temp_local_new_i64(); \
glue(TCGv_i, N) t0 = glue(tcg_temp_new_i, N)(); \
TCGv t1 = tcg_temp_local_new(); \
\
gen_loop_mode_st(instr->ctx, l0); \
gen_tag_check(instr, s1.tag); \
gen_tag_check(instr, s2.tag); \
gen_tag_check(instr, s4.tag); \
tcg_gen_add_i64(t0, s1.value, s2.value); \
glue(tcg_gen_add_i, N)(t0, s1.value, s2.value); \
cast(t1, t0); \
\
if (instr->sm) { \
TCGv_i32 t1 = tcg_temp_new_i32(); \
gen_helper_probe_write_access(t1, cpu_env, t0); \
tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 0, l0); \
tcg_temp_free_i32(t1); \
TCGv_i32 t2 = tcg_temp_new_i32(); \
gen_helper_probe_write_access(t2, cpu_env, t1); \
tcg_gen_brcondi_i32(TCG_COND_EQ, t2, 0, l0); \
tcg_temp_free_i32(t2); \
} \
\
glue(tcg_gen_qemu_st_i, S)(s4.value, t0, instr->ctx->mmuidx, memop); \
glue(tcg_gen_qemu_st_i, S)(s4.value, t1, instr->ctx->mmuidx, memop); \
gen_set_label(l0); \
\
tcg_temp_free_i64(t0); \
tcg_temp_free(t1); \
glue(tcg_temp_free_i, N)(t0); \
} \
}
IMPL_ST(gen_st_ddd, 64)
IMPL_ST(gen_st_dds, 32)
IMPL_ST(gen_st_ddd, 64, 64, tcg_gen_trunc_i64_tl)
IMPL_ST(gen_st_sdd, 32, 64, tcg_gen_trunc_i64_tl)
// TODO: stgd ops must use GD.base
IMPL_ST(gen_st_dss, 64, 32, tcg_gen_extu_i32_tl)
IMPL_ST(gen_st_sss, 32, 32, tcg_gen_extu_i32_tl)
static inline void gen_movfi(Instr *instr)
{
@ -2268,7 +2323,7 @@ static void gen_aad_ptr(DisasContext *ctx, TCGv ret, Instr *instr)
if (ctx->bundle.lts_present[lts]) {
lit = ctx->bundle.lts[lts];
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
gen_tr_excp_illopn(ctx);
return;
}
}
@ -2318,8 +2373,7 @@ static void gen_staa_i64(Instr *instr)
TCGv t0 = tcg_temp_local_new();
if (mas != 0) {
qemu_log_mask(LOG_UNIMP,
"0x%lx: staad mas=%#x is not implemented\n", ctx->pc, mas);
e2k_todo(ctx, "staad mas=%#x is not implemented", mas);
}
gen_aad_ptr(ctx, t0, instr);
@ -3197,8 +3251,6 @@ static void check_args(Alopf alopf, Instr *instr)
check_reg_src(ctx, instr->src4);
break;
case ALOPF13:
// FIXME: not tested
e2k_todo(ctx, "check_args ALOPF13");
check_reg_src(ctx, instr->src1);
check_reg_src(ctx, instr->src2);
check_reg_src(ctx, instr->src4);
@ -3340,14 +3392,32 @@ static void gen_alop_simple(Instr *instr, uint32_t op, const char *name)
case OP_FXCMPODXB:
gen_alopf1_cmp_xx(instr);
break;
case OP_STB: gen_st_dds(instr, MO_UB); break;
case OP_STH: gen_st_dds(instr, MO_UW); break;
case OP_STW: gen_st_dds(instr, MO_UL); break;
case OP_STB: gen_st_sdd(instr, MO_UB); break;
case OP_STH: gen_st_sdd(instr, MO_UW); break;
case OP_STW: gen_st_sdd(instr, MO_UL); break;
case OP_STD: gen_st_ddd(instr, MO_Q); break;
case OP_LDB: gen_ld(instr, MO_UB); break;
case OP_LDH: gen_ld(instr, MO_UW); break;
case OP_LDW: gen_ld(instr, MO_UL); break;
case OP_LDD: gen_ld(instr, MO_Q); break;
case OP_STGDB: gen_st_sss(instr, MO_UB); break;
case OP_STGDH: gen_st_sss(instr, MO_UW); break;
case OP_STGDW: gen_st_sss(instr, MO_UL); break;
case OP_STGDD: gen_st_dss(instr, MO_Q); break;
case OP_STGDQ: e2k_todo_illop(instr->ctx, "stgdq"); break;
case OP_LDB: gen_ld_mas_i64(instr, MO_UB); break;
case OP_LDH: gen_ld_mas_i64(instr, MO_UW); break;
case OP_LDW: gen_ld_mas_i64(instr, MO_UL); break;
case OP_LDD: gen_ld_mas_i64(instr, MO_Q); break;
#ifdef TARGET_E2K32
case OP_LDGDB: gen_ld_mas_i32(instr, MO_UB); break;
case OP_LDGDH: gen_ld_mas_i32(instr, MO_UW); break;
case OP_LDGDW: gen_ld_mas_i32(instr, MO_UL); break;
case OP_LDGDD: gen_ld_mas_i32(instr, MO_Q); break;
case OP_LDGDQ: e2k_todo_illop(instr->ctx, "ldgdq"); break;
#else /* !TARGET_E2K32 */
case OP_LDGDB: /* fallthrough */
case OP_LDGDH: /* fallthrough */
case OP_LDGDW: /* fallthrough */
case OP_LDGDD: /* fallthrough */
case OP_LDGDQ: gen_tr_excp_array_bounds(instr->ctx); break;
#endif
case OP_BITREVS: gen_alopf2_ss(instr, gen_bitrevs); break;
case OP_BITREVD: gen_alopf2_dd(instr, gen_bitrevd); break;
case OP_LZCNTS: gen_alopf2_ss(instr, gen_lzcnts); break;
@ -3404,14 +3474,7 @@ static void gen_alop_simple(Instr *instr, uint32_t op, const char *name)
case OP_FXTOIDTR: gen_alopf2_xd(instr, gen_fxtoidtr); break;
case OP_ISTOFX: gen_alopf2_sx(instr, gen_istofx); break;
case OP_IDTOFX: gen_alopf2_dx(instr, gen_idtofx); break;
case OP_UDIVS:
if (instr->src2 == 0xc0) {
// FIXME: temp hack
e2k_tr_gen_exception_no_spill(ctx, 0);
return;
}
gen_alopf1_sttss(instr, gen_udivs);
break;
case OP_UDIVS: gen_alopf1_sttss(instr, gen_udivs); break;
case OP_UDIVD: gen_alopf1_dttdd(instr, gen_udivd); break;
case OP_SDIVS: gen_alopf1_sttss(instr, gen_sdivs); break;
case OP_SDIVD: gen_alopf1_dttdd(instr, gen_sdivd); break;
@ -3458,6 +3521,7 @@ static void gen_alop_simple(Instr *instr, uint32_t op, const char *name)
case OP_MOVTCD: gen_movtcd(instr); break;
case OP_MOVTQ: gen_movtq(instr); break;
case OP_MOVTCQ: gen_movtcq(instr); break;
case OP_GETPL: gen_getpl(instr); break;
case OP_PANDD: gen_alopf1_ddd(instr, tcg_gen_and_i64); break;
case OP_PANDND: gen_alopf1_ddd(instr, gen_andn_i64); break;
case OP_PORD: gen_alopf1_ddd(instr, tcg_gen_or_i64); break;
@ -3562,7 +3626,7 @@ static void gen_alop_simple(Instr *instr, uint32_t op, const char *name)
extract32(ctx->bundle.als[pair_chan], 24, 7) != 0x3f ||
(instr->dst & 1) != (chan == 2 ? 0 : 1))
{
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
gen_tr_excp_illopc(ctx);
return;
}
gen_staa_i64(instr);
@ -3698,7 +3762,6 @@ static void gen_alop_simple(Instr *instr, uint32_t op, const char *name)
case OP_MOVTRCS:
case OP_MOVTRD:
case OP_MOVTRCD:
case OP_GETPL:
case OP_GETSAP:
case OP_CUDTOAP:
case OP_GDTOAP:
@ -3751,11 +3814,6 @@ static void gen_alop_simple(Instr *instr, uint32_t op, const char *name)
case OP_CAST:
case OP_TDTOMP:
case OP_ODTOAP:
case OP_LDGDB:
case OP_LDGDH:
case OP_LDGDW:
case OP_LDGDD:
case OP_LDGDQ:
case OP_LDCUDB:
case OP_LDCUDH:
case OP_LDCUDW:
@ -3798,11 +3856,6 @@ static void gen_alop_simple(Instr *instr, uint32_t op, const char *name)
case OP_STGSQ:
case OP_STSSQ:
case OP_STRD:
case OP_STGDB:
case OP_STGDH:
case OP_STGDW:
case OP_STGDD:
case OP_STGDQ:
case OP_STAPB:
case OP_STAPH:
case OP_STAPW:
@ -4256,7 +4309,7 @@ static inline bool pfcomb_check(Instr *instr, FComb opc1, FComb opc2)
case FCOMB_SUB: glue(gen_helper_fsub, T)(ret, cpu_env, arg1, arg2); break; \
case FCOMB_MUL: glue(gen_helper_fmul, T)(ret, cpu_env, arg1, arg2); break; \
case FCOMB_RSUB: glue(gen_helper_fsub, T)(ret, cpu_env, arg2, arg1); break; \
default: e2k_tr_gen_exception(instr->ctx, E2K_EXCP_ILLOPC); break; \
default: gen_tr_excp_illopc(instr->ctx); break; \
} \
}
@ -4274,7 +4327,7 @@ static void gen_pfcomb_op_i32(Instr *instr, FComb opc,
case FCOMB_MUL: gen_helper_pfmuls(ret, cpu_env, arg1, arg2); break;
case FCOMB_RSUB: gen_helper_pfsubs(ret, cpu_env, arg2, arg1); break;
case FCOMB_ADDSUB: gen_helper_pfaddsubs(ret, cpu_env, arg1, arg2); break;
default: e2k_tr_gen_exception(instr->ctx, E2K_EXCP_ILLOPC); break;
default: gen_tr_excp_illopc(instr->ctx); break;
}
}
@ -4286,7 +4339,7 @@ static void gen_pfcomb_op_i64(Instr *instr, FComb opc,
case FCOMB_SUB: gen_helper_fsubd(ret, cpu_env, arg1, arg2); break;
case FCOMB_MUL: gen_helper_fmuld(ret, cpu_env, arg1, arg2); break;
case FCOMB_RSUB: gen_helper_fsubd(ret, cpu_env, arg2, arg1); break;
default: e2k_tr_gen_exception(instr->ctx, E2K_EXCP_ILLOPC); break;
default: gen_tr_excp_illopc(instr->ctx); break;
}
}
@ -4421,7 +4474,7 @@ static void chan_check_preds(DisasContext *ctx, int chan, TCGLabel *l)
break;
default:
if (ctx->strict) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
gen_tr_excp_illopc(ctx);
}
break;
}
@ -4475,7 +4528,7 @@ static void alop_decode(Instr *instr)
case EXT2: {
AlopDesc *desc = find_op(instr);
if (!desc) {
e2k_tr_gen_exception(instr->ctx, E2K_EXCP_ILLOPC);
gen_tr_excp_illopc(instr->ctx);
return;
}
alop->format = desc->alopf;
@ -4491,7 +4544,7 @@ static void alop_decode(Instr *instr)
&& (instr->opc1 == 0x6c || instr->opc1 == 0x6d))
{
if (!is_chan_0134(instr->chan)) {
e2k_tr_gen_exception(instr->ctx, E2K_EXCP_ILLOPC);
gen_tr_excp_illopc(instr->ctx);
return;
}
alop->format = ALOPF21;
@ -4500,7 +4553,7 @@ static void alop_decode(Instr *instr)
int opc1 = icomb_opc1(instr);
int opc2 = icomb_opc2(instr);
if (!icomb_check(instr, opc1, opc2)) {
e2k_tr_gen_exception(instr->ctx, E2K_EXCP_ILLOPC);
gen_tr_excp_illopc(instr->ctx);
return;
}
alop->format = ALOPF21_ICOMB;
@ -4518,7 +4571,7 @@ static void alop_decode(Instr *instr)
int opc1 = fcomb_opc1(instr);
int opc2 = fcomb_opc2(instr);
if (!fcomb_check(instr, opc1, opc2)) {
e2k_tr_gen_exception(instr->ctx, E2K_EXCP_ILLOPC);
gen_tr_excp_illopc(instr->ctx);
return;
}
alop->format = ALOPF21_FCOMB;
@ -4541,7 +4594,7 @@ static void alop_decode(Instr *instr)
int opc1 = fcomb_opc1(instr);
int opc2 = fcomb_opc2(instr);
if (!pfcomb_check(instr, opc1, opc2)) {
e2k_tr_gen_exception(instr->ctx, E2K_EXCP_ILLOPC);
gen_tr_excp_illopc(instr->ctx);
return;
}
alop->format = ALOPF21_PFCOMB;
@ -4554,7 +4607,7 @@ static void alop_decode(Instr *instr)
alop->format = ALOPF21_LCOMB;
alop->op = instr->opc2 == LCMBD0 ? 0 : 0x80;
} else {
e2k_tr_gen_exception(instr->ctx, E2K_EXCP_ILLOPC);
gen_tr_excp_illopc(instr->ctx);
}
break;
case LCMBQ0:
@ -4566,7 +4619,7 @@ static void alop_decode(Instr *instr)
e2k_todo_illop(instr->ctx, "packed128 float combined ops");
break;
default:
e2k_tr_gen_exception(instr->ctx, E2K_EXCP_ILLOPC);
gen_tr_excp_illopc(instr->ctx);
break;
}
}

View File

@ -21,7 +21,7 @@ void e2k_gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc)
// %rndpred
e2k_todo_illop(ctx, "%%rndpred");
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
gen_tr_excp_illopn(ctx);
}
} else {
int idx = extract8(psrc, 0, 5);