diff --git a/linux-user/e2k/cpu_loop.c b/linux-user/e2k/cpu_loop.c index 7f1c8df12e..e88935ab47 100644 --- a/linux-user/e2k/cpu_loop.c +++ b/linux-user/e2k/cpu_loop.c @@ -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; diff --git a/linux-user/e2k/signal.c b/linux-user/e2k/signal.c index 2218f20126..63d2cefff4 100644 --- a/linux-user/e2k/signal.c +++ b/linux-user/e2k/signal.c @@ -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; } diff --git a/linux-user/e2k/target_syscall.h b/linux-user/e2k/target_syscall.h index f0d5e15229..f1721e5cc7 100644 --- a/linux-user/e2k/target_syscall.h +++ b/linux-user/e2k/target_syscall.h @@ -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 { diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 5ee5aef9c7..7072d1160e 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -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; diff --git a/target/e2k/cpu-param.h b/target/e2k/cpu-param.h index 3ee11a8b99..8ba96f6e0e 100644 --- a/target/e2k/cpu-param.h +++ b/target/e2k/cpu-param.h @@ -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 diff --git a/target/e2k/cpu.c b/target/e2k/cpu.c index b413b01ffc..a5a000a2db 100644 --- a/target/e2k/cpu.c +++ b/target/e2k/cpu.c @@ -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)); diff --git a/target/e2k/cpu.h b/target/e2k/cpu.h index 8c76ea2764..e8ae05dc8b 100644 --- a/target/e2k/cpu.h +++ b/target/e2k/cpu.h @@ -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; diff --git a/target/e2k/helper.c b/target/e2k/helper.c index d4cb6b100d..5c163f06d7 100644 --- a/target/e2k/helper.c +++ b/target/e2k/helper.c @@ -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); -} diff --git a/target/e2k/helper.h b/target/e2k/helper.h index a002c0a774..b1fd6edc2b 100644 --- a/target/e2k/helper.h +++ b/target/e2k/helper.h @@ -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) diff --git a/target/e2k/helper_aau.c b/target/e2k/helper_aau.c index b9b0059fb1..e3a3f653a3 100644 --- a/target/e2k/helper_aau.c +++ b/target/e2k/helper_aau.c @@ -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++) { diff --git a/target/e2k/translate.c b/target/e2k/translate.c index 2a076f05a9..1bf5c8dc7e 100644 --- a/target/e2k/translate.c +++ b/target/e2k/translate.c @@ -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); diff --git a/target/e2k/translate.h b/target/e2k/translate.h index 79a9d60dfe..6e2033f0cc 100644 --- a/target/e2k/translate.h +++ b/target/e2k/translate.h @@ -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); } } diff --git a/target/e2k/translate/aau.c b/target/e2k/translate/aau.c index a1f7bdc34a..874186518b 100644 --- a/target/e2k/translate/aau.c +++ b/target/e2k/translate/aau.c @@ -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; } diff --git a/target/e2k/translate/alc.c b/target/e2k/translate/alc.c index 3b85ab7d03..9c6b73afcf 100644 --- a/target/e2k/translate/alc.c +++ b/target/e2k/translate/alc.c @@ -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; } } diff --git a/target/e2k/translate/plu.c b/target/e2k/translate/plu.c index ef39a3b459..9498f4858c 100644 --- a/target/e2k/translate/plu.c +++ b/target/e2k/translate/plu.c @@ -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);