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:
parent
7198f44549
commit
e440ebc3db
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue