Message ID | 1255696735-21396-3-git-send-email-uli@suse.de |
---|---|
State | New |
Headers | show |
On Fri, Oct 16, 2009 at 02:38:48PM +0200, Ulrich Hecht wrote: > Currently only does userspace with 64-bit addressing, but it's quite good > at that. > > replaced always_inline with inline > > Signed-off-by: Ulrich Hecht <uli@suse.de> > --- > cpu-exec.c | 2 + > disas.c | 3 + > s390-dis.c | 4 +- > target-s390x/cpu.h | 132 +++ > target-s390x/exec.h | 51 + > target-s390x/helper.c | 81 ++ > target-s390x/helpers.h | 128 +++ > target-s390x/op_helper.c | 1719 ++++++++++++++++++++++++++++++++ > target-s390x/translate.c | 2479 ++++++++++++++++++++++++++++++++++++++++++++++ > 9 files changed, 4597 insertions(+), 2 deletions(-) > create mode 100644 target-s390x/cpu.h > create mode 100644 target-s390x/exec.h > create mode 100644 target-s390x/helper.c > create mode 100644 target-s390x/helpers.h > create mode 100644 target-s390x/op_helper.c > create mode 100644 target-s390x/translate.c Thanks for this nice patch. s390 is one if the missing major targets with ia64. First of all a few general comments. Note that I know very few things about S390/S390X, so I may have dumb comments/questions. Also as the patch is very long, I probably have missed things, we should probably iterate with new versions of the patches. Is it possible given the current implementation to emulate S390 in addition to S390X? If yes how different would be a S390 only target? If they won't be too different, it probably worth using _tl type registers and call it target-s390. A bit the way it is done with i386/x86_64, ppc/ppc64, mips/mips64 or sparc/sparc64. Secondly there seems to be a lot of mix between 32-bit and 64-bit TCG registers. They should not be mixed. _i32 ops apply to TCGv_i32 variables, _i64 ops apply to TCGv_i64 variables, and _tl ops to TGCv variables. TCGv/_tl types can map either to _i32 or _i64 depending on your target. You should try to build the target with --enable-debug-tcg Otherwise please find my comments inline. > diff --git a/cpu-exec.c b/cpu-exec.c > index 8aa92c7..6b3391c 100644 > --- a/cpu-exec.c > +++ b/cpu-exec.c > @@ -249,6 +249,7 @@ int cpu_exec(CPUState *env1) > #elif defined(TARGET_MIPS) > #elif defined(TARGET_SH4) > #elif defined(TARGET_CRIS) > +#elif defined(TARGET_S390X) > /* XXXXX */ > #else > #error unsupported target CPU > @@ -673,6 +674,7 @@ int cpu_exec(CPUState *env1) > #elif defined(TARGET_SH4) > #elif defined(TARGET_ALPHA) > #elif defined(TARGET_CRIS) > +#elif defined(TARGET_S390X) > /* XXXXX */ > #else > #error unsupported target CPU > diff --git a/disas.c b/disas.c > index ce342bc..14c8901 100644 > --- a/disas.c > +++ b/disas.c > @@ -195,6 +195,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) > #elif defined(TARGET_CRIS) > disasm_info.mach = bfd_mach_cris_v32; > print_insn = print_insn_crisv32; > +#elif defined(TARGET_S390X) > + disasm_info.mach = bfd_mach_s390_64; > + print_insn = print_insn_s390; > #elif defined(TARGET_MICROBLAZE) > disasm_info.mach = bfd_arch_microblaze; > print_insn = print_insn_microblaze; It would be nice to split all the disassembling part in a separate combined with the related makefile changes. This way it can be applied separately. > diff --git a/s390-dis.c b/s390-dis.c > index 86dd84f..9a73a57 100644 > --- a/s390-dis.c > +++ b/s390-dis.c > @@ -191,10 +191,10 @@ init_disasm (struct disassemble_info *info) > // switch (info->mach) > // { > // case bfd_mach_s390_31: > - current_arch_mask = 1 << S390_OPCODE_ESA; > +// current_arch_mask = 1 << S390_OPCODE_ESA; > // break; > // case bfd_mach_s390_64: > -// current_arch_mask = 1 << S390_OPCODE_ZARCH; > + current_arch_mask = 1 << S390_OPCODE_ZARCH; > // break; > // default: > // abort (); While I understand the second part, Why is it necessary to comment the bfd_mach_s390_31 case? > diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h > new file mode 100644 > index 0000000..93b09cd > --- /dev/null > +++ b/target-s390x/cpu.h > @@ -0,0 +1,132 @@ > +/* > + * S/390 virtual CPU header > + * > + * Copyright (c) 2009 Ulrich Hecht > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA > + */ > +#ifndef CPU_S390X_H > +#define CPU_S390X_H > + > +#define TARGET_LONG_BITS 64 > + > +#define ELF_MACHINE EM_S390 > + > +#define CPUState struct CPUS390XState > + > +#include "cpu-defs.h" > + > +#include "softfloat.h" > + > +#define NB_MMU_MODES 2 // guess > +#define MMU_USER_IDX 0 // guess > + > +typedef union FPReg { > + struct { > +#ifdef WORDS_BIGENDIAN > + float32 e; > + int32_t __pad; > +#else > + int32_t __pad; > + float32 e; > +#endif > + }; > + float64 d; > + uint64_t i; > +} FPReg; WORDS_BIGENDIAN is wrong here. It should probably be HOST_WORDS_BIGENDIAN. Also it may be a better idea to reuse CPU_FloatU and CPU_DoubleU here. > +typedef struct CPUS390XState { > + uint64_t regs[16]; /* GP registers */ > + > + uint32_t aregs[16]; /* access registers */ > + > + uint32_t fpc; /* floating-point control register */ > + FPReg fregs[16]; /* FP registers */ > + float_status fpu_status; /* passed to softfloat lib */ > + > + struct { > + uint64_t mask; > + uint64_t addr; > + } psw; > + > + int cc; /* condition code (0-3) */ > + > + uint64_t __excp_addr; > + > + CPU_COMMON > +} CPUS390XState; > + > +#if defined(CONFIG_USER_ONLY) > +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) > +{ > + if (newsp) > + env->regs[15] = newsp; > + env->regs[0] = 0; > +} > +#endif > + > +CPUS390XState *cpu_s390x_init(const char *cpu_model); > +void s390x_translate_init(void); > +int cpu_s390x_exec(CPUS390XState *s); > +void cpu_s390x_close(CPUS390XState *s); > +void do_interrupt (CPUState *env); > + > +/* you can call this signal handler from your SIGBUS and SIGSEGV > + signal handlers to inform the virtual CPU of exceptions. non zero > + is returned if the signal was handled by the virtual CPU. */ > +int cpu_s390x_signal_handler(int host_signum, void *pinfo, > + void *puc); > +int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw, > + int mmu_idx, int is_softmuu); > +#define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault > + > +void cpu_lock(void); > +void cpu_unlock(void); > + > +static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) > +{ > + env->aregs[0] = newtls >> 32; > + env->aregs[1] = newtls & 0xffffffffULL; > +} > + > +#define TARGET_PAGE_BITS 12 // guess > + > +#define cpu_init cpu_s390x_init > +#define cpu_exec cpu_s390x_exec > +#define cpu_gen_code cpu_s390x_gen_code > +#define cpu_signal_handler cpu_s390x_signal_handler > +//#define cpu_list s390x_cpu_list > + > +#include "cpu-all.h" > +#include "exec-all.h" > + > +#define EXCP_OPEX 1 /* operation exception (sigill) */ > +#define EXCP_SVC 2 /* supervisor call (syscall) */ > +#define EXCP_ADDR 5 /* addressing exception */ > +#define EXCP_EXECUTE_SVC 0xff00000 /* supervisor call via execute insn */ > + > +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb) > +{ > + env->psw.addr = tb->pc; > +} > + > +static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc, > + target_ulong *cs_base, int *flags) > +{ > + *pc = env->psw.addr; > + *cs_base = 0; > + *flags = env->psw.mask; // guess > +} > +#endif > diff --git a/target-s390x/exec.h b/target-s390x/exec.h > new file mode 100644 > index 0000000..5198359 > --- /dev/null > +++ b/target-s390x/exec.h > @@ -0,0 +1,51 @@ > +/* > + * S/390 execution defines > + * > + * Copyright (c) 2009 Ulrich Hecht > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA > + */ > + > +#include "dyngen-exec.h" > + > +register struct CPUS390XState *env asm(AREG0); > + > +#include "cpu.h" > +#include "exec-all.h" > + > +static inline int cpu_has_work(CPUState *env) > +{ > + return env->interrupt_request & CPU_INTERRUPT_HARD; // guess > +} > + > +static inline void regs_to_env(void) > +{ > +} > + > +static inline void env_to_regs(void) > +{ > +} > + > +static inline int cpu_halted(CPUState *env) > +{ > + if (!env->halted) { > + return 0; > + } > + if (cpu_has_work(env)) { > + env->halted = 0; > + return 0; > + } > + return EXCP_HALTED; > +} > diff --git a/target-s390x/helper.c b/target-s390x/helper.c > new file mode 100644 > index 0000000..5407c62 > --- /dev/null > +++ b/target-s390x/helper.c > @@ -0,0 +1,81 @@ > +/* > + * S/390 helpers > + * > + * Copyright (c) 2009 Ulrich Hecht > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA > + */ > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > + > +#include "cpu.h" > +#include "exec-all.h" > +#include "gdbstub.h" > +#include "qemu-common.h" > + > +CPUS390XState *cpu_s390x_init(const char *cpu_model) > +{ > + CPUS390XState *env; > + static int inited = 0; > + > + env = qemu_mallocz(sizeof(CPUS390XState)); > + cpu_exec_init(env); > + if (!inited) { > + inited = 1; > + s390x_translate_init(); > + } > + > + env->cpu_model_str = cpu_model; > + cpu_reset(env); > + qemu_init_vcpu(env); > + return env; > +} This function would probably be better in translate.c, so that s390x_translate_init() can be declared static. > +#if defined(CONFIG_USER_ONLY) > + > +void do_interrupt (CPUState *env) > +{ > + env->exception_index = -1; > +} > + > +int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong address, int rw, > + int mmu_idx, int is_softmmu) > +{ > + //fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d is_softmmu %d\n", __FUNCTION__, address, rw, mmu_idx, is_softmmu); Please use /* */ for comments (See CODING_STYLE). > + env->exception_index = EXCP_ADDR; > + env->__excp_addr = address; /* FIXME: find out how this works on a real machine */ > + return 1; > +} > + > +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) > +{ > + return addr; > +} > + > +#endif /* CONFIG_USER_ONLY */ > + > +void cpu_reset(CPUS390XState *env) > +{ > + if (qemu_loglevel_mask(CPU_LOG_RESET)) { > + qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); > + log_cpu_state(env, 0); > + } > + > + memset(env, 0, offsetof(CPUS390XState, breakpoints)); > + /* FIXME: reset vector? */ > + tlb_flush(env, 1); > +} Yes, reset vector, MMU mode, default register values, ... > diff --git a/target-s390x/helpers.h b/target-s390x/helpers.h > new file mode 100644 > index 0000000..0ba2086 > --- /dev/null > +++ b/target-s390x/helpers.h > @@ -0,0 +1,128 @@ > +#include "def-helper.h" > + > +DEF_HELPER_1(exception, void, i32) > +DEF_HELPER_4(nc, i32, i32, i32, i32, i32) > +DEF_HELPER_4(oc, i32, i32, i32, i32, i32) > +DEF_HELPER_4(xc, i32, i32, i32, i32, i32) > +DEF_HELPER_4(mvc, void, i32, i32, i32, i32) > +DEF_HELPER_4(clc, i32, i32, i32, i32, i32) > +DEF_HELPER_4(lmg, void, i32, i32, i32, s32) > +DEF_HELPER_4(stmg, void, i32, i32, i32, s32) > +DEF_HELPER_FLAGS_1(set_cc_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) > +DEF_HELPER_FLAGS_1(set_cc_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64) > +DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) > +DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64) > +DEF_HELPER_FLAGS_1(set_cc_nz_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32) > +DEF_HELPER_FLAGS_1(set_cc_nz_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64) > +DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) > +DEF_HELPER_4(brc, void, i32, i32, i64, s32) > +DEF_HELPER_3(brctg, void, i64, i64, s32) > +DEF_HELPER_3(brct, void, i32, i64, s32) > +DEF_HELPER_4(brcl, void, i32, i32, i64, s64) > +DEF_HELPER_4(bcr, void, i32, i32, i64, i64) > +DEF_HELPER_4(bc, void, i32, i32, i64, i64) > +DEF_HELPER_FLAGS_2(cmp_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64) > +DEF_HELPER_FLAGS_2(cmp_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) > +DEF_HELPER_FLAGS_2(cmp_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32) > +DEF_HELPER_FLAGS_2(cmp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64) > +DEF_HELPER_3(clm, i32, i32, i32, i64) > +DEF_HELPER_3(stcm, void, i32, i32, i64) > +DEF_HELPER_2(mlg, void, i32, i64) > +DEF_HELPER_2(dlg, void, i32, i64) > +DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) > +DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) > +DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) > +DEF_HELPER_FLAGS_3(set_cc_addu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) > +DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) > +DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) > +DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) > +DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) > +DEF_HELPER_3(srst, i32, i32, i32, i32) > +DEF_HELPER_3(clst, i32, i32, i32, i32) > +DEF_HELPER_3(mvst, i32, i32, i32, i32) > +DEF_HELPER_3(csg, i32, i32, i64, i32) > +DEF_HELPER_3(cdsg, i32, i32, i64, i32) > +DEF_HELPER_3(cs, i32, i32, i64, i32) > +DEF_HELPER_4(ex, i32, i32, i64, i64, i64) > +DEF_HELPER_FLAGS_2(tm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) > +DEF_HELPER_FLAGS_2(tmxx, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i32) > +DEF_HELPER_2(abs_i32, i32, i32, s32) > +DEF_HELPER_2(nabs_i32, i32, i32, s32) > +DEF_HELPER_2(abs_i64, i32, i32, s64) > +DEF_HELPER_2(nabs_i64, i32, i32, s64) > +DEF_HELPER_3(stcmh, i32, i32, i64, i32) > +DEF_HELPER_3(icmh, i32, i32, i64, i32) > +DEF_HELPER_2(ipm, void, i32, i32) > +DEF_HELPER_3(addc_u32, i32, i32, i32, i32) > +DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) > +DEF_HELPER_3(stam, void, i32, i64, i32) > +DEF_HELPER_3(mvcle, i32, i32, i64, i32) > +DEF_HELPER_3(clcle, i32, i32, i64, i32) > +DEF_HELPER_4(slb, i32, i32, i32, i32, i32) > +DEF_HELPER_4(slbg, i32, i32, i32, i64, i64) > +DEF_HELPER_2(cefbr, void, i32, s32) > +DEF_HELPER_2(cdfbr, void, i32, s32) > +DEF_HELPER_2(cxfbr, void, i32, s32) > +DEF_HELPER_2(cegbr, void, i32, s64) > +DEF_HELPER_2(cdgbr, void, i32, s64) > +DEF_HELPER_2(cxgbr, void, i32, s64) > +DEF_HELPER_2(adbr, i32, i32, i32) > +DEF_HELPER_2(aebr, i32, i32, i32) > +DEF_HELPER_2(sebr, i32, i32, i32) > +DEF_HELPER_2(sdbr, i32, i32, i32) > +DEF_HELPER_2(debr, void, i32, i32) > +DEF_HELPER_2(dxbr, void, i32, i32) > +DEF_HELPER_2(mdbr, void, i32, i32) > +DEF_HELPER_2(mxbr, void, i32, i32) > +DEF_HELPER_2(ldebr, void, i32, i32) > +DEF_HELPER_2(ldxbr, void, i32, i32) > +DEF_HELPER_2(lxdbr, void, i32, i32) > +DEF_HELPER_2(ledbr, void, i32, i32) > +DEF_HELPER_2(lexbr, void, i32, i32) > +DEF_HELPER_2(lpebr, i32, i32, i32) > +DEF_HELPER_2(lpdbr, i32, i32, i32) > +DEF_HELPER_2(lpxbr, i32, i32, i32) > +DEF_HELPER_2(ltebr, i32, i32, i32) > +DEF_HELPER_2(ltdbr, i32, i32, i32) > +DEF_HELPER_2(ltxbr, i32, i32, i32) > +DEF_HELPER_2(lcebr, i32, i32, i32) > +DEF_HELPER_2(lcdbr, i32, i32, i32) > +DEF_HELPER_2(lcxbr, i32, i32, i32) > +DEF_HELPER_2(ceb, i32, i32, i64) > +DEF_HELPER_2(aeb, i32, i32, i64) > +DEF_HELPER_2(deb, void, i32, i64) > +DEF_HELPER_2(meeb, void, i32, i64) > +DEF_HELPER_2(cdb, i32, i32, i64) > +DEF_HELPER_2(adb, i32, i32, i64) > +DEF_HELPER_2(seb, i32, i32, i64) > +DEF_HELPER_2(sdb, i32, i32, i64) > +DEF_HELPER_2(mdb, void, i32, i64) > +DEF_HELPER_2(ddb, void, i32, i64) > +DEF_HELPER_FLAGS_2(cebr, TCG_CALL_PURE, i32, i32, i32) > +DEF_HELPER_FLAGS_2(cdbr, TCG_CALL_PURE, i32, i32, i32) > +DEF_HELPER_FLAGS_2(cxbr, TCG_CALL_PURE, i32, i32, i32) > +DEF_HELPER_3(cgebr, i32, i32, i32, i32) > +DEF_HELPER_3(cgdbr, i32, i32, i32, i32) > +DEF_HELPER_3(cgxbr, i32, i32, i32, i32) > +DEF_HELPER_1(lzer, void, i32) > +DEF_HELPER_1(lzdr, void, i32) > +DEF_HELPER_1(lzxr, void, i32) > +DEF_HELPER_3(cfebr, i32, i32, i32, i32) > +DEF_HELPER_3(cfdbr, i32, i32, i32, i32) > +DEF_HELPER_3(cfxbr, i32, i32, i32, i32) > +DEF_HELPER_2(axbr, i32, i32, i32) > +DEF_HELPER_2(sxbr, i32, i32, i32) > +DEF_HELPER_2(meebr, void, i32, i32) > +DEF_HELPER_2(ddbr, void, i32, i32) > +DEF_HELPER_3(madb, void, i32, i64, i32) > +DEF_HELPER_3(maebr, void, i32, i32, i32) > +DEF_HELPER_3(madbr, void, i32, i32, i32) > +DEF_HELPER_3(msdbr, void, i32, i32, i32) > +DEF_HELPER_2(lxdb, void, i32, i64) > +DEF_HELPER_FLAGS_2(tceb, TCG_CALL_PURE, i32, i32, i64) > +DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_PURE, i32, i32, i64) > +DEF_HELPER_FLAGS_2(tcxb, TCG_CALL_PURE, i32, i32, i64) > +DEF_HELPER_2(flogr, i32, i32, i64) > +DEF_HELPER_2(sqdbr, void, i32, i32) > + > +#include "def-helper.h" > diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c > new file mode 100644 > index 0000000..5de4d08 > --- /dev/null > +++ b/target-s390x/op_helper.c > @@ -0,0 +1,1719 @@ > +/* > + * S/390 helper routines > + * > + * Copyright (c) 2009 Ulrich Hecht > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA > + */ > + > +#include "exec.h" > +#include "helpers.h" > +#include <string.h> > + > +//#define DEBUG_HELPER > +#ifdef DEBUG_HELPER > +#define HELPER_LOG(x...) qemu_log(x) > +#else > +#define HELPER_LOG(x...) > +#endif Small comment for the rest of the file. While I understand HELPER_LOG is very handy while developing, I think some calls to it can be dropped in really simple functions. Keeping it in more complex function is not a problem though. > +/* raise an exception */ > +void HELPER(exception)(uint32_t excp) > +{ > + HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp); > + env->exception_index = excp; > + cpu_loop_exit(); > +} > + > +/* and on array */ > +uint32_t HELPER(nc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) > +{ > + uint64_t dest = env->regs[b >> 4] + d1; > + uint64_t src = env->regs[b & 0xf] + d2; > + int i; > + unsigned char x; > + uint32_t cc = 0; > + HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); > + for (i = 0; i <= l; i++) { > + x = ldub(dest + i) & ldub(src + i); > + if (x) cc = 1; coding style > + stb(dest + i, x); > + } > + return cc; > +} > + > +/* xor on array */ > +uint32_t HELPER(xc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) > +{ > + uint64_t dest = env->regs[b >> 4] + d1; > + uint64_t src = env->regs[b & 0xf] + d2; > + int i; > + unsigned char x; > + uint32_t cc = 0; > + HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); > + for (i = 0; i <= l; i++) { > + x = ldub(dest + i) ^ ldub(src + i); > + if (x) cc = 1; coding style > + stb(dest + i, x); > + } > + return cc; > +} > + > +/* or on array */ > +uint32_t HELPER(oc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) > +{ > + uint64_t dest = env->regs[b >> 4] + d1; > + uint64_t src = env->regs[b & 0xf] + d2; > + int i; > + unsigned char x; > + uint32_t cc = 0; > + HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); > + for (i = 0; i <= l; i++) { > + x = ldub(dest + i) | ldub(src + i); > + if (x) cc = 1; coding style > + stb(dest + i, x); > + } > + return cc; > +} > + > +/* memcopy */ > +void HELPER(mvc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) > +{ > + uint64_t dest = env->regs[b >> 4] + d1; > + uint64_t src = env->regs[b & 0xf] + d2; > + int i; > + HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); > + for (i = 0; i <= l; i++) { > + stb(dest + i, ldub(src + i)); > + } > +} > + > +/* compare unsigned byte arrays */ > +uint32_t HELPER(clc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) > +{ > + uint64_t s1 = env->regs[b >> 4] + d1; > + uint64_t s2 = env->regs[b & 0xf] + d2; > + int i; > + unsigned char x,y; > + uint32_t cc; > + HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); > + for (i = 0; i <= l; i++) { > + x = ldub(s1 + i); > + y = ldub(s2 + i); > + HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y); > + if (x < y) { > + cc = 1; > + goto done; > + } > + else if (x > y) { coding style > + cc = 2; > + goto done; > + } > + } > + cc = 0; > +done: > + HELPER_LOG("\n"); > + return cc; > +} > + > +/* load multiple 64-bit registers from memory */ > +void HELPER(lmg)(uint32_t r1, uint32_t r3, uint32_t b2, int d2) > +{ > + uint64_t src = env->regs[b2] + d2; > + for (;;) { > + env->regs[r1] = ldq(src); > + src += 8; > + if (r1 == r3) break; coding style > + r1 = (r1 + 1) & 15; > + } > +} > + > +/* store multiple 64-bit registers to memory */ > +void HELPER(stmg)(uint32_t r1, uint32_t r3, uint32_t b2, int d2) > +{ > + uint64_t dest = env->regs[b2] + d2; > + HELPER_LOG("%s: r1 %d r3 %d\n", __FUNCTION__, r1, r3); > + for (;;) { > + HELPER_LOG("storing r%d in 0x%lx\n", r1, dest); > + stq(dest, env->regs[r1]); > + dest += 8; > + if (r1 == r3) break; coding style > + r1 = (r1 + 1) & 15; > + } > +} > + > +/* set condition code for signed 32-bit arithmetics */ > +uint32_t HELPER(set_cc_s32)(int32_t v) > +{ > + if (v < 0) return 1; > + else if (v > 0) return 2; coding style > + else return 0; > +} > + > +/* set condition code for signed 64-bit arithmetics */ > +uint32_t HELPER(set_cc_s64)(int64_t v) > +{ > + if (v < 0) return 1; > + else if (v > 0) return 2; coding style > + else return 0; > +} > + > +/* set condition code for signed 32-bit two's complement */ > +uint32_t HELPER(set_cc_comp_s32)(int32_t v) > +{ > + if ((uint32_t)v == 0x80000000UL) return 3; > + else if (v < 0) return 1; > + else if (v > 0) return 2; > + else return 0; coding style > +} > + > +/* set condition code for signed 64-bit two's complement */ > +uint32_t HELPER(set_cc_comp_s64)(int64_t v) > +{ > + if ((uint64_t)v == 0x8000000000000000ULL) return 3; > + else if (v < 0) return 1; > + else if (v > 0) return 2; > + else return 0; coding style > +} > + > +/* set negative/zero condition code for 32-bit logical op */ > +uint32_t HELPER(set_cc_nz_u32)(uint32_t v) > +{ > + if (v) return 1; > + else return 0; coding style > +} > + > +/* set negative/zero condition code for 64-bit logical op */ > +uint32_t HELPER(set_cc_nz_u64)(uint64_t v) > +{ > + if (v) return 1; > + else return 0; coding style > +} The last 6 helpers can probably be coded easily in TCG (they are very similar to some PowerPC code), though merging this patch with the helpers is not a problem at all. > +/* set condition code for insert character under mask insn */ > +uint32_t HELPER(set_cc_icm)(uint32_t mask, uint32_t val) > +{ > + HELPER_LOG("%s: mask 0x%x val %d\n", __FUNCTION__, mask, val); > + uint32_t cc; > + if (!val || !mask) cc = 0; > + else { > + while (mask != 1) { > + mask >>= 1; > + val >>= 8; > + } > + if (val & 0x80) cc = 1; > + else cc = 2; > + } > + return cc; coding style > +} > + > +/* relative conditional branch */ > +void HELPER(brc)(uint32_t cc, uint32_t mask, uint64_t pc, int32_t offset) > +{ > + if ( mask & ( 1 << (3 - cc) ) ) { > + env->psw.addr = pc + offset; > + } > + else { > + env->psw.addr = pc + 4; > + } > +} > + > +/* branch relative on 64-bit count (condition is computed inline, this only > + does the branch */ > +void HELPER(brctg)(uint64_t flag, uint64_t pc, int32_t offset) > +{ > + if (flag) { > + env->psw.addr = pc + offset; > + } > + else { > + env->psw.addr = pc + 4; > + } > + HELPER_LOG("%s: pc 0x%lx flag %ld psw.addr 0x%lx\n", __FUNCTION__, pc, flag, > + env->psw.addr); > +} > + > +/* branch relative on 32-bit count (condition is computed inline, this only > + does the branch */ > +void HELPER(brct)(uint32_t flag, uint64_t pc, int32_t offset) > +{ > + if (flag) { > + env->psw.addr = pc + offset; > + } > + else { > + env->psw.addr = pc + 4; > + } > + HELPER_LOG("%s: pc 0x%lx flag %d psw.addr 0x%lx\n", __FUNCTION__, pc, flag, > + env->psw.addr); > +} > + > +/* relative conditional branch with long displacement */ > +void HELPER(brcl)(uint32_t cc, uint32_t mask, uint64_t pc, int64_t offset) > +{ > + if ( mask & ( 1 << (3 - cc) ) ) { > + env->psw.addr = pc + offset; > + } > + else { > + env->psw.addr = pc + 6; > + } > + HELPER_LOG("%s: pc 0x%lx psw.addr 0x%lx\n", __FUNCTION__, pc, env->psw.addr); > +} > + > +/* conditional branch to register (register content is passed as target) */ > +void HELPER(bcr)(uint32_t cc, uint32_t mask, uint64_t target, uint64_t pc) > +{ > + if ( mask & ( 1 << (3 - cc) ) ) { > + env->psw.addr = target; > + } > + else { > + env->psw.addr = pc + 2; > + } > +} > + > +/* conditional branch to address (address is passed as target) */ > +void HELPER(bc)(uint32_t cc, uint32_t mask, uint64_t target, uint64_t pc) > +{ > + if ( mask & ( 1 << (3 - cc) ) ) { > + env->psw.addr = target; > + } > + else { > + env->psw.addr = pc + 4; > + } > + HELPER_LOG("%s: pc 0x%lx psw.addr 0x%lx r2 0x%lx r5 0x%lx\n", __FUNCTION__, > + pc, env->psw.addr, env->regs[2], env->regs[5]); > +} All the branch part would really gain to be coded in TCG, as it will allow TB chaining. > +/* 64-bit unsigned comparison */ > +uint32_t HELPER(cmp_u64)(uint64_t o1, uint64_t o2) > +{ > + if (o1 < o2) return 1; > + else if (o1 > o2) return 2; > + else return 0; coding style > +} > + > +/* 32-bit unsigned comparison */ > +uint32_t HELPER(cmp_u32)(uint32_t o1, uint32_t o2) > +{ > + HELPER_LOG("%s: o1 0x%x o2 0x%x\n", __FUNCTION__, o1, o2); > + if (o1 < o2) return 1; > + else if (o1 > o2) return 2; > + else return 0; > +} > + > +/* 64-bit signed comparison */ > +uint32_t HELPER(cmp_s64)(int64_t o1, int64_t o2) > +{ > + HELPER_LOG("%s: o1 %ld o2 %ld\n", __FUNCTION__, o1, o2); > + if (o1 < o2) return 1; > + else if (o1 > o2) return 2; > + else return 0; coding style > +} > + > +/* 32-bit signed comparison */ > +uint32_t HELPER(cmp_s32)(int32_t o1, int32_t o2) > +{ > + if (o1 < o2) return 1; > + else if (o1 > o2) return 2; > + else return 0; coding style > +} Same remarks as for previous comparisons, this can be done in TCG. > +/* compare logical under mask */ > +uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) > +{ > + uint8_t r,d; > + uint32_t cc; > + HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n",__FUNCTION__,r1,mask,addr); > + cc = 0; > + while (mask) { > + if (mask & 8) { > + d = ldub(addr); > + r = (r1 & 0xff000000UL) >> 24; > + HELPER_LOG("mask 0x%x %02x/%02x (0x%lx) ", mask, r, d, addr); > + if (r < d) { > + cc = 1; > + break; > + } > + else if (r > d) { coding style > + cc = 2; > + break; > + } > + addr++; > + } > + mask = (mask << 1) & 0xf; > + r1 <<= 8; > + } > + HELPER_LOG("\n"); > + return cc; > +} > + > +/* store character under mask */ > +void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) > +{ > + uint8_t r; > + HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n",__FUNCTION__,r1,mask,addr); > + while (mask) { > + if (mask & 8) { > + r = (r1 & 0xff000000UL) >> 24; > + stb(addr, r); > + HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); > + addr++; > + } > + mask = (mask << 1) & 0xf; > + r1 <<= 8; > + } > + HELPER_LOG("\n"); > +} > + > +/* 64/64 -> 128 unsigned multiplication */ > +void HELPER(mlg)(uint32_t r1, uint64_t v2) > +{ > + __uint128_t res = (__uint128_t)env->regs[r1 + 1]; > + res *= (__uint128_t)v2; > + env->regs[r1] = (uint64_t)(res >> 64); > + env->regs[r1 + 1] = (uint64_t)res; > +} __uint128_t is probably not supported on all hosts/GCC versions. mulu64() should be used instead. > +/* 128 -> 64/64 unsigned division */ > +void HELPER(dlg)(uint32_t r1, uint64_t v2) > +{ > + __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | > + (env->regs[r1+1]); > + uint64_t divisor = v2; > + __uint128_t quotient = dividend / divisor; > + env->regs[r1+1] = quotient; > + __uint128_t remainder = dividend % divisor; > + env->regs[r1] = remainder; > + HELPER_LOG("%s: dividend 0x%016lx%016lx divisor 0x%lx quotient 0x%lx rem 0x%lx\n", > + __FUNCTION__, (uint64_t)(dividend >> 64), (uint64_t)dividend, divisor, (uint64_t)quotient, > + (uint64_t)remainder); > +} Same here, __uint128_t should not be used, though I don't know what should be used instead. > +/* set condition code for 64-bit signed addition */ > +uint32_t HELPER(set_cc_add64)(int64_t a1, int64_t a2, int64_t ar) > +{ > + if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { > + return 3; /* overflow */ > + } > + else { > + if (ar < 0) return 1; > + else if (ar > 0) return 2; > + else return 0; > + } coding style > +} > + > +/* set condition code for 64-bit unsigned addition */ > +uint32_t HELPER(set_cc_addu64)(uint64_t a1, uint64_t a2, uint64_t ar) > +{ > + if (ar == 0) { > + if (a1) return 2; > + else return 0; > + } > + else { > + if (ar < a1 || ar < a2) { > + return 3; > + } > + else { > + return 1; > + } > + } coding style > +} > + > +/* set condition code for 32-bit signed addition */ > +uint32_t HELPER(set_cc_add32)(int32_t a1, int32_t a2, int32_t ar) > +{ > + if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { > + return 3; /* overflow */ > + } > + else { coding style > + if (ar < 0) return 1; > + else if (ar > 0) return 2; > + else return 0; > + } > +} > + > +/* set condition code for 32-bit unsigned addition */ > +uint32_t HELPER(set_cc_addu32)(uint32_t a1, uint32_t a2, uint32_t ar) > +{ > + if (ar == 0) { > + if (a1) return 2; > + else return 0; > + } > + else { coding style > + if (ar < a1 || ar < a2) { > + return 3; > + } > + else { > + return 1; > + } > + } > +} > + > +/* set condition code for 64-bit signed subtraction */ > +uint32_t HELPER(set_cc_sub64)(int64_t s1, int64_t s2, int64_t sr) > +{ > + if ((s1 > 0 && s2 < 0 && sr < 0) || (s1 < 0 && s2 > 0 && sr > 0)) { > + return 3; /* overflow */ > + } > + else { coding style > + if (sr < 0) return 1; > + else if (sr > 0) return 2; > + else return 0; > + } > +} > + > +/* set condition code for 32-bit signed subtraction */ > +uint32_t HELPER(set_cc_sub32)(int32_t s1, int32_t s2, int32_t sr) > +{ > + if ((s1 > 0 && s2 < 0 && sr < 0) || (s1 < 0 && s2 > 0 && sr > 0)) { > + return 3; /* overflow */ > + } > + else { > + if (sr < 0) return 1; > + else if (sr > 0) return 2; > + else return 0; > + } > +} > + > +/* set condition code for 32-bit unsigned subtraction */ > +uint32_t HELPER(set_cc_subu32)(uint32_t s1, uint32_t s2, uint32_t sr) > +{ > + if (sr == 0) return 2; > + else { coding style > + if (s2 > s1) return 1; > + else return 3; > + } > +} > + > +/* set condition code for 64-bit unsigned subtraction */ > +uint32_t HELPER(set_cc_subu64)(uint64_t s1, uint64_t s2, uint64_t sr) > +{ > + if (sr == 0) return 2; > + else { coding style > + if (s2 > s1) return 1; > + else return 3; > + } > +} > + > +/* search string (c is byte to search, r2 is string, r1 end of string) */ > +uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) > +{ > + HELPER_LOG("%s: c %d *r1 0x%lx *r2 0x%lx\n", __FUNCTION__, c, env->regs[r1], > + env->regs[r2]); > + uint64_t i; > + uint32_t cc; > + for (i = env->regs[r2]; i != env->regs[r1]; i++) { > + if (ldub(i) == c) { > + env->regs[r1] = i; > + cc = 1; > + return cc; > + } > + } > + cc = 2; > + return cc; > +} > + > +/* unsigned string compare (c is string terminator) */ > +uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) > +{ > + uint64_t s1 = env->regs[r1]; > + uint64_t s2 = env->regs[r2]; > + uint8_t v1, v2; > + uint32_t cc; > + c = c & 0xff; > +#ifdef CONFIG_USER_ONLY > + if (!c) { > + HELPER_LOG("%s: comparing '%s' and '%s'\n", > + __FUNCTION__, (char*)s1, (char*)s2); > + } > +#endif Why CONFIG_USER_ONLY ? > + for (;;) { > + v1 = ldub(s1); > + v2 = ldub(s2); > + if (v1 == c || v2 == c) break; > + if (v1 != v2) break; > + s1++; s2++; > + } coding style > + > + if (v1 == v2) cc = 0; > + else { > + if (v1 < v2) cc = 1; > + else cc = 2; > + env->regs[r1] = s1; > + env->regs[r2] = s2; > + } > + return cc; > +} > + > +/* string copy (c is string terminator) */ > +uint32_t HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) > +{ > + uint64_t dest = env->regs[r1]; > + uint64_t src = env->regs[r2]; > + uint8_t v; > + c = c & 0xff; > +#ifdef CONFIG_USER_ONLY > + if (!c) { > + HELPER_LOG("%s: copying '%s' to 0x%lx\n", __FUNCTION__, (char*)src, dest); > + } > +#endif Same. > + for (;;) { > + v = ldub(src); > + stb(dest, v); > + if (v == c) break; coding style > + src++; dest++; > + } > + env->regs[r1] = dest; > + return 1; > +} > + > +/* compare and swap 64-bit */ > +uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) > +{ > + /* FIXME: locking? */ > + uint32_t cc; > + uint64_t v2 = ldq(a2); > + if (env->regs[r1] == v2) { > + cc = 0; > + stq(a2, env->regs[r3]); > + } > + else { > + cc = 1; > + env->regs[r1] = v2; > + } > + return cc; coding style > +} > + > +/* compare double and swap 64-bit */ > +uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3) > +{ > + /* FIXME: locking? */ > + uint32_t cc; > + __uint128_t v2 = (((__uint128_t)ldq(a2)) << 64) | (__uint128_t)ldq(a2 + 8); > + __uint128_t v1 = (((__uint128_t)env->regs[r1]) << 64) | (__uint128_t)env->regs[r1 + 1]; > + if (v1 == v2) { > + cc = 0; > + stq(a2, env->regs[r3]); > + stq(a2 + 8, env->regs[r3 + 1]); > + } > + else { coding style > + cc = 1; > + env->regs[r1] = v2 >> 64; > + env->regs[r1 + 1] = v2 & 0xffffffffffffffffULL; > + } > + return cc; > +} > + > +/* compare and swap 32-bit */ > +uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) > +{ > + /* FIXME: locking? */ > + uint32_t cc; > + HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __FUNCTION__, r1, a2, r3); > + uint32_t v2 = ldl(a2); > + if (((uint32_t)env->regs[r1]) == v2) { > + cc = 0; > + stl(a2, (uint32_t)env->regs[r3]); > + } coding style > + else { > + cc = 1; > + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; > + } > + return cc; > +} > + > +/* execute instruction > + this instruction executes an insn modified with the contents of r1 > + it does not change the executed instruction in memory > + it does not change the program counter > + in other words: tricky... > + currently implemented by interpreting the cases it is most commonly used in > + */ > +uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) > +{ > + uint16_t insn = lduw(addr); > + HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __FUNCTION__, v1, addr, > + insn); > + if ((insn & 0xf0ff) == 0xd000) { > + uint32_t l, insn2, b, d1, d2; > + l = v1 & 0xff; > + insn2 = ldl(addr + 2); > + b = (((insn2 >> 28) & 0xf) << 4) | ((insn2 >> 12) & 0xf); > + d1 = (insn2 >> 16) & 0xfff; > + d2 = insn2 & 0xfff; > + switch (insn & 0xf00) { > + case 0x200: helper_mvc(l, b, d1, d2); return cc; break; > + case 0x500: return helper_clc(l, b, d1, d2); break; > + case 0x700: return helper_xc(l, b, d1, d2); break; > + default: helper_exception(23); break; > + } > + } > + else if ((insn & 0xff00) == 0x0a00) { /* supervisor call */ > + HELPER_LOG("%s: svc %ld via execute\n", __FUNCTION__, (insn|v1) & 0xff); > + env->psw.addr = ret; > + helper_exception(EXCP_EXECUTE_SVC + ((insn | v1) & 0xff)); > + } > + else { > + helper_exception(23); > + } > + return cc; > +} Looks a bit ugly, but currently do not have anything else to offer. > +/* set condition code for test under mask */ > +uint32_t HELPER(tm)(uint32_t val, uint32_t mask) > +{ > + HELPER_LOG("%s: val 0x%x mask 0x%x\n", __FUNCTION__, val, mask); > + uint16_t r = val & mask; > + if (r == 0) return 0; > + else if (r == mask) return 3; > + else return 1; coding style > +} > + > +/* set condition code for test under mask */ > +uint32_t HELPER(tmxx)(uint64_t val, uint32_t mask) > +{ > + uint16_t r = val & mask; > + HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __FUNCTION__, val, mask, r); > + if (r == 0) return 0; > + else if (r == mask) return 3; > + else { > + while (!(mask & 0x8000)) { > + mask <<= 1; > + val <<= 1; > + } > + if (val & 0x8000) return 2; > + else return 1; > + } coding style > +} > + > +/* absolute value 32-bit */ > +uint32_t HELPER(abs_i32)(uint32_t reg, int32_t val) > +{ > + uint32_t cc; > + if (val == 0x80000000UL) cc = 3; > + else if (val) cc = 1; > + else cc = 0; > + > + if (val < 0) { > + env->regs[reg] = -val; > + } > + else { > + env->regs[reg] = val; > + } > + return cc; coding style > +} > + > +/* negative absolute value 32-bit */ > +uint32_t HELPER(nabs_i32)(uint32_t reg, int32_t val) > +{ > + uint32_t cc; > + if (val) cc = 1; > + else cc = 0; > + > + if (val < 0) { > + env->regs[reg] = (env->regs[reg] & 0xffffffff00000000ULL) | val; > + } > + else { > + env->regs[reg] = (env->regs[reg] & 0xffffffff00000000ULL) | ((uint32_t)-val); > + } > + return cc; coding style > +} > + > +/* absolute value 64-bit */ > +uint32_t HELPER(abs_i64)(uint32_t reg, int64_t val) > +{ > + uint32_t cc; > + if (val == 0x8000000000000000ULL) cc = 3; > + else if (val) cc = 1; > + else cc = 0; > + > + if (val < 0) { > + env->regs[reg] = -val; > + } > + else { > + env->regs[reg] = val; > + } > + return cc; > +} > + > +/* negative absolute value 64-bit */ > +uint32_t HELPER(nabs_i64)(uint32_t reg, int64_t val) > +{ > + uint32_t cc; > + if (val) cc = 1; > + else cc = 0; > + > + if (val < 0) { > + env->regs[reg] = val; > + } > + else { > + env->regs[reg] = -val; > + } > + return cc; coding style > +} > + > +/* add with carry 32-bit unsigned */ > +uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t r1, uint32_t v2) > +{ > + uint32_t res; > + uint32_t v1 = env->regs[r1] & 0xffffffffUL; > + res = v1 + v2; > + if (cc & 2) res++; > + > + if (res == 0) { > + if (v1) cc = 2; > + else cc = 0; > + } > + else { > + if (res < v1 || res < v2) > + cc = 3; > + else > + cc = 1; > + } > + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; > + return cc; coding style > +} > + > +/* CC for add with carry 64-bit unsigned (isn't this a duplicate of some other CC function?) */ > +uint32_t HELPER(set_cc_addc_u64)(uint64_t v1, uint64_t v2, uint64_t res) > +{ > + uint32_t cc; > + if (res == 0) { > + if (v1) cc = 2; > + else cc = 0; > + } > + else { > + if (res < v1 || res < v2) { > + cc = 3; > + } > + else { > + cc = 1; > + } > + } > + return cc; > +} > + > +/* store character under mask high > + operates on the upper half of r1 */ > +uint32_t HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) > +{ > + int pos = 56; /* top of the upper half of r1 */ > + > + while (mask) { > + if (mask & 8) { > + stb(address, (env->regs[r1] >> pos) & 0xff); > + address++; > + } > + mask = (mask << 1) & 0xf; > + pos -= 8; > + } > + return 0; > +} > + > +/* insert character under mask high > + same as icm, but operates on the upper half of r1 */ > +uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) > +{ > + int pos = 56; /* top of the upper half of r1 */ > + uint64_t rmask = 0xff00000000000000ULL; > + uint8_t val = 0; > + int ccd = 0; > + uint32_t cc; > + > + cc = 0; > + > + while (mask) { > + if (mask & 8) { > + env->regs[r1] &= ~rmask; > + val = ldub(address); > + if ((val & 0x80) && !ccd) cc = 1; > + ccd = 1; > + if (val && cc == 0) cc = 2; > + env->regs[r1] |= (uint64_t)val << pos; > + address++; > + } > + mask = (mask << 1) & 0xf; > + pos -= 8; > + rmask >>= 8; > + } > + return cc; coding style > +} > + > +/* insert psw mask and condition code into r1 */ > +void HELPER(ipm)(uint32_t cc, uint32_t r1) > +{ > + uint64_t r = env->regs[r1]; > + r &= 0xffffffff00ffffffULL; > + r |= (cc << 28) | ( (env->psw.mask >> 40) & 0xf ); > + env->regs[r1] = r; > + HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __FUNCTION__, cc, env->psw.mask, r); > +} > + > +/* store access registers r1 to r3 in memory at a2 */ > +void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3) > +{ > + int i; > + for (i = r1; i != ((r3 + 1) & 15); i = (i + 1) & 15) { > + stl(a2, env->aregs[i]); > + a2 += 4; > + } > +} > + > +/* move long extended > + another memcopy insn with more bells and whistles */ > +uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) > +{ > + uint64_t destlen = env->regs[r1 + 1]; > + uint64_t dest = env->regs[r1]; > + uint64_t srclen = env->regs[r3 + 1]; > + uint64_t src = env->regs[r3]; > + uint8_t pad = a2 & 0xff; > + uint8_t v; > + uint32_t cc; > + if (destlen == srclen) cc = 0; > + else if (destlen < srclen) cc = 1; > + else cc = 2; > + if (srclen > destlen) srclen = destlen; coding style > + for(;destlen && srclen;src++,dest++,destlen--,srclen--) { > + v = ldub(src); > + stb(dest, v); > + } > + for(;destlen;dest++,destlen--) { > + stb(dest, pad); > + } > + env->regs[r1 + 1] = destlen; > + env->regs[r3 + 1] -= src - env->regs[r3]; /* can't use srclen here, > + we trunc'ed it */ > + env->regs[r1] = dest; > + env->regs[r3] = src; > + > + return cc; > +} > + > +/* compare logical long extended > + memcompare insn with padding */ > +uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) > +{ > + uint64_t destlen = env->regs[r1 + 1]; > + uint64_t dest = env->regs[r1]; > + uint64_t srclen = env->regs[r3 + 1]; > + uint64_t src = env->regs[r3]; > + uint8_t pad = a2 & 0xff; > + uint8_t v1 = 0,v2 = 0; > + uint32_t cc = 0; > + if (!(destlen || srclen)) return cc; > + if (srclen > destlen) srclen = destlen; > + for(;destlen || srclen;src++,dest++,destlen--,srclen--) { > + if (srclen) v1 = ldub(src); > + else v1 = pad; > + if (destlen) v2 = ldub(dest); > + else v2 = pad; > + if (v1 != v2) break; > + } > + > + env->regs[r1 + 1] = destlen; > + env->regs[r3 + 1] -= src - env->regs[r3]; /* can't use srclen here, > + we trunc'ed it */ > + env->regs[r1] = dest; > + env->regs[r3] = src; > + > + if (v1 < v2) cc = 1; > + else if (v1 > v2) cc = 2; > + > + return cc; coding style > +} > + > +/* subtract unsigned v2 from v1 with borrow */ > +uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v1, uint32_t v2) > +{ > + uint32_t res = v1 + (~v2) + (cc >> 1); > + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; > + if (cc & 2) { /* borrow */ > + if (v1) return 1; > + else return 0; > + } > + else { > + if (v1) return 3; > + else return 2; > + } coding style > +} > + > +/* subtract unsigned v2 from v1 with borrow */ > +uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) > +{ > + uint64_t res = v1 + (~v2) + (cc >> 1); > + env->regs[r1] = res; > + if (cc & 2) { /* borrow */ > + if (v1) return 1; > + else return 0; > + } > + else { > + if (v1) return 3; > + else return 2; > + } coding style > +} > + > +/* union used for splitting/joining 128-bit floats to/from 64-bit FP regs */ > +typedef union { > + struct { > +#ifdef WORDS_BIGENDIAN > + uint64_t h; > + uint64_t l; > +#else > + uint64_t l; > + uint64_t h; > +#endif > + }; > + float128 x; > +} FP128; WORDS_BIGENDIAN is wrong here. CPU_QuadU can probably be used instead. > +/* condition codes for binary FP ops */ > +static uint32_t set_cc_f32(float32 v1, float32 v2) > +{ > + if (float32_is_nan(v1) || float32_is_nan(v2)) return 3; > + else if (float32_eq(v1, v2, &env->fpu_status)) return 0; > + else if (float32_lt(v1, v2, &env->fpu_status)) return 1; > + else return 2; coding style > +} > + > +static uint32_t set_cc_f64(float64 v1, float64 v2) > +{ > + if (float64_is_nan(v1) || float64_is_nan(v2)) return 3; > + else if (float64_eq(v1, v2, &env->fpu_status)) return 0; > + else if (float64_lt(v1, v2, &env->fpu_status)) return 1; > + else return 2; coding style > +} > + > +/* condition codes for unary FP ops */ > +static uint32_t set_cc_nz_f32(float32 v) > +{ > + if (float32_is_nan(v)) return 3; > + else if (float32_is_zero(v)) return 0; > + else if (float32_is_neg(v)) return 1; > + else return 2; coding style > +} > + > +static uint32_t set_cc_nz_f64(float64 v) > +{ > + if (float64_is_nan(v)) return 3; > + else if (float64_is_zero(v)) return 0; > + else if (float64_is_neg(v)) return 1; > + else return 2; coding style > +} > + > +static uint32_t set_cc_nz_f128(float128 v) > +{ > + if (float128_is_nan(v)) return 3; > + else if (float128_is_zero(v)) return 0; > + else if (float128_is_neg(v)) return 1; > + else return 2; coding style > +} > + > +/* convert 32-bit int to 64-bit float */ > +void HELPER(cdfbr)(uint32_t f1, int32_t v2) > +{ > + HELPER_LOG("%s: converting %d to f%d\n", __FUNCTION__, v2, f1); > + env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); > +} > + > +/* convert 32-bit int to 128-bit float */ > +void HELPER(cxfbr)(uint32_t f1, int32_t v2) > +{ > + FP128 v1; > + v1.x = int32_to_float128(v2, &env->fpu_status); > + env->fregs[f1].i = v1.h; > + env->fregs[f1 + 2].i = v1.l; > +} > + > +/* convert 64-bit int to 32-bit float */ > +void HELPER(cegbr)(uint32_t f1, int64_t v2) > +{ > + HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1); > + env->fregs[f1].e = int64_to_float32(v2, &env->fpu_status); > +} > + > +/* convert 64-bit int to 64-bit float */ > +void HELPER(cdgbr)(uint32_t f1, int64_t v2) > +{ > + HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1); > + env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); > +} > + > +/* convert 64-bit int to 128-bit float */ > +void HELPER(cxgbr)(uint32_t f1, int64_t v2) > +{ > + FP128 x1; > + x1.x = int64_to_float128(v2, &env->fpu_status); > + HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __FUNCTION__, v2, x1.h, x1.l); > + env->fregs[f1].i = x1.h; > + env->fregs[f1 + 2].i = x1.l; > +} > + > +/* convert 32-bit int to 32-bit float */ > +void HELPER(cefbr)(uint32_t f1, int32_t v2) > +{ > + env->fregs[f1].e = int32_to_float32(v2, &env->fpu_status); > + HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __FUNCTION__, v2, env->fregs[f1].e, f1); > +} > + > +/* 32-bit FP addition RR */ > +uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].e = float32_add(env->fregs[f1].e, env->fregs[f2].e, &env->fpu_status); > + HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, env->fregs[f2].e, env->fregs[f1].e, f1); > + return set_cc_nz_f32(env->fregs[f1].e); > +} > + > +/* 64-bit FP addition RR */ > +uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); > + HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1); > + return set_cc_nz_f64(env->fregs[f1].d); > +} > + > +/* 32-bit FP subtraction RR */ > +uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].e = float32_sub(env->fregs[f1].e, env->fregs[f2].e, &env->fpu_status); > + HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, env->fregs[f2].e, env->fregs[f1].e, f1); > + return set_cc_nz_f32(env->fregs[f1].e); > +} > + > +/* 64-bit FP subtraction RR */ > +uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); > + HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1); > + return set_cc_nz_f64(env->fregs[f1].d); > +} > + > +/* 32-bit FP division RR */ > +void HELPER(debr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].e = float32_div(env->fregs[f1].e, env->fregs[f2].e, &env->fpu_status); > +} > + > +/* 128-bit FP division RR */ > +void HELPER(dxbr)(uint32_t f1, uint32_t f2) > +{ > + FP128 v1; > + v1.h = env->fregs[f1].i; > + v1.l = env->fregs[f1 + 2].i; > + FP128 v2; > + v2.h = env->fregs[f2].i; > + v2.l = env->fregs[f2 + 2].i; > + FP128 res; > + res.x = float128_div(v1.x, v2.x, &env->fpu_status); > + env->fregs[f1].i = res.h; > + env->fregs[f1 + 2].i = res.l; > +} > + > +/* 64-bit FP multiplication RR */ > +void HELPER(mdbr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); > +} > + > +/* 128-bit FP multiplication RR */ > +void HELPER(mxbr)(uint32_t f1, uint32_t f2) > +{ > + FP128 v1; > + v1.h = env->fregs[f1].i; > + v1.l = env->fregs[f1 + 2].i; > + FP128 v2; > + v2.h = env->fregs[f2].i; > + v2.l = env->fregs[f2 + 2].i; > + FP128 res; > + res.x = float128_mul(v1.x, v2.x, &env->fpu_status); > + //HELPER_LOG("%s: 0x%ld * 0x%ld = 0x%ld\n", __FUNCTION__, v1.x, v2.x, res.x); > + env->fregs[f1].i = res.h; > + env->fregs[f1 + 2].i = res.l; > +} > + > +/* convert 32-bit float to 64-bit float */ > +void HELPER(ldebr)(uint32_t r1, uint32_t r2) > +{ > + env->fregs[r1].d = float32_to_float64(env->fregs[r2].e, &env->fpu_status); > +} > + > +/* convert 128-bit float to 64-bit float */ > +void HELPER(ldxbr)(uint32_t f1, uint32_t f2) > +{ > + FP128 x2; > + x2.h = env->fregs[f2].i; > + x2.l = env->fregs[f2 + 2].i; > + //HELPER_LOG("%s: converted %llf ", __FUNCTION__, x2.x); > + env->fregs[f1].d = float128_to_float64(x2.x, &env->fpu_status); > + HELPER_LOG("%s: to 0x%ld\n", __FUNCTION__, env->fregs[f1].d); > +} > + > +/* convert 64-bit float to 128-bit float */ > +void HELPER(lxdbr)(uint32_t f1, uint32_t f2) > +{ > + FP128 res; > + res.x = float64_to_float128(env->fregs[f2].d, &env->fpu_status); > + env->fregs[f1].i = res.h; > + env->fregs[f1 + 2].i = res.l; > +} > + > +/* convert 64-bit float to 32-bit float */ > +void HELPER(ledbr)(uint32_t f1, uint32_t f2) > +{ > + float64 d2 = env->fregs[f2].d; > + env->fregs[f1].e = float64_to_float32(d2, &env->fpu_status); > +} > + > +/* convert 128-bit float to 32-bit float */ > +void HELPER(lexbr)(uint32_t f1, uint32_t f2) > +{ > + FP128 x2; > + x2.h = env->fregs[f2].i; > + x2.l = env->fregs[f2 + 2].i; > + //HELPER_LOG("%s: converted %llf ", __FUNCTION__, x2.x); > + env->fregs[f1].e = float128_to_float32(x2.x, &env->fpu_status); > + HELPER_LOG("%s: to 0x%d\n", __FUNCTION__, env->fregs[f1].e); > +} > + > +/* absolute value of 32-bit float */ > +uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) > +{ > + float32 v1; > + float32 v2 = env->fregs[f2].d; > + if (float32_is_neg(v2)) { > + v1 = float32_abs(v2); > + } > + else { > + v1 = v2; > + } I don't see the point of such a test here. > + env->fregs[f1].d = v1; > + return set_cc_nz_f32(v1); > +} > + > +/* absolute value of 64-bit float */ > +uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) > +{ > + float64 v1; > + float64 v2 = env->fregs[f2].d; > + if (float64_is_neg(v2)) { > + v1 = float64_abs(v2); > + } > + else { > + v1 = v2; > + } Same. > + env->fregs[f1].d = v1; > + return set_cc_nz_f64(v1); > +} > + > +/* absolute value of 128-bit float */ > +uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) > +{ > + FP128 v1; > + FP128 v2; > + v2.h = env->fregs[f2].i; > + v2.l = env->fregs[f2 + 2].i; > + if (float128_is_neg(v2.x)) { > + v1.x = float128_abs(v2.x); > + } > + else { > + v1 = v2; > + } Same. > + env->fregs[f1].i = v1.h; > + env->fregs[f1 + 2].i = v1.l; > + return set_cc_nz_f128(v1.x); > +} > + > +/* load and test 64-bit float */ > +uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].d = env->fregs[f2].d; > + return set_cc_nz_f64(env->fregs[f1].d); > +} > + > +/* load and test 32-bit float */ > +uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].e = env->fregs[f2].e; > + return set_cc_nz_f32(env->fregs[f1].e); > +} > + > +/* load and test 128-bit float */ > +uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) > +{ > + FP128 x; > + x.h = env->fregs[f2].i; > + x.l = env->fregs[f2 + 2].i; > + env->fregs[f1].i = x.h; > + env->fregs[f1 + 2].i = x.l; > + return set_cc_nz_f128(x.x); > +} > + > +/* negative absolute of 32-bit float */ > +uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].e = float32_sub(float32_zero, env->fregs[f2].e, &env->fpu_status); > + return set_cc_nz_f32(env->fregs[f1].e); > +} > + > +/* negative absolute of 64-bit float */ > +uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].d = float64_sub(float64_zero, env->fregs[f2].d, &env->fpu_status); > + return set_cc_nz_f64(env->fregs[f1].d); > +} > + > +/* convert 64-bit float to 128-bit float */ > +uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) > +{ > + FP128 x1, x2; > + x2.h = env->fregs[f2].i; > + x2.l = env->fregs[f2 + 2].i; > + x1.x = float128_sub(float64_to_float128(float64_zero, &env->fpu_status), x2.x, &env->fpu_status); > + env->fregs[f1].i = x1.h; > + env->fregs[f1 + 2].i = x1.l; > + return set_cc_nz_f128(x1.x); > +} > + > +/* 32-bit FP compare RM */ > +uint32_t HELPER(ceb)(uint32_t f1, uint64_t a2) > +{ > + float32 v1 = env->fregs[f1].e; > + union { > + float32 e; > + uint32_t i; > + } v2; CPU_FloatU should be used instead. > + v2.i = ldl(a2); The value should be passed directly instead of loaded here, as ldl is is wrong depending on the MMU mode. > + HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2.e); > + return set_cc_f32(v1, v2.e); > +} > + > +/* 32-bit FP addition RM */ > +uint32_t HELPER(aeb)(uint32_t f1, uint64_t a2) > +{ > + float32 v1 = env->fregs[f1].e; > + union { > + float32 e; > + uint32_t i; > + } v2; same > + v2.i = ldl(a2); same > + HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2.e); > + env->fregs[f1].e = float32_add(v1, v2.e, &env->fpu_status); > + return set_cc_nz_f32(env->fregs[f1].e); > +} > + > +/* 32-bit FP division RM */ > +void HELPER(deb)(uint32_t f1, uint64_t a2) > +{ > + float32 v1 = env->fregs[f1].e; > + union { > + float32 e; > + uint32_t i; > + } v2; same > + v2.i = ldl(a2); same > + HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __FUNCTION__, v1, f1, v2.e); > + env->fregs[f1].e = float32_div(v1, v2.e, &env->fpu_status); > +} > + > +/* 32-bit FP multiplication RM */ > +void HELPER(meeb)(uint32_t f1, uint64_t a2) > +{ > + float32 v1 = env->fregs[f1].e; > + union { > + float32 e; > + uint32_t i; > + } v2; same > + v2.i = ldl(a2); same > + HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2.e); > + env->fregs[f1].e = float32_mul(v1, v2.e, &env->fpu_status); > +} > + > +/* 32-bit FP compare RR */ > +uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) > +{ > + float32 v1 = env->fregs[f1].e; > + float32 v2 = env->fregs[f2].e;; > + HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2); > + return set_cc_f32(v1, v2); > +} > + > +/* 64-bit FP compare RR */ > +uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) > +{ > + float64 v1 = env->fregs[f1].d; > + float64 v2 = env->fregs[f2].d;; > + HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __FUNCTION__, v1, f1, v2); > + return set_cc_f64(v1, v2); > +} > + > +/* 128-bit FP compare RR */ > +uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) > +{ > + FP128 v1; > + v1.h = env->fregs[f1].i; > + v1.l = env->fregs[f1 + 2].i; > + FP128 v2; > + v2.h = env->fregs[f2].i; > + v2.l = env->fregs[f2 + 2].i; > + //HELPER_LOG("%s: comparing %llf from f%d and %llf\n", __FUNCTION__, v1.x, f1, v2.x); > + if (float128_is_nan(v1.x) || float128_is_nan(v2.x)) return 3; > + else if (float128_eq(v1.x, v2.x, &env->fpu_status)) return 0; > + else if (float128_lt(v1.x, v2.x, &env->fpu_status)) return 1; > + else return 2; coding style > +} > + > +/* 64-bit FP compare RM */ > +uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) > +{ > + float64 v1 = env->fregs[f1].d; > + union { > + float64 d; > + uint64_t i; > + } v2; same > + v2.i = ldq(a2); same > + HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __FUNCTION__, v1, f1, v2.d); > + return set_cc_f64(v1, v2.d); > +} > + > +/* 64-bit FP addition RM */ > +uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) > +{ > + float64 v1 = env->fregs[f1].d; > + union { > + float64 d; > + uint64_t i; > + } v2; same > + v2.i = ldq(a2); same > + HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __FUNCTION__, v1, f1, v2.d); > + env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); > + return set_cc_nz_f64(v1); > +} > + > +/* 32-bit FP subtraction RM */ > +uint32_t HELPER(seb)(uint32_t f1, uint64_t a2) > +{ > + float32 v1 = env->fregs[f1].e; > + union { > + float32 e; > + uint32_t i; > + } v2; same > + v2.i = ldl(a2); same > + env->fregs[f1].e = v1 = float32_sub(v1, v2.e, &env->fpu_status); > + return set_cc_nz_f32(v1); > +} > + > +/* 64-bit FP subtraction RM */ > +uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) > +{ > + float64 v1 = env->fregs[f1].d; > + union { > + float64 d; > + uint64_t i; > + } v2; same > + v2.i = ldq(a2); same > + env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); > + return set_cc_nz_f64(v1); > +} > + > +/* 64-bit FP multiplication RM */ > +void HELPER(mdb)(uint32_t f1, uint64_t a2) > +{ > + float64 v1 = env->fregs[f1].d; > + union { > + float64 d; > + uint64_t i; > + } v2; same > + v2.i = ldq(a2); same > + HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __FUNCTION__, v1, f1, v2.d); > + env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); > +} > + > +/* 64-bit FP division RM */ > +void HELPER(ddb)(uint32_t f1, uint64_t a2) > +{ > + float64 v1 = env->fregs[f1].d; > + union { > + float64 d; > + uint64_t i; > + } v2; same > + v2.i = ldq(a2); same > + HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __FUNCTION__, v1, f1, v2.d); > + env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); > +} > + > +static void set_round_mode(int m3) > +{ > + switch (m3) { > + case 0: break; /* current mode */ > + case 1: /* biased round no nearest */ > + case 4: /* round to nearest */ > + set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); > + break; > + case 5: /* round to zero */ > + set_float_rounding_mode(float_round_to_zero, &env->fpu_status); > + break; > + case 6: /* round to +inf */ > + set_float_rounding_mode(float_round_up, &env->fpu_status); > + break; > + case 7: /* round to -inf */ > + set_float_rounding_mode(float_round_down, &env->fpu_status); > + break; > + } > +} > + > +/* convert 32-bit float to 64-bit int */ > +uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) > +{ > + float32 v2 = env->fregs[f2].e; > + set_round_mode(m3); > + env->regs[r1] = float32_to_int64(v2, &env->fpu_status); > + return set_cc_nz_f32(v2); > +} > + > +/* convert 64-bit float to 64-bit int */ > +uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) > +{ > + float64 v2 = env->fregs[f2].d; > + set_round_mode(m3); > + env->regs[r1] = float64_to_int64(v2, &env->fpu_status); > + return set_cc_nz_f64(v2); > +} > + > +/* convert 128-bit float to 64-bit int */ > +uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) > +{ > + FP128 v2; > + v2.h = env->fregs[f2].i; > + v2.l = env->fregs[f2 + 2].i; > + set_round_mode(m3); > + env->regs[r1] = float128_to_int64(v2.x, &env->fpu_status); > + if (float128_is_nan(v2.x)) return 3; > + else if (float128_is_zero(v2.x)) return 0; > + else if (float128_is_neg(v2.x)) return 1; > + else return 2; coding style > +} > + > +/* convert 32-bit float to 32-bit int */ > +uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) > +{ > + float32 v2 = env->fregs[f2].e; > + set_round_mode(m3); > + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | float32_to_int32(v2, &env->fpu_status); > + return set_cc_nz_f32(v2); > +} > + > +/* convert 64-bit float to 32-bit int */ > +uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) > +{ > + float64 v2 = env->fregs[f2].d; > + set_round_mode(m3); > + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | float64_to_int32(v2, &env->fpu_status); > + return set_cc_nz_f64(v2); > +} > + > +/* convert 128-bit float to 32-bit int */ > +uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) > +{ > + FP128 v2; > + v2.h = env->fregs[f2].i; > + v2.l = env->fregs[f2 + 2].i; > + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | float128_to_int32(v2.x, &env->fpu_status); > + return set_cc_nz_f128(v2.x); > +} > + > +/* load 32-bit FP zero */ > +void HELPER(lzer)(uint32_t f1) > +{ > + env->fregs[f1].e = float32_zero; > +} > + > +/* load 64-bit FP zero */ > +void HELPER(lzdr)(uint32_t f1) > +{ > + env->fregs[f1].d = float64_zero; > +} > > +/* load 128-bit FP zero */ > +void HELPER(lzxr)(uint32_t f1) > +{ > + FP128 x; > + x.x = float64_to_float128(float64_zero, &env->fpu_status); > + env->fregs[f1].i = x.h; > + env->fregs[f1 + 1].i = x.l; > +} > + > +/* 128-bit FP subtraction RR */ > +uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) > +{ > + FP128 v1; > + v1.h = env->fregs[f1].i; > + v1.l = env->fregs[f1 + 2].i; > + FP128 v2; > + v2.h = env->fregs[f2].i; > + v2.l = env->fregs[f2 + 2].i; > + FP128 res; > + res.x = float128_sub(v1.x, v2.x, &env->fpu_status); > + env->fregs[f1].i = res.h; > + env->fregs[f1 + 2].i = res.l; > + return set_cc_nz_f128(res.x); > +} > + > +/* 128-bit FP addition RR */ > +uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) > +{ > + FP128 v1; > + v1.h = env->fregs[f1].i; > + v1.l = env->fregs[f1 + 2].i; > + FP128 v2; > + v2.h = env->fregs[f2].i; > + v2.l = env->fregs[f2 + 2].i; > + FP128 res; > + res.x = float128_add(v1.x, v2.x, &env->fpu_status); > + env->fregs[f1].i = res.h; > + env->fregs[f1 + 2].i = res.l; > + return set_cc_nz_f128(res.x); > +} > + > +/* 32-bit FP multiplication RR */ > +void HELPER(meebr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].e = float32_mul(env->fregs[f1].e, env->fregs[f2].e, &env->fpu_status); > +} > + > +/* 64-bit FP division RR */ > +void HELPER(ddbr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); > +} > + > +/* 64-bit FP multiply and add RM */ > +void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) > +{ > + HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __FUNCTION__, f1, a2, f3); > + union { > + float64 d; > + uint64_t i; > + } v2; > + v2.i = ldq(a2); > + env->fregs[f1].d = float64_add(env->fregs[f1].d, float64_mul(v2.d, env->fregs[f3].d, &env->fpu_status), &env->fpu_status); > +} > + > +/* 64-bit FP multiply and add RR */ > +void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) > +{ > + HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3); > + env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, env->fregs[f3].d, &env->fpu_status), env->fregs[f1].d, &env->fpu_status); > +} > + > +/* 64-bit FP multiply and subtract RR */ > +void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) > +{ > + HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3); > + env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, env->fregs[f3].d, &env->fpu_status), env->fregs[f1].d, &env->fpu_status); > +} > + > +/* 32-bit FP multiply and add RR */ > +void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) > +{ > + env->fregs[f1].e = float32_add(env->fregs[f1].e, float32_mul(env->fregs[f2].e, env->fregs[f3].e, &env->fpu_status), &env->fpu_status); > +} > + > +/* convert 64-bit float to 128-bit float */ > +void HELPER(lxdb)(uint32_t f1, uint64_t a2) > +{ > + union { > + float64 d; > + uint64_t i; > + } v2; same > + v2.i = ldq(a2); same > + FP128 v1; > + v1.x = float64_to_float128(v2.d, &env->fpu_status); > + env->fregs[f1].i = v1.h; > + env->fregs[f1 + 2].i = v1.l; > +} > + > +/* test data class 32-bit */ > +uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) > +{ > + float32 v1 = env->fregs[f1].e; > + int neg = float32_is_neg(v1); > + uint32_t cc = 0; > + HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg); > + if (float32_is_zero(v1) && (m2 & (1 << (11-neg)))) cc = 1; > + else if (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) cc = 1; > + else if (float32_is_nan(v1) && (m2 & (1 << (3-neg)))) cc = 1; > + else if (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg)))) cc = 1; > + else /* assume normalized number */ if (m2 & (1 << (9-neg))) cc = 1; > + /* FIXME: denormalized? */ > + return cc; coding style > +} > + > +/* test data class 64-bit */ > +uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) > +{ > + float64 v1 = env->fregs[f1].d; > + int neg = float64_is_neg(v1); > + uint32_t cc = 0; > + HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg); > + if (float64_is_zero(v1) && (m2 & (1 << (11-neg)))) cc = 1; > + else if (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) cc = 1; > + else if (float64_is_nan(v1) && (m2 & (1 << (3-neg)))) cc = 1; > + else if (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg)))) cc = 1; > + else /* assume normalized number */ if (m2 & (1 << (9-neg))) cc = 1; > + /* FIXME: denormalized? */ > + return cc; coding style > +} > + > +/* test data class 128-bit */ > +uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) > +{ > + FP128 v1; > + uint32_t cc = 0; > + v1.h = env->fregs[f1].i; > + v1.l = env->fregs[f1 + 2].i; > + > + int neg = float128_is_neg(v1.x); > + if (float128_is_zero(v1.x) && (m2 & (1 << (11-neg)))) cc = 1; > + else if (float128_is_infinity(v1.x) && (m2 & (1 << (5-neg)))) cc = 1; > + else if (float128_is_nan(v1.x) && (m2 & (1 << (3-neg)))) cc = 1; > + else if (float128_is_signaling_nan(v1.x) && (m2 & (1 << (1-neg)))) cc = 1; > + else /* assume normalized number */ if (m2 & (1 << (9-neg))) cc = 1; > + /* FIXME: denormalized? */ > + return cc; coding style > +} > + > +/* find leftmost one */ > +uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) > +{ > + uint64_t res = 0; > + uint64_t ov2 = v2; > + while (!(v2 & 0x8000000000000000ULL) && v2) { > + v2 <<= 1; > + res++; > + } > + if (!v2) { > + env->regs[r1] = 64; > + env->regs[r1 + 1] = 0; > + return 0; > + } > + else { > + env->regs[r1] = res; > + env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); > + return 2; > + } > +} > + > +/* square root 64-bit RR */ > +void HELPER(sqdbr)(uint32_t f1, uint32_t f2) > +{ > + env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); > +} > diff --git a/target-s390x/translate.c b/target-s390x/translate.c > new file mode 100644 > index 0000000..a1948bf > --- /dev/null > +++ b/target-s390x/translate.c > @@ -0,0 +1,2479 @@ > +/* > + * S/390 translation > + * > + * Copyright (c) 2009 Ulrich Hecht > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA > + */ > +#include <stdarg.h> > +#include <stdlib.h> > +#include <stdio.h> > +#include <string.h> > +#include <inttypes.h> > + > +#define S390X_DEBUG_DISAS > +#ifdef S390X_DEBUG_DISAS > +# define LOG_DISAS(...) qemu_log(__VA_ARGS__) > +#else > +# define LOG_DISAS(...) do { } while (0) > +#endif > + > +#include "cpu.h" > +#include "exec-all.h" > +#include "disas.h" > +#include "tcg-op.h" > +#include "qemu-log.h" > + > +/* global register indexes */ > +static TCGv_ptr cpu_env; > + > +#include "gen-icount.h" > +#include "helpers.h" > +#define GEN_HELPER 1 > +#include "helpers.h" > + > +typedef struct DisasContext DisasContext; > +struct DisasContext { > + uint64_t pc; > + int is_jmp; > + CPUS390XState *env; > +}; > + > +#define DISAS_EXCP 4 > +#define DISAS_SVC 5 > + > +void cpu_dump_state(CPUState *env, FILE *f, > + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), > + int flags) > +{ > + int i; > + for (i = 0; i < 16; i++) { > + cpu_fprintf(f, "R%02d=%016lx", i, env->regs[i]); > + if ((i % 4) == 3) cpu_fprintf(f, "\n"); coding style > + else cpu_fprintf(f, " "); > + } > + for (i = 0; i < 16; i++) { > + cpu_fprintf(f, "F%02d=%016lx", i, env->fregs[i]); > + if ((i % 4) == 3) cpu_fprintf(f, "\n"); coding style > + else cpu_fprintf(f, " "); > + } > + cpu_fprintf(f, "PSW=mask %016lx addr %016lx cc %02x\n", env->psw.mask, env->psw.addr, env->cc); > +} > + > +#define TCGREGS > + > +static TCGv global_cc; > +#ifdef TCGREGS > +/* registers stored in TCG variables enhance performance */ > +static TCGv tcgregs[16]; > +static TCGv tcgregs32[16]; This variables hold 32-bit TCG values, it should be of type TCGv_i32. > +#endif > +static TCGv cc; > +static TCGv psw_addr; > + > +void s390x_translate_init(void) > +{ > + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); > + global_cc = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, cc), "global_cc"); > +#ifdef TCGREGS > + int i; > + char rn[4]; > + for (i = 0; i < 16; i++) { > + sprintf(rn, "R%d", i); > + tcgregs[i] = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, regs[i]), strdup(rn)); > + sprintf(rn, "r%d", i); > + tcgregs32[i] = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, regs[i]) > +#ifdef WORDS_BIGENDIAN This is wrong. It should probably be HOST_WORDS_BIGENDIAN. > + + 4 > +#endif > + , strdup(rn)); > + } > +#endif > + psw_addr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, psw.addr), "psw_addr"); > +} > + > +#ifdef TCGREGS > +static inline void sync_reg64(int reg) > +{ > + tcg_gen_sync_i64(tcgregs[reg]); > +} > +static inline void sync_reg32(int reg) > +{ > + tcg_gen_sync_i32(tcgregs32[reg]); > +} > +#endif > + > +static TCGv load_reg(int reg) > +{ > + TCGv r = tcg_temp_new_i64(); > +#ifdef TCGREGS > + sync_reg32(reg); > + tcg_gen_mov_i64(r, tcgregs[reg]); > + return r; > +#else > + tcg_gen_ld_i64(r, cpu_env, offsetof(CPUState, regs[reg])); > + return r; > +#endif > +} I don't really like implicit TCGv temp allocation. In other targets it often has caused missing tcg_temp_free(). It should probably be rewritten as load_reg(TCGv t, int reg). > +static TCGv load_freg(int reg) > +{ > + TCGv r = tcg_temp_new_i64(); > + tcg_gen_ld_i64(r, cpu_env, offsetof(CPUState, fregs[reg].d)); > + return r; > +} > + > +static TCGv load_freg32(int reg) > +{ > + TCGv r = tcg_temp_new_i32(); > + tcg_gen_ld_i32(r, cpu_env, offsetof(CPUState, fregs[reg].e)); > + return r; > +} Should be of type TCGv_i32. > +static void load_reg32_var(TCGv r, int reg) > +{ > +#ifdef TCGREGS > + sync_reg64(reg); > + tcg_gen_mov_i32(r, tcgregs32[reg]); > +#else > +#ifdef WORDS_BIGENDIAN HOST_WORDS_BIGENDIAN ? > + tcg_gen_ld_i32(r, cpu_env, offsetof(CPUState, regs[reg]) + 4); > +#else > + tcg_gen_ld_i32(r, cpu_env, offsetof(CPUState, regs[reg])); > +#endif > +#endif > +} Should be of type TCGv_i32. > + > +static TCGv load_reg32(int reg) > +{ > + TCGv r = tcg_temp_new_i32(); > + load_reg32_var(r, reg); > + return r; > +} Should be of type TCGv_i32. > + > +static void store_reg(int reg, TCGv v) > +{ > +#ifdef TCGREGS > + sync_reg32(reg); > + tcg_gen_mov_i64(tcgregs[reg], v); > +#else > + tcg_gen_st_i64(v, cpu_env, offsetof(CPUState, regs[reg])); > +#endif > +} > + > +static void store_freg(int reg, TCGv v) > +{ > + tcg_gen_st_i64(v, cpu_env, offsetof(CPUState, fregs[reg].d)); > +} > + > +static void store_reg32(int reg, TCGv v) > +{ > +#ifdef TCGREGS > + sync_reg64(reg); > + tcg_gen_mov_i32(tcgregs32[reg], v); > +#else > +#ifdef WORDS_BIGENDIAN HOST_WORDS_BIGENDIAN ? > + tcg_gen_st_i32(v, cpu_env, offsetof(CPUState, regs[reg]) + 4); > +#else > + tcg_gen_st_i32(v, cpu_env, offsetof(CPUState, regs[reg])); > +#endif > +#endif This should use TCGv_i32. > +} > + > +static void store_reg8(int reg, TCGv v) > +{ > +#ifdef TCGREGS > + TCGv tmp = tcg_temp_new_i32(); > + sync_reg64(reg); > + tcg_gen_andi_i32(tmp, tcgregs32[reg], 0xffffff00UL); > + tcg_gen_or_i32(tcgregs32[reg], tmp, v); > + tcg_temp_free(tmp); > +#else > +#ifdef WORDS_BIGENDIAN HOST_WORDS_BIGENDIAN ? > + tcg_gen_st8_i32(v, cpu_env, offsetof(CPUState, regs[reg]) + 7); > +#else > + tcg_gen_st8_i32(v, cpu_env, offsetof(CPUState, regs[reg])); > +#endif > +#endif > +} This should use TCGv_i32. > + > +static void store_freg32(int reg, TCGv v) > +{ > + tcg_gen_st_i32(v, cpu_env, offsetof(CPUState, fregs[reg].e)); > +} This should use TCGv_i32. For all register load/store, as already explained in the TCG sync op patch, I am in favor of using the ld/st version (TCGREGS not defined). > + > +static void gen_illegal_opcode(DisasContext *s) > +{ > + TCGv tmp = tcg_temp_new_i64(); > + tcg_gen_movi_i64(tmp, 42); tcg_const_i64 could be used instead. > + gen_helper_exception(tmp); Missing tcg_temp_free_i64(tmp); > + s->is_jmp = DISAS_EXCP; > +} > + > +#define DEBUGINSN LOG_DISAS("insn: 0x%lx\n", insn); > + > +static TCGv get_address(int x2, int b2, int d2) > +{ > + TCGv tmp = 0,tmp2 = 0; > + if (d2) tmp = tcg_const_i64(d2); > + if (x2) { > + if (d2) { > + tmp2 = load_reg(x2); > + tcg_gen_add_i64(tmp, tmp, tmp2); > + tcg_temp_free(tmp2); > + } > + else { > + tmp = load_reg(x2); > + } > + } > + if (b2) { > + if (d2 || x2) { > + tmp2 = load_reg(b2); > + tcg_gen_add_i64(tmp, tmp, tmp2); > + tcg_temp_free(tmp2); > + } > + else { > + tmp = load_reg(b2); > + } > + } > + > + if (!(d2 || x2 || b2)) tmp = tcg_const_i64(0); > + > + return tmp; coding style > +} > + > +static inline void set_cc_nz_u32(TCGv val) > +{ > + gen_helper_set_cc_nz_u32(cc, val); > +} > + > +static inline void set_cc_nz_u64(TCGv val) > +{ > + gen_helper_set_cc_nz_u64(cc, val); > +} > + > +static inline void set_cc_s32(TCGv val) > +{ > + gen_helper_set_cc_s32(cc, val); > +} > + > +static inline void set_cc_s64(TCGv val) > +{ > + gen_helper_set_cc_s64(cc, val); > +} > + > +static inline void cmp_s32(TCGv v1, TCGv v2) > +{ > + gen_helper_cmp_s32(cc, v1, v2); > +} > + > +static inline void cmp_u32(TCGv v1, TCGv v2) > +{ > + gen_helper_cmp_u32(cc, v1, v2); > +} > + > +/* this is a hysterical raisin */ > +static inline void cmp_s32c(TCGv v1, int32_t v2) > +{ > + gen_helper_cmp_s32(cc, v1, tcg_const_i32(v2)); The TCG passed to the helper should be freed. > +} > +static inline void cmp_u32c(TCGv v1, uint32_t v2) > +{ > + gen_helper_cmp_u32(cc, v1, tcg_const_i32(v2)); Same. > +} > + > + > +static inline void cmp_s64(TCGv v1, TCGv v2) > +{ > + gen_helper_cmp_s64(cc, v1, v2); > +} > + > +static inline void cmp_u64(TCGv v1, TCGv v2) > +{ > + gen_helper_cmp_u64(cc, v1, v2); > +} > + > +/* see cmp_[su]32c() */ > +static inline void cmp_s64c(TCGv v1, int64_t v2) > +{ > + gen_helper_cmp_s64(cc, v1, tcg_const_i64(v2)); Same > +} > +static inline void cmp_u64c(TCGv v1, uint64_t v2) > +{ > + gen_helper_cmp_u64(cc, v1, tcg_const_i64(v2)); Same > +} > + > +static void gen_bcr(uint32_t mask, int tr, uint64_t offset) > +{ > + TCGv target; > + if (mask == 0xf) { /* unconditional */ > + target = load_reg(tr); > + tcg_gen_mov_i64(psw_addr, target); > + } > + else { > + gen_helper_bcr(cc, tcg_const_i32(mask), (target = load_reg(tr)), tcg_const_i64(offset)); > + } > + tcg_temp_free(target); > +} > + > +static void gen_brc(uint32_t mask, uint64_t pc, int32_t offset) > +{ > + if (mask == 0xf) { /* unconditional */ > + tcg_gen_movi_i64(psw_addr, pc + offset); > + } > + else { > + gen_helper_brc(cc, tcg_const_i32(mask), tcg_const_i64(pc), tcg_const_i32(offset)); > + } > +} The branches should be handled using brcond and goto_tb and exit_tb and not with helpers, to allow TB chaining. > +static void gen_set_cc_add64(TCGv v1, TCGv v2, TCGv vr) > +{ > + gen_helper_set_cc_add64(cc, v1, v2, vr); > +} > + > +static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) > +{ > + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; This is wrong. 0 maps to global 0 (env in your case). -1 should be used instead, or even better the TCGV_UNUSED macro. > + > + LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", op, r1, x2, b2, d2); > + tmp = get_address(x2, b2, d2); > + switch (op) { > + case 0x2: /* LTG R1,D2(X2,B2) [RXY] */ > + case 0x4: /* lg r1,d2(x2,b2) */ > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > + store_reg(r1, tmp2); > + if (op == 0x2) set_cc_s64(tmp2); coding style > + break; > + case 0x12: /* LT R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld32s(tmp2, tmp, 1); tcg_gen_qemu_ld32s loads a 32 bit value in the default size register, that is 64-bit here. > + store_reg32(r1, tmp2); > + set_cc_s32(tmp2); > + break; > + case 0xc: /* MSG R1,D2(X2,B2) [RXY] */ > + case 0x1c: /* MSGF R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + if (op == 0xc) { > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > + } > + else { > + tcg_gen_qemu_ld32s(tmp2, tmp, 1); > + tcg_gen_ext32s_i64(tmp2, tmp2); The sign extension is already done by qemu_ld32s > + } > + tmp = load_reg(r1); > + tcg_gen_mul_i64(tmp, tmp, tmp2); > + store_reg(r1, tmp); > + break; > + case 0xd: /* DSG R1,D2(X2,B2) [RXY] */ > + case 0x1d: /* DSGF R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + if (op == 0x1d) { > + tcg_gen_qemu_ld32s(tmp2, tmp, 1); > + tcg_gen_ext32s_i64(tmp2, tmp2); The sign extension is already done by qemu_ld32s > + } > + else { > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > + } > + tmp = load_reg(r1 + 1); > + tmp3 = tcg_temp_new_i64(); > + tcg_gen_div_i64(tmp3, tmp, tmp2); > + store_reg(r1 + 1, tmp3); > + tcg_gen_rem_i64(tmp3, tmp, tmp2); > + store_reg(r1, tmp3); > + break; > + case 0x8: /* AG R1,D2(X2,B2) [RXY] */ > + case 0xa: /* ALG R1,D2(X2,B2) [RXY] */ > + case 0x18: /* AGF R1,D2(X2,B2) [RXY] */ > + case 0x1a: /* ALGF R1,D2(X2,B2) [RXY] */ > + if (op == 0x1a) { > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + tcg_gen_ext32u_i64(tmp2, tmp2); The zero extension is already done by qemu_ld32u > + } > + else if (op == 0x18) { > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld32s(tmp2, tmp, 1); > + tcg_gen_ext32s_i64(tmp2, tmp2); The sign extension is already done by qemu_ld32s > + } > + else { coding style > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > + } > + tmp = load_reg(r1); > + tmp3 = tcg_temp_new_i64(); > + tcg_gen_add_i64(tmp3, tmp, tmp2); > + store_reg(r1, tmp3); > + switch (op) { > + case 0x8: case 0x18: gen_set_cc_add64(tmp, tmp2, tmp3); break; > + case 0xa: case 0x1a: gen_helper_set_cc_addu64(cc, tmp, tmp2, tmp3); break; > + default: tcg_abort(); tcg_abort() is wrong here, it is for internal TCG use. Also all the real CPU it probably launch an illegal instruction exception, it does not power off the machin. > + } > + break; > + case 0x9: /* SG R1,D2(X2,B2) [RXY] */ > + case 0xb: /* SLG R1,D2(X2,B2) [RXY] */ > + case 0x19: /* SGF R1,D2(X2,B2) [RXY] */ > + case 0x1b: /* SLGF R1,D2(X2,B2) [RXY] */ > + if (op == 0x19) { > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld32s(tmp2, tmp, 1); > + tcg_gen_ext32s_i64(tmp2, tmp2); The sign extension is already done by qemu_ld32s > + } > + else if (op == 0x1b) { > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + tcg_gen_ext32u_i64(tmp2, tmp2); The zero extension is already done by qemu_ld32u > + } > + else { > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > + } > + tmp = load_reg(r1); > + tmp3 = tcg_temp_new_i64(); > + tcg_gen_sub_i64(tmp3, tmp, tmp2); > + store_reg(r1, tmp3); > + switch (op) { > + case 0x9: case 0x19: gen_helper_set_cc_sub64(cc, tmp, tmp2, tmp3); break; > + case 0xb: case 0x1b: gen_helper_set_cc_subu64(cc, tmp, tmp2, tmp3); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + break; > + case 0x14: /* LGF R1,D2(X2,B2) [RXY] */ > + case 0x16: /* LLGF R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + switch (op) { > + case 0x14: tcg_gen_ext32s_i64(tmp2, tmp2); break; > + case 0x16: tcg_gen_ext32u_i64(tmp2, tmp2); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg(r1, tmp2); > + break; > + case 0x15: /* LGH R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld16s(tmp2, tmp, 1); > + tcg_gen_ext16s_i64(tmp2, tmp2); > + store_reg(r1, tmp2); > + break; > + case 0x17: /* LLGT R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + tcg_gen_ext32u_i64(tmp2, tmp2); The zero extension is already done by qemu_ld32u > + tcg_gen_andi_i64(tmp2, tmp2, 0x7fffffffULL); > + store_reg(r1, tmp2); > + break; > + case 0x1e: /* LRV R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type; > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + tcg_gen_bswap32_i32(tmp2, tmp2); Wrong TCGv type; > + store_reg(r1, tmp2); > + break; > + case 0x20: /* CG R1,D2(X2,B2) [RXY] */ > + case 0x21: /* CLG R1,D2(X2,B2) */ > + case 0x30: /* CGF R1,D2(X2,B2) [RXY] */ > + case 0x31: /* CLGF R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + switch (op) { > + case 0x20: > + case 0x21: > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > + break; > + case 0x30: > + tcg_gen_qemu_ld32s(tmp2, tmp, 1); > + tcg_gen_ext32s_i64(tmp2, tmp2); The zero extension is already done by qemu_ld32s > + break; > + case 0x31: > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + tcg_gen_ext32u_i64(tmp2, tmp2); The zero extension is already done by qemu_ld32u > + break; > + default: > + tcg_abort(); Same comment as previous tcg_abort() one. > + } > + tmp = load_reg(r1); > + switch (op) { > + case 0x20: case 0x30: cmp_s64(tmp, tmp2); break; > + case 0x21: case 0x31: cmp_u64(tmp, tmp2); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + break; > + case 0x24: /* stg r1, d2(x2,b2) */ > + tmp2 = load_reg(r1); > + tcg_gen_qemu_st64(tmp2, tmp, 1); > + break; > + case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */ > + tmp2 = load_reg32(r1); > + tcg_gen_bswap32_i32(tmp2, tmp2); > + tcg_gen_qemu_st32(tmp2, tmp, 1); Wrong TCGv type. > + break; > + case 0x50: /* STY R1,D2(X2,B2) [RXY] */ > + tmp2 = load_reg32(r1); > + tcg_gen_qemu_st32(tmp2, tmp, 1); Wrong TCGv type. > + break; > + case 0x57: /* XY R1,D2(X2,B2) [RXY] */ > + tmp2 = load_reg32(r1); > + tmp3 = tcg_temp_new_i32(); > + tcg_gen_qemu_ld32u(tmp3, tmp, 1); > + tcg_gen_xor_i32(tmp, tmp2, tmp3); > + store_reg32(r1, tmp); > + set_cc_nz_u32(tmp); Wrong TCGv type. > + break; > + case 0x58: /* LY R1,D2(X2,B2) [RXY] */ > + tmp3 = tcg_temp_new_i32(); > + tcg_gen_qemu_ld32u(tmp3, tmp, 1); > + store_reg32(r1, tmp3); Wrong TCGv type. > + break; > + case 0x5a: /* AY R1,D2(X2,B2) [RXY] */ > + case 0x5b: /* SY R1,D2(X2,B2) [RXY] */ > + tmp2 = load_reg32(r1); > + tmp3 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld32s(tmp3, tmp, 1); > + switch (op) { > + case 0x5a: tcg_gen_add_i32(tmp, tmp2, tmp3); break; > + case 0x5b: tcg_gen_sub_i32(tmp, tmp2, tmp3); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg32(r1, tmp); > + switch (op) { > + case 0x5a: gen_helper_set_cc_add32(cc, tmp2, tmp3, tmp); break; > + case 0x5b: gen_helper_set_cc_sub32(cc, tmp2, tmp3, tmp); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + break; > + case 0x71: /* LAY R1,D2(X2,B2) [RXY] */ > + store_reg(r1, tmp); > + break; > + case 0x72: /* STCY R1,D2(X2,B2) [RXY] */ > + tmp2 = load_reg32(r1); > + tcg_gen_qemu_st8(tmp2, tmp, 1); > + break; > + case 0x73: /* ICY R1,D2(X2,B2) [RXY] */ > + tmp3 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld8u(tmp3, tmp, 1); > + store_reg8(r1, tmp3); > + break; > + case 0x76: /* LB R1,D2(X2,B2) [RXY] */ > + case 0x77: /* LGB R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld8s(tmp2, tmp, 1); > + switch (op) { > + case 0x76: > + tcg_gen_ext8s_i32(tmp2, tmp2); Wrong TCGv type. > + store_reg32(r1, tmp2); > + break; > + case 0x77: > + tcg_gen_ext8s_i64(tmp2, tmp2); Wrong TCGv type. > + store_reg(r1, tmp2); > + break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + break; > + case 0x78: /* LHY R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld16s(tmp2, tmp, 1); > + tcg_gen_ext16s_i32(tmp2, tmp2); > + store_reg32(r1, tmp2); > + break; > + case 0x80: /* NG R1,D2(X2,B2) [RXY] */ > + case 0x81: /* OG R1,D2(X2,B2) [RXY] */ > + case 0x82: /* XG R1,D2(X2,B2) [RXY] */ > + tmp2 = load_reg(r1); > + tmp3 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld64(tmp3, tmp, 1); > + switch (op) { > + case 0x80: tcg_gen_and_i64(tmp, tmp2, tmp3); break; > + case 0x81: tcg_gen_or_i64(tmp, tmp2, tmp3); break; > + case 0x82: tcg_gen_xor_i64(tmp, tmp2, tmp3); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg(r1, tmp); > + set_cc_nz_u64(tmp); > + break; > + case 0x86: /* MLG R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > + tmp = tcg_const_i32(r1); Wrong TCGv type. > + gen_helper_mlg(tmp, tmp2); > + break; > + case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > + tmp = tcg_const_i32(r1); Wrong TCGv type. > + gen_helper_dlg(tmp, tmp2); > + break; > + case 0x88: /* ALCG R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > + tmp = load_reg(r1); > + tmp3 = tcg_temp_new_i64(); > + tcg_gen_shri_i64(tmp3, cc, 1); > + tcg_gen_andi_i64(tmp3, tmp3, 1); > + tcg_gen_add_i64(tmp3, tmp2, tmp3);; > + tcg_gen_add_i64(tmp3, tmp, tmp3); > + store_reg(r1, tmp3); > + gen_helper_set_cc_addc_u64(cc, tmp, tmp2, tmp3); > + break; > + case 0x89: /* SLBG R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > + tmp = load_reg(r1); > + tmp3 = tcg_const_i32(r1); Wrong TCGv type. > + gen_helper_slbg(cc, cc, tmp3, tmp, tmp2); > + break; > + case 0x90: /* LLGC R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld8u(tmp2, tmp, 1); > + store_reg(r1, tmp2); > + break; > + case 0x91: /* LLGH R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld16u(tmp2, tmp, 1); > + store_reg(r1, tmp2); > + break; > + case 0x94: /* LLC R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld8u(tmp2, tmp, 1); > + store_reg32(r1, tmp2); > + break; > + case 0x95: /* LLH R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i32(); > + tcg_gen_qemu_ld16u(tmp2, tmp, 1); > + store_reg32(r1, tmp2); > + break; > + case 0x98: /* ALC R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + tmp = tcg_const_i32(r1); > + gen_helper_addc_u32(cc, cc, tmp, tmp2); > + break; > + case 0x99: /* SLB R1,D2(X2,B2) [RXY] */ > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + tmp = load_reg32(r1); > + tmp3 = tcg_const_i32(r1); > + gen_helper_slb(cc, cc, tmp3, tmp, tmp2); > + break; > + default: > + LOG_DISAS("illegal e3 operation 0x%x\n", op); > + gen_illegal_opcode(s); > + break; > + } > + tcg_temp_free(tmp); > + if (tmp2) tcg_temp_free(tmp2); > + if (tmp3) tcg_temp_free(tmp3); Comparison on TCGv type is not allowed. > +} > + > +static void disas_eb(DisasContext *s, int op, int r1, int r3, int b2, int d2) > +{ > + TCGv tmp = 0,tmp2 = 0,tmp3 = 0,tmp4 = 0; Same comment as in the previous function. 0 maps to a global. > + int i; > + > + LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); > + switch (op) { > + case 0xc: /* SRLG R1,R3,D2(B2) [RSY] */ > + case 0xd: /* SLLG R1,R3,D2(B2) [RSY] */ > + case 0xa: /* SRAG R1,R3,D2(B2) [RSY] */ > + case 0x1c: /* RLLG R1,R3,D2(B2) [RSY] */ > + if (b2) { > + tmp = get_address(0, b2, d2); > + tcg_gen_andi_i64(tmp, tmp, 0x3f); > + } coding style > + else tmp = tcg_const_i32(d2 & 0x3f); Wrong TCGv type. > + tmp2 = load_reg(r3); > + tmp3 = tcg_temp_new_i64(); > + switch (op) { > + case 0xc: tcg_gen_shr_i64(tmp3, tmp2, tmp); break; > + case 0xd: tcg_gen_shl_i64(tmp3, tmp2, tmp); break; > + case 0xa: tcg_gen_sar_i64(tmp3, tmp2, tmp); break; > + case 0x1c: tcg_gen_rotl_i64(tmp3, tmp2, tmp); break; > + default: tcg_abort(); break; Same comment as previous tcg_abort() one. > + } > + store_reg(r1, tmp3); > + if (op == 0xa) set_cc_s64(tmp3); > + break; > + case 0x1d: /* RLL R1,R3,D2(B2) [RSY] */ > + if (b2) { > + tmp = get_address(0, b2, d2); > + tcg_gen_andi_i64(tmp, tmp, 0x3f); > + } > + else tmp = tcg_const_i32(d2 & 0x3f); > + tmp2 = load_reg32(r3); > + tmp3 = tcg_temp_new_i32(); Wrong TCGv type. > + switch (op) { > + case 0x1d: tcg_gen_rotl_i32(tmp3, tmp2, tmp); break; > + default: tcg_abort(); break; Same comment as previous tcg_abort() one. > + } > + store_reg32(r1, tmp3); > + break; > + case 0x4: /* LMG R1,R3,D2(B2) [RSY] */ > + case 0x24: /* stmg */ > + /* Apparently, unrolling lmg/stmg of any size gains performance - > + even for very long ones... */ > + if (r3 > r1) { > + tmp = get_address(0, b2, d2); > + for (i = r1; i <= r3; i++) { > + if (op == 0x4) { > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > + store_reg(i, tmp2); > + /* At least one register is usually read after an lmg > + (br %rsomething), which is why freeing them is > + detrimental to performance */ > + } > + else { > + tmp2 = load_reg(i); > + tcg_gen_qemu_st64(tmp2, tmp, 1); > + /* R15 is usually read after an stmg; other registers > + generally aren't and can be free'd */ > + if (i != 15) tcg_temp_free(tmp2); > + } > + tcg_gen_addi_i64(tmp, tmp, 8); > + } > + tmp2 = 0; > + } > + else { > + tmp = tcg_const_i32(r1); > + tmp2 = tcg_const_i32(r3); > + tmp3 = tcg_const_i32(b2); > + tmp4 = tcg_const_i32(d2); Wrong TCGv type. > + if (op == 0x4) gen_helper_lmg(tmp, tmp2, tmp3, tmp4); > + else gen_helper_stmg(tmp, tmp2, tmp3, tmp4); > + } > + break; > + case 0x2c: /* STCMH R1,M3,D2(B2) [RSY] */ > + tmp2 = get_address(0, b2, d2); > + tmp = tcg_const_i32(r1); > + tmp3 = tcg_const_i32(r3); Wrong TCGv type. > + gen_helper_stcmh(cc, tmp, tmp2, tmp3); > + break; > + case 0x30: /* CSG R1,R3,D2(B2) [RSY] */ > + tmp2 = get_address(0, b2, d2); > + tmp = tcg_const_i32(r1); > + tmp3 = tcg_const_i32(r3); Wrong TCGv type. > + gen_helper_csg(cc, tmp, tmp2, tmp3); > + break; > + case 0x3e: /* CDSG R1,R3,D2(B2) [RSY] */ > + tmp2 = get_address(0, b2, d2); > + tmp = tcg_const_i32(r1); > + tmp3 = tcg_const_i32(r3); Wrong TCGv type. > + gen_helper_cdsg(cc, tmp, tmp2, tmp3); > + break; > + case 0x51: /* TMY D1(B1),I2 [SIY] */ > + tmp = get_address(0, b2, d2); /* SIY -> this is the destination */ > + tmp2 = tcg_temp_new_i32(); > + tcg_gen_qemu_ld8u(tmp2, tmp, 1); > + tmp = tcg_const_i32((r1 << 4) | r3); Wrong TCGv type. > + gen_helper_tm(cc, tmp2, tmp); > + break; > + case 0x52: /* MVIY D1(B1),I2 [SIY] */ > + tmp2 = tcg_const_i32((r1 << 4) | r3); Wrong TCGv type. > + tmp = get_address(0, b2, d2); /* SIY -> this is the destination */ > + tcg_gen_qemu_st8(tmp2, tmp, 1); > + break; > + case 0x55: /* CLIY D1(B1),I2 [SIY] */ > + tmp3 = get_address(0, b2, d2); /* SIY -> this is the 1st operand */ > + tmp = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld8u(tmp, tmp3, 1); > + cmp_u32c(tmp, (r1 << 4) | r3); > + break; > + case 0x80: /* ICMH R1,M3,D2(B2) [RSY] */ > + tmp2 = get_address(0, b2, d2); > + tmp = tcg_const_i32(r1); > + tmp3 = tcg_const_i32(r3); Wrong TCGv type. > + gen_helper_icmh(cc, tmp, tmp2, tmp3); > + break; > + default: > + LOG_DISAS("illegal eb operation 0x%x\n", op); > + gen_illegal_opcode(s); > + break; > + } > + if (tmp) tcg_temp_free(tmp); > + if (tmp2) tcg_temp_free(tmp2); > + if (tmp3) tcg_temp_free(tmp3); > + if (tmp4) tcg_temp_free(tmp4); Comparison on TCGv type is not allowed. > +} > + > +static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, int r1b) > +{ > + TCGv tmp, tmp2, tmp3 = 0; tmp should be declared as TGV_i32 here, so that the types are correct for the whole function. Also tmp3 should not be initialized to 0. > + tmp2 = get_address(x2, b2, d2); > + tmp = tcg_const_i32(r1); > + switch (op) { > + case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */ > + gen_helper_lxdb(tmp, tmp2); > + break; > + case 0x9: /* CEB R1,D2(X2,B2) [RXE] */ > + gen_helper_ceb(cc, tmp, tmp2); > + break; > + case 0xa: /* AEB R1,D2(X2,B2) [RXE] */ > + gen_helper_aeb(cc, tmp, tmp2); > + break; > + case 0xb: /* SEB R1,D2(X2,B2) [RXE] */ > + gen_helper_seb(cc, tmp, tmp2); > + break; > + case 0xd: /* DEB R1,D2(X2,B2) [RXE] */ > + gen_helper_deb(tmp, tmp2); > + break; > + case 0x10: /* TCEB R1,D2(X2,B2) [RXE] */ > + gen_helper_tceb(cc, tmp, tmp2); > + break; > + case 0x11: /* TCDB R1,D2(X2,B2) [RXE] */ > + gen_helper_tcdb(cc, tmp, tmp2); > + break; > + case 0x12: /* TCXB R1,D2(X2,B2) [RXE] */ > + gen_helper_tcxb(cc, tmp, tmp2); > + break; > + case 0x17: /* MEEB R1,D2(X2,B2) [RXE] */ > + gen_helper_meeb(tmp, tmp2); > + break; > + case 0x19: /* CDB R1,D2(X2,B2) [RXE] */ > + gen_helper_cdb(cc, tmp, tmp2); > + break; > + case 0x1a: /* ADB R1,D2(X2,B2) [RXE] */ > + gen_helper_adb(cc, tmp, tmp2); > + break; > + case 0x1b: /* SDB R1,D2(X2,B2) [RXE] */ > + gen_helper_sdb(cc, tmp, tmp2); > + break; > + case 0x1c: /* MDB R1,D2(X2,B2) [RXE] */ > + gen_helper_mdb(tmp, tmp2); > + break; > + case 0x1d: /* DDB R1,D2(X2,B2) [RXE] */ > + gen_helper_ddb(tmp, tmp2); > + break; > + case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ > + /* for RXF insns, r1 is R3 and r1b is R1 */ > + tmp3 = tcg_const_i32(r1b); > + gen_helper_madb(tmp3, tmp2, tmp); tmp3 should be freed after the helper. > + break; > + default: > + LOG_DISAS("illegal ed operation 0x%x\n", op); > + gen_illegal_opcode(s); > + break; > + } > + tcg_temp_free(tmp); > + tcg_temp_free(tmp2); > +} > + > +static void disas_a5(DisasContext *s, int op, int r1, int i2) > +{ > + TCGv tmp = 0,tmp2 = 0; Same. > + uint64_t vtmp; > + LOG_DISAS("disas_a5: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); > + switch (op) { > + case 0x0: /* IIHH R1,I2 [RI] */ > + case 0x1: /* IIHL R1,I2 [RI] */ > + tmp = load_reg(r1); > + vtmp = i2; > + switch (op) { > + case 0x0: tcg_gen_andi_i64(tmp, tmp, 0x0000ffffffffffffULL); vtmp <<= 48; break; > + case 0x1: tcg_gen_andi_i64(tmp, tmp, 0xffff0000ffffffffULL); vtmp <<= 32; break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + tcg_gen_ori_i64(tmp, tmp, vtmp); > + store_reg(r1, tmp); > + break; > + case 0x4: /* NIHH R1,I2 [RI] */ > + case 0x8: /* OIHH R1,I2 [RI] */ > + tmp = load_reg(r1); > + switch (op) { > + case 0x4: > + tmp2 = tcg_const_i64( (((uint64_t)i2) << 48) | 0x0000ffffffffffffULL); > + tcg_gen_and_i64(tmp, tmp, tmp2); > + break; > + case 0x8: > + tmp2 = tcg_const_i64(((uint64_t)i2) << 48); > + tcg_gen_or_i64(tmp, tmp, tmp2); > + break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg(r1, tmp); > + tcg_gen_shri_i64(tmp2, tmp, 48); > + tcg_gen_trunc_i64_i32(tmp2, tmp2); Wrong TCGv type. > + set_cc_nz_u32(tmp2); > + break; > + case 0x5: /* NIHL R1,I2 [RI] */ > + case 0x9: /* OIHL R1,I2 [RI] */ > + tmp = load_reg(r1); > + switch (op) { > + case 0x5: > + tmp2 = tcg_const_i64( (((uint64_t)i2) << 32) | 0xffff0000ffffffffULL); > + tcg_gen_and_i64(tmp, tmp, tmp2); > + break; > + case 0x9: > + tmp2 = tcg_const_i64(((uint64_t)i2) << 32); > + tcg_gen_or_i64(tmp, tmp, tmp2); > + break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg(r1, tmp); > + tcg_gen_shri_i64(tmp2, tmp, 32); > + tcg_gen_trunc_i64_i32(tmp2, tmp2); Wrong TCGv type. > + tcg_gen_andi_i32(tmp2, tmp2, 0xffff); > + set_cc_nz_u32(tmp2); > + break; > + case 0x6: /* NILH R1,I2 [RI] */ > + case 0xa: /* OILH R1,I2 [RI] */ > + tmp = load_reg(r1); > + switch (op) { > + case 0x6: > + tmp2 = tcg_const_i64( (((uint64_t)i2) << 16) | 0xffffffff0000ffffULL); > + tcg_gen_and_i64(tmp, tmp, tmp2); > + break; > + case 0xa: > + tmp2 = tcg_const_i64(((uint64_t)i2) << 16); > + tcg_gen_or_i64(tmp, tmp, tmp2); > + break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg(r1, tmp); > + tcg_gen_shri_i64(tmp2, tmp, 16); > + tcg_gen_trunc_i64_i32(tmp2, tmp2); > + tcg_gen_andi_i32(tmp2, tmp2, 0xffff); Wrong TCGv type. > + set_cc_nz_u32(tmp2); > + break; > + case 0x7: /* NILL R1,I2 [RI] */ > + case 0xb: /* OILL R1,I2 [RI] */ > + tmp = load_reg(r1); > + switch (op) { > + case 0x7: > + tmp2 = tcg_const_i64(i2 | 0xffffffffffff0000ULL); > + tcg_gen_and_i64(tmp, tmp, tmp2); > + break; > + case 0xb: > + tmp2 = tcg_const_i64(i2); > + tcg_gen_or_i64(tmp, tmp, tmp2); > + break; > + default: tcg_abort(); break; > + } > + store_reg(r1, tmp); > + tcg_gen_trunc_i64_i32(tmp, tmp); > + tcg_gen_andi_i32(tmp, tmp, 0xffff); Wrong TCGv type. > + set_cc_nz_u32(tmp); /* signedness should not matter here */ > + break; > + case 0xc: /* LLIHH R1,I2 [RI] */ > + tmp = tcg_const_i64( ((uint64_t)i2) << 48 ); > + store_reg(r1, tmp); > + break; > + case 0xd: /* LLIHL R1,I2 [RI] */ > + tmp = tcg_const_i64( ((uint64_t)i2) << 32 ); > + store_reg(r1, tmp); > + break; > + case 0xe: /* LLILH R1,I2 [RI] */ > + tmp = tcg_const_i64( ((uint64_t)i2) << 16 ); > + store_reg(r1, tmp); > + break; > + case 0xf: /* LLILL R1,I2 [RI] */ > + tmp = tcg_const_i64(i2); > + store_reg(r1, tmp); > + break; > + default: > + LOG_DISAS("illegal a5 operation 0x%x\n", op); > + gen_illegal_opcode(s); > + break; > + } > + if (tmp) tcg_temp_free(tmp); > + if (tmp2) tcg_temp_free(tmp2); Comparison on TCGv type is not allowed. > +} > + > +static void disas_a7(DisasContext *s, int op, int r1, int i2) > +{ > + TCGv tmp = 0,tmp2 = 0,tmp3 = 0; Same > + LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); > + switch (op) { > + case 0x0: /* TMLH or TMH R1,I2 [RI] */ > + tmp = load_reg(r1); > + tcg_gen_shri_i64(tmp, tmp, 16); > + tmp2 = tcg_const_i32((uint16_t)i2); Wrong TCGv type. > + gen_helper_tmxx(cc, tmp, tmp2); > + break; > + case 0x1: /* TMLL or TML R1,I2 [RI] */ > + tmp = load_reg(r1); > + tmp2 = tcg_const_i32((uint16_t)i2); Wrong TCGv type. > + gen_helper_tmxx(cc, tmp, tmp2); > + break; > + case 0x2: /* TMHH R1,I2 [RI] */ > + tmp = load_reg(r1); > + tcg_gen_shri_i64(tmp, tmp, 48); > + tmp2 = tcg_const_i32((uint16_t)i2); Wrong TCGv type. > + gen_helper_tmxx(cc, tmp, tmp2); > + break; > + case 0x3: /* TMHL R1,I2 [RI] */ > + tmp = load_reg(r1); > + tcg_gen_shri_i64(tmp, tmp, 32); > + tmp2 = tcg_const_i32((uint16_t)i2); Wrong TCGv type. > + gen_helper_tmxx(cc, tmp, tmp2); > + break; > + case 0x4: /* brc m1, i2 */ > + /* FIXME: optimize m1 == 0xf (unconditional) case */ > + gen_brc(r1, s->pc, i2 * 2); > + s->is_jmp = DISAS_JUMP; > + break; > + case 0x5: /* BRAS R1,I2 [RI] */ > + tmp = tcg_const_i64(s->pc + 4); > + store_reg(r1, tmp); > + tmp = tcg_const_i64(s->pc + i2 * 2); > + tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, psw.addr)); > + s->is_jmp = DISAS_JUMP; > + break; > + case 0x6: /* BRCT R1,I2 [RI] */ > + tmp = load_reg32(r1); > + tcg_gen_subi_i32(tmp, tmp, 1); > + store_reg32(r1, tmp); > + tmp2 = tcg_const_i64(s->pc); > + tmp3 = tcg_const_i32(i2 * 2); Wrong TCGv type. > + gen_helper_brct(tmp, tmp2, tmp3); > + s->is_jmp = DISAS_JUMP; > + break; > + case 0x7: /* BRCTG R1,I2 [RI] */ > + tmp = load_reg(r1); > + tcg_gen_subi_i64(tmp, tmp, 1); > + store_reg(r1, tmp); > + tmp2 = tcg_const_i64(s->pc); > + tmp3 = tcg_const_i32(i2 * 2); Wrong TCGv type. > + gen_helper_brctg(tmp, tmp2, tmp3); > + s->is_jmp = DISAS_JUMP; > + break; > + case 0x8: /* lhi r1, i2 */ > + tmp = tcg_const_i32(i2); Wrong TCGv type. > + store_reg32(r1, tmp); > + break; > + case 0x9: /* lghi r1, i2 */ > + tmp = tcg_const_i64(i2); > + store_reg(r1, tmp); > + break; > + case 0xa: /* AHI R1,I2 [RI] */ > + tmp = load_reg32(r1); > + tmp3 = tcg_temp_new_i32(); > + tcg_gen_addi_i32(tmp3, tmp, i2); > + store_reg32(r1, tmp3); > + tmp2 = tcg_const_i32(i2); Wrong TCGv type. > + gen_helper_set_cc_add32(cc, tmp, tmp2, tmp3); > + break; > + case 0xb: /* aghi r1, i2 */ > + tmp = load_reg(r1); > + tmp3 = tcg_temp_new_i64(); > + tcg_gen_addi_i64(tmp3, tmp, i2); > + store_reg(r1, tmp3); > + tmp2 = tcg_const_i64(i2); > + gen_set_cc_add64(tmp, tmp2, tmp3); > + break; > + case 0xc: /* MHI R1,I2 [RI] */ > + tmp = load_reg32(r1); > + tcg_gen_muli_i32(tmp, tmp, i2); Wrong TCGv type. > + store_reg32(r1, tmp); > + break; > + case 0xd: /* MGHI R1,I2 [RI] */ > + tmp = load_reg(r1); > + tcg_gen_muli_i64(tmp, tmp, i2); > + store_reg(r1, tmp); > + break; > + case 0xe: /* CHI R1,I2 [RI] */ > + tmp = load_reg32(r1); > + cmp_s32c(tmp, i2); > + break; > + case 0xf: /* CGHI R1,I2 [RI] */ > + tmp = load_reg(r1); > + cmp_s64c(tmp, i2); > + break; > + default: > + LOG_DISAS("illegal a7 operation 0x%x\n", op); > + gen_illegal_opcode(s); > + break; > + } > + if (tmp) tcg_temp_free(tmp); > + if (tmp2) tcg_temp_free(tmp2); > + if (tmp3) tcg_temp_free(tmp3); Comparison on TCGv type is not allowed. > +} > + > +static void disas_b2(DisasContext *s, int op, int r1, int r2) > +{ > + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; The three should be of type TCGv_i32 and not initialized to 0 > + LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); > + switch (op) { > + case 0x22: /* IPM R1 [RRE] */ > + tmp = tcg_const_i32(r1); > + gen_helper_ipm(cc, tmp); > + break; > + case 0x4e: /* SAR R1,R2 [RRE] */ > + tmp = load_reg32(r2); > + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, aregs[r1])); > + break; > + case 0x4f: /* EAR R1,R2 [RRE] */ > + tmp = tcg_temp_new_i32(); > + tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, aregs[r2])); > + store_reg32(r1, tmp); > + break; > + case 0x52: /* MSR R1,R2 [RRE] */ > + tmp = load_reg32(r1); > + tmp2 = load_reg32(r2); > + tcg_gen_mul_i32(tmp, tmp, tmp2); > + store_reg32(r1, tmp); > + break; > + case 0x55: /* MVST R1,R2 [RRE] */ > + tmp = load_reg32(0); > + tmp2 = tcg_const_i32(r1); > + tmp3 = tcg_const_i32(r2); > + gen_helper_mvst(cc, tmp, tmp2, tmp3); > + break; > + case 0x5d: /* CLST R1,R2 [RRE] */ > + tmp = load_reg32(0); > + tmp2 = tcg_const_i32(r1); > + tmp3 = tcg_const_i32(r2); > + gen_helper_clst(cc, tmp, tmp2, tmp3); > + break; > + case 0x5e: /* SRST R1,R2 [RRE] */ > + tmp = load_reg32(0); > + tmp2 = tcg_const_i32(r1); > + tmp3 = tcg_const_i32(r2); > + gen_helper_srst(cc, tmp, tmp2, tmp3); > + break; > + default: > + LOG_DISAS("illegal b2 operation 0x%x\n", op); > + gen_illegal_opcode(s); > + break; > + } > + if (tmp) tcg_temp_free(tmp); > + if (tmp2) tcg_temp_free(tmp2); > + if (tmp3) tcg_temp_free(tmp3); Comparison on TCGv type is not allowed. > +} > + > +static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) > +{ > + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; The three should be of type TCGv_i32 and not initialized to 0 > + LOG_DISAS("disas_b3: op 0x%x m3 0x%x r1 %d r2 %d\n", op, m3, r1, r2); > +#define FP_HELPER(i) \ > + tmp = tcg_const_i32(r1); \ > + tmp2 = tcg_const_i32(r2); \ > + gen_helper_ ## i (tmp, tmp2); > +#define FP_HELPER_CC(i) \ > + tmp = tcg_const_i32(r1); \ > + tmp2 = tcg_const_i32(r2); \ > + gen_helper_ ## i (cc, tmp, tmp2); > + > + switch (op) { > + case 0x0: /* LPEBR R1,R2 [RRE] */ > + FP_HELPER_CC(lpebr); break; > + case 0x2: /* LTEBR R1,R2 [RRE] */ > + FP_HELPER_CC(ltebr); break; > + case 0x3: /* LCEBR R1,R2 [RRE] */ > + FP_HELPER_CC(lcebr); break; > + case 0x4: /* LDEBR R1,R2 [RRE] */ > + FP_HELPER(ldebr); break; > + case 0x5: /* LXDBR R1,R2 [RRE] */ > + FP_HELPER(lxdbr); break; > + case 0x9: /* CEBR R1,R2 [RRE] */ > + FP_HELPER_CC(cebr); break; > + case 0xa: /* AEBR R1,R2 [RRE] */ > + FP_HELPER_CC(aebr); break; > + case 0xb: /* SEBR R1,R2 [RRE] */ > + FP_HELPER_CC(sebr); break; > + case 0xd: /* DEBR R1,R2 [RRE] */ > + FP_HELPER(debr); break; > + case 0x10: /* LPDBR R1,R2 [RRE] */ > + FP_HELPER_CC(lpdbr); break; > + case 0x12: /* LTDBR R1,R2 [RRE] */ > + FP_HELPER_CC(ltdbr); break; > + case 0x13: /* LCDBR R1,R2 [RRE] */ > + FP_HELPER_CC(lcdbr); break; > + case 0x15: /* SQBDR R1,R2 [RRE] */ > + FP_HELPER(sqdbr); break; > + case 0x17: /* MEEBR R1,R2 [RRE] */ > + FP_HELPER(meebr); break; > + case 0x19: /* CDBR R1,R2 [RRE] */ > + FP_HELPER_CC(cdbr); break; > + case 0x1a: /* ADBR R1,R2 [RRE] */ > + FP_HELPER_CC(adbr); break; > + case 0x1b: /* SDBR R1,R2 [RRE] */ > + FP_HELPER_CC(sdbr); break; > + case 0x1c: /* MDBR R1,R2 [RRE] */ > + FP_HELPER(mdbr); break; > + case 0x1d: /* DDBR R1,R2 [RRE] */ > + FP_HELPER(ddbr); break; > + case 0xe: /* MAEBR R1,R3,R2 [RRF] */ > + case 0x1e: /* MADBR R1,R3,R2 [RRF] */ > + case 0x1f: /* MSDBR R1,R3,R2 [RRF] */ > + /* for RRF insns, m3 is R1, r1 is R3, and r2 is R2 */ > + tmp = tcg_const_i32(m3); > + tmp2 = tcg_const_i32(r2); > + tmp3 = tcg_const_i32(r1); > + switch (op) { > + case 0xe: gen_helper_maebr(tmp, tmp3, tmp2); break; > + case 0x1e: gen_helper_madbr(tmp, tmp3, tmp2); break; > + case 0x1f: gen_helper_msdbr(tmp, tmp3, tmp2); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + break; > + case 0x40: /* LPXBR R1,R2 [RRE] */ > + FP_HELPER_CC(lpxbr); break; > + case 0x42: /* LTXBR R1,R2 [RRE] */ > + FP_HELPER_CC(ltxbr); break; > + case 0x43: /* LCXBR R1,R2 [RRE] */ > + FP_HELPER_CC(lcxbr); break; > + case 0x44: /* LEDBR R1,R2 [RRE] */ > + FP_HELPER(ledbr); break; > + case 0x45: /* LDXBR R1,R2 [RRE] */ > + FP_HELPER(ldxbr); break; > + case 0x46: /* LEXBR R1,R2 [RRE] */ > + FP_HELPER(lexbr); break; > + case 0x49: /* CXBR R1,R2 [RRE] */ > + FP_HELPER_CC(cxbr); break; > + case 0x4a: /* AXBR R1,R2 [RRE] */ > + FP_HELPER_CC(axbr); break; > + case 0x4b: /* SXBR R1,R2 [RRE] */ > + FP_HELPER_CC(sxbr); break; > + case 0x4c: /* MXBR R1,R2 [RRE] */ > + FP_HELPER(mxbr); break; > + case 0x4d: /* DXBR R1,R2 [RRE] */ > + FP_HELPER(dxbr); break; > + case 0x65: /* LXR R1,R2 [RRE] */ > + tmp = load_freg(r2); > + store_freg(r1, tmp); > + tmp = load_freg(r2 + 2); > + store_freg(r1 + 2, tmp); > + break; > + case 0x74: /* LZER R1 [RRE] */ > + tmp = tcg_const_i32(r1); > + gen_helper_lzer(tmp); > + break; > + case 0x75: /* LZDR R1 [RRE] */ > + tmp = tcg_const_i32(r1); > + gen_helper_lzdr(tmp); > + break; > + case 0x76: /* LZXR R1 [RRE] */ > + tmp = tcg_const_i32(r1); > + gen_helper_lzxr(tmp); > + break; > + case 0x84: /* SFPC R1 [RRE] */ > + tmp = load_reg32(r1); > + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, fpc)); > + break; > + case 0x8c: /* EFPC R1 [RRE] */ > + tmp = tcg_temp_new_i32(); > + tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, fpc)); > + store_reg32(r1, tmp); > + break; > + case 0x94: /* CEFBR R1,R2 [RRE] */ > + case 0x95: /* CDFBR R1,R2 [RRE] */ > + case 0x96: /* CXFBR R1,R2 [RRE] */ > + tmp = tcg_const_i32(r1); > + tmp2 = load_reg32(r2); > + switch (op) { > + case 0x94: gen_helper_cefbr(tmp, tmp2); break; > + case 0x95: gen_helper_cdfbr(tmp, tmp2); break; > + case 0x96: gen_helper_cxfbr(tmp, tmp2); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + break; > + case 0x98: /* CFEBR R1,R2 [RRE] */ > + case 0x99: /* CFDBR R1,R2 [RRE] */ > + case 0x9a: /* CFXBR R1,R2 [RRE] */ > + tmp = tcg_const_i32(r1); > + tmp2 = tcg_const_i32(r2); > + tmp3 = tcg_const_i32(m3); > + switch (op) { > + case 0x98: gen_helper_cfebr(cc, tmp, tmp2, tmp3); break; > + case 0x99: gen_helper_cfdbr(cc, tmp, tmp2, tmp3); break; > + case 0x9a: gen_helper_cfxbr(cc, tmp, tmp2, tmp3); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + break; > + case 0xa4: /* CEGBR R1,R2 [RRE] */ > + case 0xa5: /* CDGBR R1,R2 [RRE] */ > + tmp = tcg_const_i32(r1); > + tmp2 = load_reg(r2); > + switch (op) { > + case 0xa4: gen_helper_cegbr(tmp, tmp2); break; > + case 0xa5: gen_helper_cdgbr(tmp, tmp2); break; > + default: tcg_abort(); > + } > + break; > + case 0xa6: /* CXGBR R1,R2 [RRE] */ > + tmp = tcg_const_i32(r1); > + tmp2 = load_reg(r2); > + gen_helper_cxgbr(tmp, tmp2); > + break; > + case 0xa8: /* CGEBR R1,R2 [RRE] */ > + tmp = tcg_const_i32(r1); > + tmp2 = tcg_const_i32(r2); > + tmp3 = tcg_const_i32(m3); > + gen_helper_cgebr(cc, tmp, tmp2, tmp3); > + break; > + case 0xa9: /* CGDBR R1,R2 [RRE] */ > + tmp = tcg_const_i32(r1); > + tmp2 = tcg_const_i32(r2); > + tmp3 = tcg_const_i32(m3); > + gen_helper_cgdbr(cc, tmp, tmp2, tmp3); > + break; > + case 0xaa: /* CGXBR R1,R2 [RRE] */ > + tmp = tcg_const_i32(r1); > + tmp2 = tcg_const_i32(r2); > + tmp3 = tcg_const_i32(m3); > + gen_helper_cgxbr(cc, tmp, tmp2, tmp3); > + break; > + default: > + LOG_DISAS("illegal b3 operation 0x%x\n", op); > + gen_illegal_opcode(s); > + break; > + } > + if (tmp) tcg_temp_free(tmp); > + if (tmp2) tcg_temp_free(tmp2); > + if (tmp3) tcg_temp_free(tmp3); Comparison on TCGv type is not allowed. > +} > + > +static void disas_b9(DisasContext *s, int op, int r1, int r2) > +{ > + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; The variables should not be initialized to 0 > + LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); > + switch (op) { > + case 0: /* LPGR R1,R2 [RRE] */ > + case 0x10: /* LPGFR R1,R2 [RRE] */ > + if (op == 0) { > + tmp2 = load_reg(r2); > + } > + else { > + tmp2 = load_reg32(r2); > + tcg_gen_ext32s_i64(tmp2, tmp2); > + } > + tmp = tcg_const_i32(r1); Wrong TCG type. > + gen_helper_abs_i64(cc, tmp, tmp2); > + break; > + case 1: /* LNGR R1,R2 [RRE] */ > + tmp2 = load_reg(r2); > + tmp = tcg_const_i32(r1); Wrong TCG type. > + gen_helper_nabs_i64(cc, tmp, tmp2); > + break; > + case 2: /* LTGR R1,R2 [RRE] */ > + tmp = load_reg(r2); > + if (r1 != r2) store_reg(r1, tmp); coding style > + set_cc_s64(tmp); > + break; > + case 3: /* LCGR R1,R2 [RRE] */ > + case 0x13: /* LCGFR R1,R2 [RRE] */ > + if (op == 0x13) { > + tmp = load_reg32(r2); Wrong TCG type. > + tcg_gen_ext32s_i64(tmp, tmp); > + } > + else { > + tmp = load_reg(r2); > + } > + tcg_gen_neg_i64(tmp, tmp); > + store_reg(r1, tmp); > + gen_helper_set_cc_comp_s64(cc, tmp); > + break; > + case 4: /* LGR R1,R2 [RRE] */ > + tmp = load_reg(r2); > + store_reg(r1, tmp); > + break; > + case 0x6: /* LGBR R1,R2 [RRE] */ > + tmp2 = load_reg(r2); > + tcg_gen_ext8s_i64(tmp2, tmp2); > + store_reg(r1, tmp2); > + break; > + case 8: /* AGR R1,R2 [RRE] */ > + case 0xa: /* ALGR R1,R2 [RRE] */ > + tmp = load_reg(r1); > + tmp2 = load_reg(r2); > + tmp3 = tcg_temp_new_i64(); > + tcg_gen_add_i64(tmp3, tmp, tmp2); > + store_reg(r1, tmp3); > + switch (op) { > + case 0x8: gen_set_cc_add64(tmp, tmp2, tmp3); break; > + case 0xa: gen_helper_set_cc_addu64(cc, tmp, tmp2, tmp3); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + break; > + case 9: /* SGR R1,R2 [RRE] */ > + case 0xb: /* SLGR R1,R2 [RRE] */ > + case 0x1b: /* SLGFR R1,R2 [RRE] */ > + case 0x19: /* SGFR R1,R2 [RRE] */ > + tmp = load_reg(r1); > + switch (op) { > + case 0x1b: case 0x19: > + tmp2 = load_reg32(r2); > + if (op == 0x19) tcg_gen_ext32s_i64(tmp2, tmp2); > + else tcg_gen_ext32u_i64(tmp2, tmp2); coding style > + break; > + default: > + tmp2 = load_reg(r2); > + break; > + } > + tmp3 = tcg_temp_new_i64(); > + tcg_gen_sub_i64(tmp3, tmp, tmp2); > + store_reg(r1, tmp3); > + switch (op) { > + case 9: case 0x19: gen_helper_set_cc_sub64(cc, tmp,tmp2,tmp3); break; > + case 0xb: case 0x1b: gen_helper_set_cc_subu64(cc, tmp, tmp2, tmp3); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + break; > + case 0xc: /* MSGR R1,R2 [RRE] */ > + case 0x1c: /* MSGFR R1,R2 [RRE] */ > + tmp = load_reg(r1); > + tmp2 = load_reg(r2); > + if (op == 0x1c) tcg_gen_ext32s_i64(tmp2, tmp2); > + tcg_gen_mul_i64(tmp, tmp, tmp2); > + store_reg(r1, tmp); > + break; > + case 0xd: /* DSGR R1,R2 [RRE] */ > + case 0x1d: /* DSGFR R1,R2 [RRE] */ > + tmp = load_reg(r1 + 1); > + if (op == 0xd) { > + tmp2 = load_reg(r2); > + } > + else { > + tmp2 = load_reg32(r2); > + tcg_gen_ext32s_i64(tmp2, tmp2); > + } > + tmp3 = tcg_temp_new_i64(); > + tcg_gen_div_i64(tmp3, tmp, tmp2); > + store_reg(r1 + 1, tmp3); > + tcg_gen_rem_i64(tmp3, tmp, tmp2); > + store_reg(r1, tmp3); > + break; > + case 0x14: /* LGFR R1,R2 [RRE] */ > + tmp = load_reg32(r2); > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_ext32s_i64(tmp2, tmp); > + store_reg(r1, tmp2); > + break; > + case 0x16: /* LLGFR R1,R2 [RRE] */ > + tmp = load_reg32(r2); > + tcg_gen_ext32u_i64(tmp, tmp); > + store_reg(r1, tmp); > + break; > + case 0x17: /* LLGTR R1,R2 [RRE] */ > + tmp = load_reg32(r2); > + tcg_gen_andi_i32(tmp, tmp, 0x7fffffffUL); Wrong TCG type. > + tcg_gen_ext32u_i64(tmp, tmp); > + store_reg(r1, tmp); > + break; > + case 0x18: /* AGFR R1,R2 [RRE] */ > + case 0x1a: /* ALGFR R1,R2 [RRE] */ > + tmp2 = load_reg32(r2); > + switch (op) { > + case 0x18: tcg_gen_ext32s_i64(tmp2, tmp2); break; > + case 0x1a: tcg_gen_ext32u_i64(tmp2, tmp2); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + tmp = load_reg(r1); > + tmp3 = tcg_temp_new_i64(); > + tcg_gen_add_i64(tmp3, tmp, tmp2); > + store_reg(r1, tmp3); > + switch (op) { > + case 0x18: gen_set_cc_add64(tmp, tmp2, tmp3); break; > + case 0x1a: gen_helper_set_cc_addu64(cc, tmp, tmp2, tmp3); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + break; > + case 0x20: /* CGR R1,R2 [RRE] */ > + case 0x30: /* CGFR R1,R2 [RRE] */ > + tmp2 = load_reg(r2); > + if (op == 0x30) tcg_gen_ext32s_i64(tmp2, tmp2); > + tmp = load_reg(r1); > + cmp_s64(tmp, tmp2); > + break; > + case 0x21: /* CLGR R1,R2 [RRE] */ > + case 0x31: /* CLGFR R1,R2 [RRE] */ > + tmp2 = load_reg(r2); > + if (op == 0x31) tcg_gen_ext32u_i64(tmp2, tmp2); > + tmp = load_reg(r1); > + cmp_u64(tmp, tmp2); > + break; > + case 0x26: /* LBR R1,R2 [RRE] */ > + tmp2 = load_reg32(r2); > + tcg_gen_ext8s_i32(tmp2, tmp2); Wrong TCG type. > + store_reg32(r1, tmp2); > + break; > + case 0x27: /* LHR R1,R2 [RRE] */ > + tmp2 = load_reg32(r2); > + tcg_gen_ext16s_i32(tmp2, tmp2); > + store_reg32(r1, tmp2); > + break; > + case 0x80: /* NGR R1,R2 [RRE] */ > + case 0x81: /* OGR R1,R2 [RRE] */ > + case 0x82: /* XGR R1,R2 [RRE] */ > + tmp = load_reg(r1); > + tmp2 = load_reg(r2); > + switch (op) { > + case 0x80: tcg_gen_and_i64(tmp, tmp, tmp2); break; > + case 0x81: tcg_gen_or_i64(tmp, tmp, tmp2); break; > + case 0x82: tcg_gen_xor_i64(tmp, tmp, tmp2); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg(r1, tmp); > + set_cc_nz_u64(tmp); > + break; > + case 0x83: /* FLOGR R1,R2 [RRE] */ > + tmp2 = load_reg(r2); > + tmp = tcg_const_i32(r1); Wrong TCG type. > + gen_helper_flogr(cc, tmp, tmp2); > + break; > + case 0x84: /* LLGCR R1,R2 [RRE] */ > + tmp = load_reg(r2); > + tcg_gen_andi_i64(tmp, tmp, 0xff); > + store_reg(r1, tmp); > + break; > + case 0x85: /* LLGHR R1,R2 [RRE] */ > + tmp = load_reg(r2); > + tcg_gen_andi_i64(tmp, tmp, 0xffff); > + store_reg(r1, tmp); > + break; > + case 0x87: /* DLGR R1,R2 [RRE] */ > + tmp = tcg_const_i32(r1); Wrong TCG type. > + tmp2 = load_reg(r2); > + gen_helper_dlg(tmp, tmp2); > + break; > + case 0x88: /* ALCGR R1,R2 [RRE] */ > + tmp = load_reg(r1); > + tmp2 = load_reg(r2); > + tmp3 = tcg_temp_new_i64(); > + tcg_gen_shri_i64(tmp3, cc, 1); > + tcg_gen_andi_i64(tmp3, tmp3, 1); > + tcg_gen_add_i64(tmp3, tmp2, tmp3); > + tcg_gen_add_i64(tmp3, tmp, tmp3); > + store_reg(r1, tmp3); > + gen_helper_set_cc_addc_u64(cc, tmp, tmp2, tmp3); > + break; > + case 0x89: /* SLBGR R1,R2 [RRE] */ > + tmp = load_reg(r1); > + tmp2 = load_reg(r2); > + tmp3 = tcg_const_i32(r1); Wrong TCG type. > + gen_helper_slbg(cc, cc, tmp3, tmp, tmp2); > + break; > + case 0x94: /* LLCR R1,R2 [RRE] */ > + tmp = load_reg32(r2); > + tcg_gen_andi_i32(tmp, tmp, 0xff); > + store_reg32(r1, tmp); > + break; > + case 0x95: /* LLHR R1,R2 [RRE] */ > + tmp = load_reg32(r2); > + tcg_gen_andi_i32(tmp, tmp, 0xffff); Wrong TCG type. > + store_reg32(r1, tmp); > + break; > + case 0x98: /* ALCR R1,R2 [RRE] */ > + tmp = tcg_const_i32(r1); Wrong TCG type. > + tmp2 = load_reg32(r2); > + gen_helper_addc_u32(cc, cc, tmp, tmp2); > + break; > + case 0x99: /* SLBR R1,R2 [RRE] */ > + tmp = load_reg32(r1); > + tmp2 = load_reg32(r2); > + tmp3 = tcg_const_i32(r1); Wrong TCG type. > + gen_helper_slb(cc, cc, tmp3, tmp, tmp2); > + break; > + default: > + LOG_DISAS("illegal b9 operation 0x%x\n", op); > + gen_illegal_opcode(s); > + break; > + } > + if (tmp) tcg_temp_free(tmp); > + if (tmp2) tcg_temp_free(tmp2); > + if (tmp3) tcg_temp_free(tmp3); Comparison on TCGv type is not allowed. > +} > + > +static void disas_c0(DisasContext *s, int op, int r1, int i2) > +{ > + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; The variables should not be initialized to 0 > + LOG_DISAS("disas_c0: op 0x%x r1 %d i2 %d\n", op, r1, i2); > + uint64_t target = s->pc + i2 * 2; > + /* FIXME: huh? */ target &= 0xffffffff; That should be fixed before a merge. > + switch (op) { > + case 0: /* larl r1, i2 */ > + tmp = tcg_const_i64(target); > + store_reg(r1, tmp); > + break; > + case 0x1: /* LGFI R1,I2 [RIL] */ > + tmp = tcg_const_i64((int64_t)i2); > + store_reg(r1, tmp); > + break; > + case 0x4: /* BRCL M1,I2 [RIL] */ > + tmp = tcg_const_i32(r1); /* aka m1 */ Wrong TCG type. > + tmp2 = tcg_const_i64(s->pc); > + tmp3 = tcg_const_i64(i2 * 2); > + gen_helper_brcl(cc, tmp, tmp2, tmp3); > + s->is_jmp = DISAS_JUMP; > + break; > + case 0x5: /* brasl r1, i2 */ > + tmp = tcg_const_i64(s->pc + 6); > + store_reg(r1, tmp); > + tmp = tcg_const_i64(target); > + tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, psw.addr)); > + s->is_jmp = DISAS_JUMP; > + break; > + case 0x7: /* XILF R1,I2 [RIL] */ > + case 0xb: /* NILF R1,I2 [RIL] */ > + case 0xd: /* OILF R1,I2 [RIL] */ > + tmp = load_reg32(r1); > + switch (op) { > + case 0x7: tcg_gen_xori_i32(tmp, tmp, (uint32_t)i2); break; > + case 0xb: tcg_gen_andi_i32(tmp, tmp, (uint32_t)i2); break; > + case 0xd: tcg_gen_ori_i32(tmp, tmp, (uint32_t)i2); break; Wrong TCG type. > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg32(r1, tmp); > + tcg_gen_trunc_i64_i32(tmp, tmp); Wrong TCG type. > + set_cc_nz_u32(tmp); > + break; > + case 0x9: /* IILF R1,I2 [RIL] */ > + tmp = tcg_const_i32((uint32_t)i2); Wrong TCG type. > + store_reg32(r1, tmp); > + break; > + case 0xa: /* NIHF R1,I2 [RIL] */ > + tmp = load_reg(r1); > + switch (op) { > + case 0xa: tcg_gen_andi_i64(tmp, tmp, (((uint64_t)((uint32_t)i2)) << 32) | 0xffffffffULL); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg(r1, tmp); > + tcg_gen_shr_i64(tmp, tmp, 32); > + tcg_gen_trunc_i64_i32(tmp, tmp); Wrong TCG type. > + set_cc_nz_u32(tmp); > + break; > + case 0xe: /* LLIHF R1,I2 [RIL] */ > + tmp = tcg_const_i64(((uint64_t)(uint32_t)i2) << 32); > + store_reg(r1, tmp); > + break; > + case 0xf: /* LLILF R1,I2 [RIL] */ > + tmp = tcg_const_i64((uint32_t)i2); > + store_reg(r1, tmp); > + break; > + default: > + LOG_DISAS("illegal c0 operation 0x%x\n", op); > + gen_illegal_opcode(s); > + break; > + } > + if (tmp) tcg_temp_free(tmp); > + if (tmp2) tcg_temp_free(tmp2); > + if (tmp3) tcg_temp_free(tmp3); Comparison on TCGv type is not allowed. > +} > + > +static void disas_c2(DisasContext *s, int op, int r1, int i2) > +{ > + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; The variables should not be initialized to 0 > + switch (op) { > + case 0x4: /* SLGFI R1,I2 [RIL] */ > + case 0xa: /* ALGFI R1,I2 [RIL] */ > + tmp = load_reg(r1); > + tmp2 = tcg_const_i64((uint64_t)(uint32_t)i2); > + tmp3 = tcg_temp_new_i64(); > + switch (op) { > + case 0x4: > + tcg_gen_sub_i64(tmp3, tmp, tmp2); > + gen_helper_set_cc_subu64(cc, tmp, tmp2, tmp3); > + break; > + case 0xa: > + tcg_gen_add_i64(tmp3, tmp, tmp2); > + gen_helper_set_cc_addu64(cc, tmp, tmp2, tmp3); > + break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg(r1, tmp3); > + break; > + case 0x5: /* SLFI R1,I2 [RIL] */ > + case 0xb: /* ALFI R1,I2 [RIL] */ > + tmp = load_reg32(r1); > + tmp2 = tcg_const_i32(i2); > + tmp3 = tcg_temp_new_i32(); Wrong TCG type. > + switch (op) { > + case 0x5: > + tcg_gen_sub_i32(tmp3, tmp, tmp2); Wrong TCG type. > + gen_helper_set_cc_subu32(cc, tmp, tmp2, tmp3); > + break; > + case 0xb: > + tcg_gen_add_i32(tmp3, tmp, tmp2); Wrong TCG type. > + gen_helper_set_cc_addu32(cc, tmp, tmp2, tmp3); > + break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg32(r1, tmp3); > + break; > + case 0xc: /* CGFI R1,I2 [RIL] */ > + tmp = load_reg(r1); > + cmp_s64c(tmp, (int64_t)i2); > + break; > + case 0xe: /* CLGFI R1,I2 [RIL] */ > + tmp = load_reg(r1); > + cmp_u64c(tmp, (uint64_t)(uint32_t)i2); > + break; > + case 0xd: /* CFI R1,I2 [RIL] */ > + case 0xf: /* CLFI R1,I2 [RIL] */ > + tmp = load_reg32(r1); > + switch (op) { > + case 0xd: cmp_s32c(tmp, i2); break; > + case 0xf: cmp_u32c(tmp, i2); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + break; > + default: > + LOG_DISAS("illegal c2 operation 0x%x\n", op); > + gen_illegal_opcode(s); > + break; > + } > + if (tmp) tcg_temp_free(tmp); > + if (tmp2) tcg_temp_free(tmp2); > + if (tmp3) tcg_temp_free(tmp3); Comparison on TCGv type is not allowed. > +} > + > +static inline uint64_t ld_code2(uint64_t pc) { return (uint64_t)lduw_code(pc); } Coding style. > +static inline uint64_t ld_code4(uint64_t pc) { return (uint64_t)ldl_code(pc); } Coding style. > +static inline uint64_t ld_code6(uint64_t pc) > +{ > + uint64_t opc; > + opc = (uint64_t)lduw_code(pc) << 32; > + opc |= (uint64_t)(unsigned int)ldl_code(pc+2); > + return opc; > +} > + > +static void disas_s390_insn(CPUState *env, DisasContext *s) > +{ > + TCGv tmp = 0,tmp2 = 0,tmp3 = 0; The variables should not be initialized to 0 > + unsigned char opc; > + uint64_t insn; > + int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; > + TCGv vl, vd1, vd2, vb; > + > + opc = ldub_code(s->pc); > + LOG_DISAS("opc 0x%x\n", opc); > + > +#define FETCH_DECODE_RR \ > + insn = ld_code2(s->pc); \ > + DEBUGINSN \ > + r1 = (insn >> 4) & 0xf; \ > + r2 = insn & 0xf; > + > +#define FETCH_DECODE_RX \ > + insn = ld_code4(s->pc); \ > + DEBUGINSN \ > + r1 = (insn >> 20) & 0xf; \ > + x2 = (insn >> 16) & 0xf; \ > + b2 = (insn >> 12) & 0xf; \ > + d2 = insn & 0xfff; \ > + tmp = get_address(x2, b2, d2); > + > +#define FETCH_DECODE_RS \ > + insn = ld_code4(s->pc); \ > + DEBUGINSN \ > + r1 = (insn >> 20) & 0xf; \ > + r3 = (insn >> 16) & 0xf; /* aka m3 */ \ > + b2 = (insn >> 12) & 0xf; \ > + d2 = insn & 0xfff; > + > +#define FETCH_DECODE_SI \ > + insn = ld_code4(s->pc); \ > + i2 = (insn >> 16) & 0xff; \ > + b1 = (insn >> 12) & 0xf; \ > + d1 = insn & 0xfff; \ > + tmp = get_address(0, b1, d1); > + > + switch (opc) { > + case 0x7: /* BCR M1,R2 [RR] */ > + FETCH_DECODE_RR > + if (r2) { > + gen_bcr(r1, r2, s->pc); > + s->is_jmp = DISAS_JUMP; > + } > + else { > + /* FIXME: "serialization and checkpoint-synchronization function"? */ > + } > + s->pc += 2; > + break; > + case 0xa: /* SVC I [RR] */ > + insn = ld_code2(s->pc); > + DEBUGINSN > + i = insn & 0xff; > + tmp = tcg_const_i64(s->pc); > + tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, psw.addr)); > + s->is_jmp = DISAS_SVC; > + s->pc += 2; > + break; > + case 0xd: /* BASR R1,R2 [RR] */ > + FETCH_DECODE_RR > + tmp = tcg_const_i64(s->pc + 2); > + store_reg(r1, tmp); > + if (r2) { > + tmp2 = load_reg(r2); > + tcg_gen_st_i64(tmp2, cpu_env, offsetof(CPUState, psw.addr)); > + s->is_jmp = DISAS_JUMP; > + } > + s->pc += 2; > + break; > + case 0x10: /* LPR R1,R2 [RR] */ > + FETCH_DECODE_RR > + tmp2 = load_reg32(r2); > + tmp = tcg_const_i32(r1); > + gen_helper_abs_i32(cc, tmp, tmp2); Wrong TCGv type. > + s->pc += 2; > + break; > + case 0x11: /* LNR R1,R2 [RR] */ > + FETCH_DECODE_RR > + tmp2 = load_reg32(r2); > + tmp = tcg_const_i32(r1); > + gen_helper_nabs_i32(cc, tmp, tmp2); Wrong TCGv type. > + s->pc += 2; > + break; > + case 0x12: /* LTR R1,R2 [RR] */ > + FETCH_DECODE_RR > + tmp = load_reg32(r2); > + if (r1 != r2) store_reg32(r1, tmp); > + set_cc_s32(tmp); > + s->pc += 2; > + break; > + case 0x13: /* LCR R1,R2 [RR] */ > + FETCH_DECODE_RR > + tmp = load_reg32(r2); > + tcg_gen_neg_i32(tmp, tmp); > + store_reg32(r1, tmp); > + gen_helper_set_cc_comp_s32(cc, tmp); Wrong TCGv type. > + s->pc += 2; > + break; > + case 0x14: /* NR R1,R2 [RR] */ > + case 0x16: /* OR R1,R2 [RR] */ > + case 0x17: /* XR R1,R2 [RR] */ > + FETCH_DECODE_RR > + tmp2 = load_reg32(r2); > + tmp = load_reg32(r1); > + switch (opc) { > + case 0x14: tcg_gen_and_i32(tmp, tmp, tmp2); break; > + case 0x16: tcg_gen_or_i32(tmp, tmp, tmp2); break; > + case 0x17: tcg_gen_xor_i32(tmp, tmp, tmp2); break; Wrong TCGv type. > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg32(r1, tmp); > + set_cc_nz_u32(tmp); > + s->pc += 2; > + break; > + case 0x18: /* LR R1,R2 [RR] */ > + FETCH_DECODE_RR > + tmp = load_reg32(r2); > + store_reg32(r1, tmp); > + s->pc += 2; > + break; > + case 0x15: /* CLR R1,R2 [RR] */ > + case 0x19: /* CR R1,R2 [RR] */ > + FETCH_DECODE_RR > + tmp = load_reg32(r1); > + tmp2 = load_reg32(r2); > + switch (opc) { > + case 0x15: cmp_u32(tmp, tmp2); break; > + case 0x19: cmp_s32(tmp, tmp2); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + s->pc += 2; > + break; > + case 0x1a: /* AR R1,R2 [RR] */ > + case 0x1e: /* ALR R1,R2 [RR] */ > + FETCH_DECODE_RR > + tmp = load_reg32(r1); > + tmp2 = load_reg32(r2); > + tmp3 = tcg_temp_new_i32(); > + tcg_gen_add_i32(tmp3, tmp, tmp2); > + store_reg32(r1, tmp3); Wrong TCGv type. > + switch (opc) { > + case 0x1a: gen_helper_set_cc_add32(cc, tmp, tmp2, tmp3); break; > + case 0x1e: gen_helper_set_cc_addu32(cc, tmp, tmp2, tmp3); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + s->pc += 2; > + break; > + case 0x1b: /* SR R1,R2 [RR] */ > + case 0x1f: /* SLR R1,R2 [RR] */ > + FETCH_DECODE_RR > + tmp = load_reg32(r1); > + tmp2 = load_reg32(r2); > + tmp3 = tcg_temp_new_i32(); > + tcg_gen_sub_i32(tmp3, tmp, tmp2); > + store_reg32(r1, tmp3); Wrong TCGv type. > + switch (opc) { > + case 0x1b: gen_helper_set_cc_sub32(cc, tmp, tmp2, tmp3); break; > + case 0x1f: gen_helper_set_cc_subu32(cc, tmp, tmp2, tmp3); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + s->pc += 2; > + break; > + case 0x28: /* LDR R1,R2 [RR] */ > + FETCH_DECODE_RR > + tmp = load_freg(r2); > + store_freg(r1, tmp); > + s->pc += 2; > + break; > + case 0x38: /* LER R1,R2 [RR] */ > + FETCH_DECODE_RR > + tmp = load_freg32(r2); > + store_freg32(r1, tmp); > + s->pc += 2; > + break; > + case 0x40: /* STH R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = load_reg32(r1); > + tcg_gen_qemu_st16(tmp2, tmp, 1); > + s->pc += 4; > + break; > + case 0x41: /* la */ > + FETCH_DECODE_RX > + store_reg(r1, tmp); /* FIXME: 31/24-bit addressing */ > + s->pc += 4; > + break; > + case 0x42: /* STC R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = load_reg32(r1); > + tcg_gen_qemu_st8(tmp2, tmp, 1); > + s->pc += 4; > + break; > + case 0x43: /* IC R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld8u(tmp2, tmp, 1); > + store_reg8(r1, tmp2); > + s->pc += 4; > + break; > + case 0x44: /* EX R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = load_reg(r1); > + tmp3 = tcg_const_i64(s->pc + 4); > + gen_helper_ex(cc, cc, tmp2, tmp, tmp3); > + s->pc += 4; > + break; > + case 0x47: /* BC M1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + /* FIXME: optimize m1 == 0xf (unconditional) case */ > + tmp2 = tcg_const_i32(r1); /* aka m1 */ Wrong TCGv type. > + tmp3 = tcg_const_i64(s->pc); > + gen_helper_bc(cc, tmp2, tmp, tmp3); > + s->is_jmp = DISAS_JUMP; > + s->pc += 4; > + break; > + case 0x48: /* LH R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld16s(tmp2, tmp, 1); > + store_reg32(r1, tmp2); > + s->pc += 4; > + break; > + case 0x49: /* CH R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld16s(tmp2, tmp, 1); > + tmp = load_reg32(r1); > + cmp_s32(tmp, tmp2); > + s->pc += 4; > + break; > + case 0x4a: /* AH R1,D2(X2,B2) [RX] */ > + case 0x4b: /* SH R1,D2(X2,B2) [RX] */ > + case 0x4c: /* MH R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld16s(tmp2, tmp, 1); > + tmp = load_reg32(r1); > + tmp3 = tcg_temp_new_i32(); > + switch (opc) { > + case 0x4a: > + tcg_gen_add_i32(tmp3, tmp, tmp2); > + gen_helper_set_cc_add32(cc, tmp, tmp2, tmp3); > + break; > + case 0x4b: > + tcg_gen_sub_i32(tmp3, tmp, tmp2); > + gen_helper_set_cc_sub32(cc, tmp, tmp2, tmp3); > + break; > + case 0x4c: > + tcg_gen_mul_i32(tmp3, tmp, tmp2); > + break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg32(r1, tmp3); > + s->pc += 4; > + break; > + case 0x50: /* st r1, d2(x2, b2) */ > + FETCH_DECODE_RX > + tmp2 = load_reg32(r1); > + tcg_gen_qemu_st32(tmp2, tmp, 1); > + s->pc += 4; > + break; > + case 0x55: /* CL R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + tmp = load_reg32(r1); > + cmp_u32(tmp, tmp2); > + s->pc += 4; > + break; > + case 0x54: /* N R1,D2(X2,B2) [RX] */ > + case 0x56: /* O R1,D2(X2,B2) [RX] */ > + case 0x57: /* X R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX Wrong TCGv type. > + tmp2 = tcg_temp_new_i32(); > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + tmp = load_reg32(r1); > + switch (opc) { > + case 0x54: tcg_gen_and_i32(tmp, tmp, tmp2); break; > + case 0x56: tcg_gen_or_i32(tmp, tmp, tmp2); break; > + case 0x57: tcg_gen_xor_i32(tmp, tmp, tmp2); break; Wrong TCGv type. > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg32(r1, tmp); > + set_cc_nz_u32(tmp); > + s->pc += 4; > + break; > + case 0x58: /* l r1, d2(x2, b2) */ > + FETCH_DECODE_RX > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + store_reg32(r1, tmp2); > + s->pc += 4; > + break; > + case 0x59: /* C R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld32s(tmp2, tmp, 1); > + tmp = load_reg32(r1); > + cmp_s32(tmp, tmp2); > + s->pc += 4; > + break; > + case 0x5a: /* A R1,D2(X2,B2) [RX] */ > + case 0x5b: /* S R1,D2(X2,B2) [RX] */ > + case 0x5e: /* AL R1,D2(X2,B2) [RX] */ > + case 0x5f: /* SL R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = load_reg32(r1); > + tcg_gen_qemu_ld32s(tmp, tmp, 1); > + tmp3 = tcg_temp_new_i32(); Wrong TCGv type. > + switch (opc) { > + case 0x5a: case 0x5e: tcg_gen_add_i32(tmp3, tmp2, tmp); break; > + case 0x5b: case 0x5f: tcg_gen_sub_i32(tmp3, tmp2, tmp); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg32(r1, tmp3); > + switch (opc) { > + case 0x5a: gen_helper_set_cc_add32(cc, tmp2, tmp, tmp3); break; > + case 0x5e: gen_helper_set_cc_addu32(cc, tmp2, tmp, tmp3); break; > + case 0x5b: gen_helper_set_cc_sub32(cc, tmp2, tmp, tmp3); break; > + case 0x5f: gen_helper_set_cc_subu32(cc, tmp2, tmp, tmp3); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + s->pc += 4; > + break; > + case 0x60: /* STD R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = load_freg(r1); > + tcg_gen_qemu_st64(tmp2, tmp, 1); > + s->pc += 4; > + break; > + case 0x68: /* LD R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = tcg_temp_new_i64(); > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > + store_freg(r1, tmp2); > + s->pc += 4; > + break; > + case 0x70: /* STE R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = load_freg32(r1); > + tcg_gen_qemu_st32(tmp2, tmp, 1); > + s->pc += 4; > + break; > + case 0x71: /* MS R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld32s(tmp2, tmp, 1); > + tmp = load_reg(r1); > + tcg_gen_mul_i32(tmp, tmp, tmp2); > + store_reg(r1, tmp); > + s->pc += 4; > + break; > + case 0x78: /* LE R1,D2(X2,B2) [RX] */ > + FETCH_DECODE_RX > + tmp2 = tcg_temp_new_i32(); > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + store_freg32(r1, tmp2); > + s->pc += 4; > + break; > + case 0x88: /* SRL R1,D2(B2) [RS] */ > + case 0x89: /* SLL R1,D2(B2) [RS] */ > + case 0x8a: /* SRA R1,D2(B2) [RS] */ > + FETCH_DECODE_RS > + tmp = get_address(0, b2, d2); > + tcg_gen_andi_i64(tmp, tmp, 0x3f); > + tmp2 = load_reg32(r1); > + switch (opc) { > + case 0x88: tcg_gen_shr_i32(tmp2, tmp2, tmp); break; > + case 0x89: tcg_gen_shl_i32(tmp2, tmp2, tmp); break; > + case 0x8a: tcg_gen_sar_i32(tmp2, tmp2, tmp); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + store_reg32(r1, tmp2); > + if (opc == 0x8a) set_cc_s32(tmp2); coding style > + s->pc += 4; > + break; > + case 0x91: /* TM D1(B1),I2 [SI] */ > + FETCH_DECODE_SI > + tmp2 = tcg_temp_new_i32(); > + tcg_gen_qemu_ld8u(tmp2, tmp, 1); > + tmp = tcg_const_i32(i2); Wrong TCGv type. > + gen_helper_tm(cc, tmp2, tmp); > + s->pc += 4; > + break; > + case 0x92: /* MVI D1(B1),I2 [SI] */ > + FETCH_DECODE_SI > + tmp2 = tcg_const_i32(i2); > + tcg_gen_qemu_st8(tmp2, tmp, 1); > + s->pc += 4; > + break; > + case 0x94: /* NI D1(B1),I2 [SI] */ > + case 0x96: /* OI D1(B1),I2 [SI] */ > + case 0x97: /* XI D1(B1),I2 [SI] */ > + FETCH_DECODE_SI > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld8u(tmp2, tmp, 1); > + switch (opc) { > + case 0x94: tcg_gen_andi_i32(tmp2, tmp2, i2); break; > + case 0x96: tcg_gen_ori_i32(tmp2, tmp2, i2); break; > + case 0x97: tcg_gen_xori_i32(tmp2, tmp2, i2); break; Same comment as previous tcg_abort() one. > + default: tcg_abort(); > + } > + tcg_gen_qemu_st8(tmp2, tmp, 1); > + set_cc_nz_u32(tmp2); > + s->pc += 4; > + break; > + case 0x95: /* CLI D1(B1),I2 [SI] */ > + FETCH_DECODE_SI > + tmp2 = tcg_temp_new_i32(); Wrong TCGv type. > + tcg_gen_qemu_ld8u(tmp2, tmp, 1); > + cmp_u32c(tmp2, i2); > + s->pc += 4; > + break; > + case 0x9b: /* STAM R1,R3,D2(B2) [RS] */ > + FETCH_DECODE_RS > + tmp = tcg_const_i32(r1); > + tmp2 = get_address(0, b2, d2); > + tmp3 = tcg_const_i32(r3); Wrong TCGv type. > + gen_helper_stam(tmp, tmp2, tmp3); > + s->pc += 4; > + break; > + case 0xa5: > + insn = ld_code4(s->pc); > + r1 = (insn >> 20) & 0xf; > + op = (insn >> 16) & 0xf; > + i2 = insn & 0xffff; > + disas_a5(s, op, r1, i2); > + s->pc += 4; > + break; > + case 0xa7: > + insn = ld_code4(s->pc); > + r1 = (insn >> 20) & 0xf; > + op = (insn >> 16) & 0xf; > + i2 = (short)insn; > + disas_a7(s, op, r1, i2); > + s->pc += 4; > + break; > + case 0xa8: /* MVCLE R1,R3,D2(B2) [RS] */ > + FETCH_DECODE_RS > + tmp = tcg_const_i32(r1); > + tmp3 = tcg_const_i32(r3); Wrong TCGv type. > + tmp2 = get_address(0, b2, d2); > + gen_helper_mvcle(cc, tmp, tmp2, tmp3); > + s->pc += 4; > + break; > + case 0xa9: /* CLCLE R1,R3,D2(B2) [RS] */ > + FETCH_DECODE_RS > + tmp = tcg_const_i32(r1); > + tmp3 = tcg_const_i32(r3); > + tmp2 = get_address(0, b2, d2); > + gen_helper_clcle(cc, tmp, tmp2, tmp3); > + s->pc += 4; > + break; > + case 0xb2: > + insn = ld_code4(s->pc); > + op = (insn >> 16) & 0xff; > + switch (op) { > + case 0x9c: /* STFPC D2(B2) [S] */ > + d2 = insn & 0xfff; > + b2 = (insn >> 12) & 0xf; > + tmp = tcg_temp_new_i32(); > + tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, fpc)); Wrong TCGv type. > + tmp2 = get_address(0, b2, d2); > + tcg_gen_qemu_st32(tmp, tmp2, 1); > + break; > + default: > + r1 = (insn >> 4) & 0xf; > + r2 = insn & 0xf; > + disas_b2(s, op, r1, r2); > + break; > + } > + s->pc += 4; > + break; > + case 0xb3: > + insn = ld_code4(s->pc); > + op = (insn >> 16) & 0xff; > + r3 = (insn >> 12) & 0xf; /* aka m3 */ > + r1 = (insn >> 4) & 0xf; > + r2 = insn & 0xf; > + disas_b3(s, op, r3, r1, r2); > + s->pc += 4; > + break; > + case 0xb9: > + insn = ld_code4(s->pc); > + r1 = (insn >> 4) & 0xf; > + r2 = insn & 0xf; > + op = (insn >> 16) & 0xff; > + disas_b9(s, op, r1, r2); > + s->pc += 4; > + break; > + case 0xba: /* CS R1,R3,D2(B2) [RS] */ > + FETCH_DECODE_RS > + tmp = tcg_const_i32(r1); > + tmp2 = get_address(0, b2, d2); > + tmp3 = tcg_const_i32(r3); Wrong TCGv type. > + gen_helper_cs(cc, tmp, tmp2, tmp3); > + s->pc += 4; > + break; > + case 0xbd: /* CLM R1,M3,D2(B2) [RS] */ > + FETCH_DECODE_RS > + tmp3 = get_address(0, b2, d2); > + tmp2 = tcg_const_i32(r3); /* aka m3 */ Wrong TCGv type. > + tmp = load_reg32(r1); > + gen_helper_clm(cc, tmp, tmp2, tmp3); > + s->pc += 4; > + break; > + case 0xbe: /* STCM R1,M3,D2(B2) [RS] */ > + FETCH_DECODE_RS > + tmp3 = get_address(0, b2, d2); > + tmp2 = tcg_const_i32(r3); /* aka m3 */ Wrong TCGv type. > + tmp = load_reg32(r1); > + gen_helper_stcm(tmp, tmp2, tmp3); > + s->pc += 4; > + break; > + case 0xbf: /* ICM R1,M3,D2(B2) [RS] */ > + FETCH_DECODE_RS > + if (r3 == 15) { /* effectively a 32-bit load */ > + tmp = get_address(0, b2, d2); > + tmp2 = tcg_temp_new_i32(); > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > + store_reg32(r1, tmp2); > + tmp = tcg_const_i32(r3); Wrong TCGv type. > + gen_helper_set_cc_icm(cc, tmp, tmp2); > + } > + else if (r3) { > + uint32_t mask = 0x00ffffffUL; > + uint32_t shift = 24; > + int m3 = r3; > + tmp3 = load_reg32(r1); > + tmp = get_address(0, b2, d2); > + tmp2 = tcg_temp_new_i32(); > + while (m3) { > + if (m3 & 8) { > + tcg_gen_qemu_ld8u(tmp2, tmp, 1); > + if (shift) tcg_gen_shli_i32(tmp2, tmp2, shift); > + tcg_gen_andi_i32(tmp3, tmp3, mask); > + tcg_gen_or_i32(tmp3, tmp3, tmp2); > + tcg_gen_addi_i64(tmp, tmp, 1); > + } > + m3 = (m3 << 1) & 0xf; > + mask = (mask >> 8) | 0xff000000UL; > + shift -= 8; > + } > + store_reg32(r1, tmp3); > + tmp = tcg_const_i32(r3); Wrong TCGv type. > + gen_helper_set_cc_icm(cc, tmp, tmp2); > + } > + else { > + tmp = tcg_const_i32(0); Wrong TCGv type. > + gen_helper_set_cc_icm(cc, tmp, tmp); /* i.e. env->cc = 0 */ > + } > + s->pc += 4; > + break; > + case 0xc0: > + case 0xc2: > + insn = ld_code6(s->pc); > + r1 = (insn >> 36) & 0xf; > + op = (insn >> 32) & 0xf; > + i2 = (int)insn; > + switch (opc) { > + case 0xc0: disas_c0(s, op, r1, i2); break; > + case 0xc2: disas_c2(s, op, r1, i2); break; > + default: tcg_abort(); Same comment as previous tcg_abort() one. > + } > + s->pc += 6; > + break; > + case 0xd2: /* mvc d1(l, b1), d2(b2) */ > + case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ > + case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ > + case 0xd6: /* OC D1(L,B1),D2(B2) [SS] */ > + case 0xd7: /* xc d1(l, b1), d2(b2) */ > + insn = ld_code6(s->pc); > + vl = tcg_const_i32((insn >> 32) & 0xff); > + b1 = (insn >> 28) & 0xf; > + vd1 = tcg_const_i32((insn >> 16) & 0xfff); > + b2 = (insn >> 12) & 0xf; > + vd2 = tcg_const_i32(insn & 0xfff); > + vb = tcg_const_i32((b1 << 4) | b2); Wrong TCGv type. > + switch (opc) { > + case 0xd2: gen_helper_mvc(vl, vb, vd1, vd2); break; > + case 0xd4: gen_helper_nc(cc, vl, vb, vd1, vd2); break; > + case 0xd5: gen_helper_clc(cc, vl, vb, vd1, vd2); break; > + case 0xd6: gen_helper_oc(cc, vl, vb, vd1, vd2); break; > + case 0xd7: gen_helper_xc(cc, vl, vb, vd1, vd2); break; > + default: tcg_abort(); break; Same comment as previous tcg_abort() one. > + } > + s->pc += 6; > + break; > + case 0xe3: > + insn = ld_code6(s->pc); > + DEBUGINSN > + d2 = ( (int) ( (((insn >> 16) & 0xfff) | ((insn << 4) & 0xff000)) << 12 ) ) >> 12; > + disas_e3(s, /* op */ insn & 0xff, /* r1 */ (insn >> 36) & 0xf, /* x2 */ (insn >> 32) & 0xf, /* b2 */ (insn >> 28) & 0xf, d2 ); > + s->pc += 6; > + break; > + case 0xeb: > + insn = ld_code6(s->pc); > + DEBUGINSN > + op = insn & 0xff; > + r1 = (insn >> 36) & 0xf; > + r3 = (insn >> 32) & 0xf; > + b2 = (insn >> 28) & 0xf; > + d2 = ( (int) ( (((insn >> 16) & 0xfff) | ((insn << 4) & 0xff000)) << 12 ) ) >> 12; > + disas_eb(s, op, r1, r3, b2, d2); > + s->pc += 6; > + break; > + case 0xed: > + insn = ld_code6(s->pc); > + DEBUGINSN > + op = insn & 0xff; > + r1 = (insn >> 36) & 0xf; > + x2 = (insn >> 32) & 0xf; > + b2 = (insn >> 28) & 0xf; > + d2 = (short)((insn >> 16) & 0xfff); > + r1b = (insn >> 12) & 0xf; > + disas_ed(s, op, r1, x2, b2, d2, r1b); > + s->pc += 6; > + break; > + default: > + LOG_DISAS("unimplemented opcode 0x%x\n", opc); > + gen_illegal_opcode(s); > + s->pc += 6; > + break; > + } > + if (tmp) tcg_temp_free(tmp); > + if (tmp2) tcg_temp_free(tmp2); > + if (tmp3) tcg_temp_free(tmp3); Comparison on TCGv type is not allowed. > +} > + > +static inline void gen_intermediate_code_internal (CPUState *env, > + TranslationBlock *tb, > + int search_pc) > +{ > + DisasContext dc; > + target_ulong pc_start; > + uint64_t next_page_start; > + uint16_t *gen_opc_end; > + int j, lj = -1; > + int num_insns, max_insns; > + > + pc_start = tb->pc; > + > + dc.pc = tb->pc; > + dc.env = env; > + dc.pc = pc_start; > + dc.is_jmp = DISAS_NEXT; > + > + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; > + > + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; > + > + num_insns = 0; > + max_insns = tb->cflags & CF_COUNT_MASK; > + if (max_insns == 0) > + max_insns = CF_COUNT_MASK; > + > + gen_icount_start(); > +#if 1 > + cc = tcg_temp_local_new_i32(); > + tcg_gen_mov_i32(cc, global_cc); > +#else > + cc = global_cc; > +#endif Why this? > + do { > + if (search_pc) { > + j = gen_opc_ptr - gen_opc_buf; > + if (lj < j) { > + lj++; > + while (lj < j) > + gen_opc_instr_start[lj++] = 0; > + } > + gen_opc_pc[lj] = dc.pc; > + gen_opc_instr_start[lj] = 1; > + gen_opc_icount[lj] = num_insns; > + } > + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) > + gen_io_start(); > +#if defined S390X_DEBUG_DISAS > + LOG_DISAS("pc " TARGET_FMT_lx "\n", > + dc.pc); > +#endif > + disas_s390_insn(env, &dc); > + > + num_insns++; > + } while (!dc.is_jmp && gen_opc_ptr < gen_opc_end && dc.pc < next_page_start && num_insns < max_insns); The also translation should be stopped if in singlestep mode (singlestep variable). > + tcg_gen_mov_i32(global_cc, cc); > + tcg_temp_free(cc); > + > + if (!dc.is_jmp) { > + tcg_gen_st_i64(tcg_const_i64(dc.pc), cpu_env, offsetof(CPUState, psw.addr)); > + } > + > + if (dc.is_jmp == DISAS_SVC) { > + tcg_gen_st_i64(tcg_const_i64(dc.pc), cpu_env, offsetof(CPUState, psw.addr)); > + TCGv tmp = tcg_const_i32(EXCP_SVC); > + gen_helper_exception(tmp); > + } > + > + if (tb->cflags & CF_LAST_IO) > + gen_io_end(); > + /* Generate the return instruction */ > + tcg_gen_exit_tb(0); > + gen_icount_end(tb, num_insns); > + *gen_opc_ptr = INDEX_op_end; > + if (search_pc) { > + j = gen_opc_ptr - gen_opc_buf; > + lj++; > + while (lj <= j) > + gen_opc_instr_start[lj++] = 0; > + } else { > + tb->size = dc.pc - pc_start; > + tb->icount = num_insns; > + } > +#if defined S390X_DEBUG_DISAS > + log_cpu_state_mask(CPU_LOG_TB_CPU, env, 0); > + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { > + qemu_log("IN: %s\n", lookup_symbol(pc_start)); > + log_target_disas(pc_start, dc.pc - pc_start, 1); > + qemu_log("\n"); > + } > +#endif > +} > + > +void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) > +{ > + gen_intermediate_code_internal(env, tb, 0); > +} > + > +void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) > +{ > + gen_intermediate_code_internal(env, tb, 1); > +} > + > +void gen_pc_load(CPUState *env, TranslationBlock *tb, > + unsigned long searched_pc, int pc_pos, void *puc) > +{ > + env->psw.addr = gen_opc_pc[pc_pos]; > +} > -- > 1.6.2.1 > > > >
On Saturday 17 October 2009, Aurelien Jarno wrote: > On Fri, Oct 16, 2009 at 02:38:48PM +0200, Ulrich Hecht wrote: > First of all a few general comments. Note that I know very few things > about S390/S390X, so I may have dumb comments/questions. Also as the > patch is very long, I probably have missed things, we should probably > iterate with new versions of the patches. > > Is it possible given the current implementation to emulate S390 in > addition to S390X? Not as it stands. The S/390 instruction set is a subset of zArch (64-bit), but currently only 64-bit addressing is implemented (because that is the only mode used by 64-bit Linux binaries). > If yes how different would be a S390 only target? It would need support for 31-bit addressing. 24-bit, too, if you want to run the really old stuff. > If they won't be too different, it probably worth using _tl type > registers and call it target-s390. A bit the way it is done with > i386/x86_64, ppc/ppc64, mips/mips64 or sparc/sparc64. If it's going to be implemented, it will certainly share most code with the 64-bit target, so having a common directory would most likely be a good idea. There are some cases where _tl types might be appropriate, but generally everything that is shared between S/390 and zArch is 32-bit, and instructions present in both architectures also have the same operand size: L, for instance, is a 32-bit load to a 32-bit register on both architectures. > Secondly there seems to be a lot of mix between 32-bit and 64-bit > TCG registers. They should not be mixed. _i32 ops apply to TCGv_i32 > variables, _i64 ops apply to TCGv_i64 variables, and _tl ops to TGCv > variables. TCGv/_tl types can map either to _i32 or _i64 depending on > your target. You should try to build the target with > --enable-debug-tcg Er, reading the code and observing the behavior of the (AMD64) code generator, it seemed to me that neither frontends nor backends care one bit about that. I'll look into it, though. (I won't comment on those below, except in cases where the solution or, indeed, the problem is not clear to me.) > It would be nice to split all the disassembling part in a separate > combined with the related makefile changes. This way it can be applied > separately. Can do. > > // switch (info->mach) > > // { > > // case bfd_mach_s390_31: > > - current_arch_mask = 1 << S390_OPCODE_ESA; > > +// current_arch_mask = 1 << S390_OPCODE_ESA; > > // break; > > // case bfd_mach_s390_64: > > -// current_arch_mask = 1 << S390_OPCODE_ZARCH; > > + current_arch_mask = 1 << S390_OPCODE_ZARCH; > > // break; > > // default: > > // abort (); > > While I understand the second part, Why is it necessary to comment the > bfd_mach_s390_31 case? It's not necessary, but current_arch_mask can only hold one value... > > +typedef union FPReg { > > + struct { > > +#ifdef WORDS_BIGENDIAN > > + float32 e; > > + int32_t __pad; > > +#else > > + int32_t __pad; > > + float32 e; > > +#endif > > + }; > > + float64 d; > > + uint64_t i; > > +} FPReg; > > WORDS_BIGENDIAN is wrong here. It should probably be > HOST_WORDS_BIGENDIAN. Indeed. > Also it may be a better idea to > reuse CPU_FloatU and CPU_DoubleU here. Yes. Didn't know about those. > > +CPUS390XState *cpu_s390x_init(const char *cpu_model) > > This function would probably be better in translate.c, so that > s390x_translate_init() can be declared static. I'll check that. > Please use /* */ for comments (See CODING_STYLE). OK. > > + /* FIXME: reset vector? */ > > Yes, reset vector, MMU mode, default register values, ... Works perfectly fine without. ;) Also, the question remains what kind of reset cpu_reset() is supposed to be. For instance, a CPU Reset or Initial CPU Reset on S/390 leaves the general-purpose registers unchanged, a Clear Reset or Power-On Reset sets them to zero. See the table on p. 4-50 in the zArchitecture Principles of Operation (POP), http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/download/A2278324.pdf, for the gory details. > > +//#define DEBUG_HELPER > > +#ifdef DEBUG_HELPER > > +#define HELPER_LOG(x...) qemu_log(x) > > +#else > > +#define HELPER_LOG(x...) > > +#endif > > Small comment for the rest of the file. While I understand HELPER_LOG > is very handy while developing, I think some calls to it can be > dropped in really simple functions. Yes, a bit of cleanup will be in order. > > + for (i = 0; i <= l; i++) { > > + x = ldub(dest + i) & ldub(src + i); > > + if (x) cc = 1; > > coding style Maybe you are referring to "Every indented statement is braced; even if the block contains just one statement.", but I figured that that does not apply here because there is no indentation... > > + if (v < 0) return 1; > > + else if (v > 0) return 2; > > coding style Same here. > The last 6 helpers can probably be coded easily in TCG (they are very > similar to some PowerPC code), though merging this patch with the > helpers is not a problem at all. Again, that would be detrimental to performance. I have experimented with that and found that TCG is well capable of optimizing out a pure helper call, but not a complex piece of code with branches. Condition codes are not used most times, and the overhead of calling a helper in the cases they are is far smaller than doing all the condition code stuff that is not used. Also reduces code size. > All the branch part would really gain to be coded in TCG, as it will > allow TB chaining. I vaguely remember trying that as well, but I don't know if I gave up on it because it was slower, or because I couldn't get it to work... > > + } > > + else if (r > d) { > > coding style OK, this one is valid. :) > __uint128_t is probably not supported on all hosts/GCC versions. Definitely does not work on 32-bit hosts. > mulu64() should be used instead. Excellent, didn't know about that either. > Same here, __uint128_t should not be used, though I don't know what > should be used instead. Hmmmm... > > +/* unsigned string compare (c is string terminator) */ > > +uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) > > +{ > > + uint64_t s1 = env->regs[r1]; > > + uint64_t s2 = env->regs[r2]; > > + uint8_t v1, v2; > > + uint32_t cc; > > + c = c & 0xff; > > +#ifdef CONFIG_USER_ONLY > > + if (!c) { > > + HELPER_LOG("%s: comparing '%s' and '%s'\n", > > + __FUNCTION__, (char*)s1, (char*)s2); > > + } > > +#endif > > Why CONFIG_USER_ONLY ? s1 and s2 are target addresses and not valid on the host system in the SOFTMMU case, so this would segfault. > > +/* union used for splitting/joining 128-bit floats to/from 64-bit > > FP regs */ +typedef union { > > + struct { > > +#ifdef WORDS_BIGENDIAN > > + uint64_t h; > > + uint64_t l; > > +#else > > + uint64_t l; > > + uint64_t h; > > +#endif > > + }; > > + float128 x; > > +} FP128; > > WORDS_BIGENDIAN is wrong here. CPU_QuadU can probably be used instead. Agree. > > + if (float32_is_neg(v2)) { > > + v1 = float32_abs(v2); > > + } > > + else { > > + v1 = v2; > > + } > > I don't see the point of such a test here. Now that you mention it, I don't really see it either. > > + v2.i = ldl(a2); > > The value should be passed directly instead of loaded here, as ldl is > is wrong depending on the MMU mode. Yup. > > +#ifdef WORDS_BIGENDIAN > > This is wrong. It should probably be HOST_WORDS_BIGENDIAN. I concur. > > +static TCGv load_reg(int reg) > > +{ > > + TCGv r = tcg_temp_new_i64(); > > +#ifdef TCGREGS > > + sync_reg32(reg); > > + tcg_gen_mov_i64(r, tcgregs[reg]); > > + return r; > > +#else > > + tcg_gen_ld_i64(r, cpu_env, offsetof(CPUState, regs[reg])); > > + return r; > > +#endif > > +} > > I don't really like implicit TCGv temp allocation. In other targets it > often has caused missing tcg_temp_free(). I did in fact run into problems with this and was thus forced to make sure that no tcg_temp_free()s are missing... :) > It should probably be > rewritten as load_reg(TCGv t, int reg). Later. This is the kind of change that you never get right on the first try, so I'd like to do that after everything went upstream. > For all register load/store, as already explained in the TCG sync op > patch, I am in favor of using the ld/st version (TCGREGS not defined). It doesn't perform. > > +static void gen_illegal_opcode(DisasContext *s) > > +{ > > + TCGv tmp = tcg_temp_new_i64(); > > + tcg_gen_movi_i64(tmp, 42); > > tcg_const_i64 could be used instead. Yes. Using the actual value for a specification exception instead of 42 might be a good idea as well. :) > > > + gen_helper_exception(tmp); > > Missing tcg_temp_free_i64(tmp); OK, so I missed _that_ one. Fine. Be like that if you want to. Illegal instructions are not that frequent anyway... > > + gen_helper_cmp_s32(cc, v1, tcg_const_i32(v2)); > > The TCG passed to the helper should be freed. And that one... > > + gen_helper_cmp_u32(cc, v1, tcg_const_i32(v2)); > > Same. And that one... :( > > + gen_helper_cmp_s64(cc, v1, tcg_const_i64(v2)); > > Same And that one... :(( > > + gen_helper_cmp_u64(cc, v1, tcg_const_i64(v2)); > > Same And that one... :((( > The branches should be handled using brcond and goto_tb and exit_tb > and not with helpers, to allow TB chaining. I'll look into that, but I guess it's not entirely trivial. > > + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; > > This is wrong. 0 maps to global 0 (env in your case). -1 should be > used instead, or even better the TCGV_UNUSED macro. OK. > > + case 0x12: /* LT R1,D2(X2,B2) [RXY] */ > > + tmp2 = tcg_temp_new_i32(); > > Wrong TCGv type. > > > + tcg_gen_qemu_ld32s(tmp2, tmp, 1); > > tcg_gen_qemu_ld32s loads a 32 bit value in the default size register, > that is 64-bit here. Actually, this a purely 32-bit insn, so it should be tcg_gen_qemu_ld32() in the first place. > > + tcg_gen_qemu_ld32s(tmp2, tmp, 1); > > + tcg_gen_ext32s_i64(tmp2, tmp2); > > The sign extension is already done by qemu_ld32s Just to be on the safe side. :) > > + switch (op) { > > + case 0x8: case 0x18: gen_set_cc_add64(tmp, tmp2, tmp3); > > break; + case 0xa: case 0x1a: gen_helper_set_cc_addu64(cc, > > tmp, tmp2, tmp3); break; + default: tcg_abort(); > > tcg_abort() is wrong here, it is for internal TCG use. Also all the > real CPU it probably launch an illegal instruction exception, it does > not power off the machin. Actually, if default is reached here there's an error in the translator (it should only get here in the explicit cases), so I'd consider tcg_abort() appropriate. > > + case 0x1e: /* LRV R1,D2(X2,B2) [RXY] */ > > + tmp2 = tcg_temp_new_i32(); > > Wrong TCGv type; > > > + tcg_gen_qemu_ld32u(tmp2, tmp, 1); > > + tcg_gen_bswap32_i32(tmp2, tmp2); > > Wrong TCGv type; > > > + store_reg(r1, tmp2); This is more wrong than you think, because this is a 32-bit insn, so it shouldn't overwrite the top 32 bits. Rarely used, I guess that's how it could slip through. > > + case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */ > > + tmp2 = load_reg32(r1); > > + tcg_gen_bswap32_i32(tmp2, tmp2); > > + tcg_gen_qemu_st32(tmp2, tmp, 1); > > Wrong TCGv type. What's wrong here? Everything's 32-bit. > > + case 0x57: /* XY R1,D2(X2,B2) [RXY] */ > > + tmp2 = load_reg32(r1); > > + tmp3 = tcg_temp_new_i32(); > > + tcg_gen_qemu_ld32u(tmp3, tmp, 1); > > + tcg_gen_xor_i32(tmp, tmp2, tmp3); > > + store_reg32(r1, tmp); > > + set_cc_nz_u32(tmp); > > Wrong TCGv type. No need to zero-extend anyway, it's a 32-bit insn. > > + case 0x76: /* LB R1,D2(X2,B2) [RXY] */ > > + case 0x77: /* LGB R1,D2(X2,B2) [RXY] */ > > + tmp2 = tcg_temp_new_i64(); > > + tcg_gen_qemu_ld8s(tmp2, tmp, 1); > > + switch (op) { > > + case 0x76: > > + tcg_gen_ext8s_i32(tmp2, tmp2); > > Wrong TCGv type. > > > + store_reg32(r1, tmp2); > > + break; > > + case 0x77: > > + tcg_gen_ext8s_i64(tmp2, tmp2); > > Wrong TCGv type. The way I see it, there are only 32-bit and 64-bit types, so it can only be wrong in one case, right? > > + case 0x78: /* LHY R1,D2(X2,B2) [RXY] */ > > + tmp2 = tcg_temp_new_i32(); > > Wrong TCGv type. > > > + tcg_gen_qemu_ld16s(tmp2, tmp, 1); > > + tcg_gen_ext16s_i32(tmp2, tmp2); > > + store_reg32(r1, tmp2); > > + break; Replacing that tcg_gen_qemu_ld16s() with tcg_gen_qemu_ld16() should do it, right? > > + case 0x86: /* MLG R1,D2(X2,B2) [RXY] */ > > + tmp2 = tcg_temp_new_i64(); > > + tcg_gen_qemu_ld64(tmp2, tmp, 1); > > + tmp = tcg_const_i32(r1); > > Wrong TCGv type. > > > + gen_helper_mlg(tmp, tmp2); Huh? It's a register number. There are only 16 GP registers. Fits a 32-bit value, last time I checked. The helper also expects a 32-bit value. > > + if (tmp2) tcg_temp_free(tmp2); > > + if (tmp3) tcg_temp_free(tmp3); > > Comparison on TCGv type is not allowed. Not even to TCGV_UNUSED? > > +static void disas_ed(DisasContext *s, int op, int r1, int x2, int > > b2, int d2, int r1b) +{ > > + TCGv tmp, tmp2, tmp3 = 0; > > tmp should be declared as TGV_i32 here, so that the types are correct > for the whole function. Also tmp3 should not be initialized to 0. OK. > > + gen_helper_madb(tmp3, tmp2, tmp); > > tmp3 should be freed after the helper. Yup. > > + LOG_DISAS("disas_c0: op 0x%x r1 %d i2 %d\n", op, r1, i2); > > + uint64_t target = s->pc + i2 * 2; > > + /* FIXME: huh? */ target &= 0xffffffff; > > That should be fixed before a merge. Tricky, because I have not yet understood why it is necessary. According to the POP, the address calculation in 64-bit addressing mode should be 64 bits. In practice, on a real machine running a real Linux kernel, it wraps around at 32 bits, and userland code actually relies on that. No clue what I could be missing here... > > +static inline uint64_t ld_code2(uint64_t pc) { return > > (uint64_t)lduw_code(pc); } > > Coding style. OK. > > +#if 1 > > + cc = tcg_temp_local_new_i32(); > > + tcg_gen_mov_i32(cc, global_cc); > > +#else > > + cc = global_cc; > > +#endif > > Why this? Because it didn't work otherwise. I don't claim to understand the mysterious ways of the TCG to its full extent... > > + } while (!dc.is_jmp && gen_opc_ptr < gen_opc_end && dc.pc < > > next_page_start && num_insns < max_insns); > > The also translation should be stopped if in singlestep mode > (singlestep variable). OK. Phew, that was a big one. :) Thanks for reviewing. I'll fix what makes sense to me and send a new one when I'm done. CU Uli
On Mon, Oct 19, 2009 at 07:17:18PM +0200, Ulrich Hecht wrote: > On Saturday 17 October 2009, Aurelien Jarno wrote: > > On Fri, Oct 16, 2009 at 02:38:48PM +0200, Ulrich Hecht wrote: > > First of all a few general comments. Note that I know very few things > > about S390/S390X, so I may have dumb comments/questions. Also as the > > patch is very long, I probably have missed things, we should probably > > iterate with new versions of the patches. > > > > Is it possible given the current implementation to emulate S390 in > > addition to S390X? > > Not as it stands. The S/390 instruction set is a subset of zArch > (64-bit), but currently only 64-bit addressing is implemented (because > that is the only mode used by 64-bit Linux binaries). > > > If yes how different would be a S390 only target? > > It would need support for 31-bit addressing. 24-bit, too, if you want to > run the really old stuff. > > > If they won't be too different, it probably worth using _tl type > > registers and call it target-s390. A bit the way it is done with > > i386/x86_64, ppc/ppc64, mips/mips64 or sparc/sparc64. > > If it's going to be implemented, it will certainly share most code with > the 64-bit target, so having a common directory would most likely be a > good idea. > > There are some cases where _tl types might be appropriate, but generally > everything that is shared between S/390 and zArch is 32-bit, and > instructions present in both architectures also have the same operand > size: L, for instance, is a 32-bit load to a 32-bit register on both > architectures. Ok, so I think we should go for putting the code is the target-s390 directory. As no code is shared for now, we can just ignore the _tl stuff. > > Secondly there seems to be a lot of mix between 32-bit and 64-bit > > TCG registers. They should not be mixed. _i32 ops apply to TCGv_i32 > > variables, _i64 ops apply to TCGv_i64 variables, and _tl ops to TGCv > > variables. TCGv/_tl types can map either to _i32 or _i64 depending on > > your target. You should try to build the target with > > --enable-debug-tcg > > Er, reading the code and observing the behavior of the (AMD64) code > generator, it seemed to me that neither frontends nor backends care one > bit about that. I'll look into it, though. (I won't comment on those > below, except in cases where the solution or, indeed, the problem is not > clear to me.) It is not strictly needed on AMD64, because a move between 32- and 64- bit registers also zero extends the value. It is definitely needs on other hosts (and most probably s390x as I understand). > > It would be nice to split all the disassembling part in a separate > > combined with the related makefile changes. This way it can be applied > > separately. > > Can do. > > > > // switch (info->mach) > > > // { > > > // case bfd_mach_s390_31: > > > - current_arch_mask = 1 << S390_OPCODE_ESA; > > > +// current_arch_mask = 1 << S390_OPCODE_ESA; > > > // break; > > > // case bfd_mach_s390_64: > > > -// current_arch_mask = 1 << S390_OPCODE_ZARCH; > > > + current_arch_mask = 1 << S390_OPCODE_ZARCH; > > > // break; > > > // default: > > > // abort (); > > > > While I understand the second part, Why is it necessary to comment the > > bfd_mach_s390_31 case? > > It's not necessary, but current_arch_mask can only hold one value... I'll answer in the new version of the patch. > > > > + /* FIXME: reset vector? */ > > > > Yes, reset vector, MMU mode, default register values, ... > > Works perfectly fine without. ;) > > Also, the question remains what kind of reset cpu_reset() is supposed to > be. For instance, a CPU Reset or Initial CPU Reset on S/390 leaves the > general-purpose registers unchanged, a Clear Reset or Power-On Reset > sets them to zero. See the table on p. 4-50 in the zArchitecture > Principles of Operation (POP), > http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/download/A2278324.pdf, > for the gory details. I don't know what is the best, probably a CPU Reset is enough. Just consider that as the code that will be run if someone press the reset button. > > > + for (i = 0; i <= l; i++) { > > > + x = ldub(dest + i) & ldub(src + i); > > > + if (x) cc = 1; > > > > coding style > > Maybe you are referring to "Every indented statement is braced; even if > the block contains just one statement.", but I figured that that does > not apply here because there is no indentation... You are basically trying to workaround the coding style. The idea behind it is to write: if (x) { cc = 1; } > > All the branch part would really gain to be coded in TCG, as it will > > allow TB chaining. > > I vaguely remember trying that as well, but I don't know if I gave up on > it because it was slower, or because I couldn't get it to work... Probably the second. Changing the instruction pointer in the helper instead of using the proper goto_tb TCG op prevents TB chaining, and therefore as a huge impact on performance. It's something not difficult to implement, and that I would definitely want to see in the patch before getting it merged. > > It should probably be > > rewritten as load_reg(TCGv t, int reg). > > Later. This is the kind of change that you never get right on the first > try, so I'd like to do that after everything went upstream. It also means huge patch difficult to review when it is done after the initial merge, as they need to be checked within the context. > > > + tmp = tcg_const_i32(r1); > > > > Wrong TCGv type. > > > > > + gen_helper_mlg(tmp, tmp2); > > Huh? It's a register number. There are only 16 GP registers. Fits a > 32-bit value, last time I checked. The helper also expects a 32-bit > value. Then a TCGv_i32 variable should be used. TCGv is 64-bit, as the whole target is 64-bit. > > > + if (tmp2) tcg_temp_free(tmp2); > > > + if (tmp3) tcg_temp_free(tmp3); > > > > Comparison on TCGv type is not allowed. > > Not even to TCGV_UNUSED? TCGV_UNUSED() is a macro to set the value, not to retrieve it. > > > + LOG_DISAS("disas_c0: op 0x%x r1 %d i2 %d\n", op, r1, i2); > > > + uint64_t target = s->pc + i2 * 2; > > > + /* FIXME: huh? */ target &= 0xffffffff; > > > > That should be fixed before a merge. > > Tricky, because I have not yet understood why it is necessary. According > to the POP, the address calculation in 64-bit addressing mode should be > 64 bits. In practice, on a real machine running a real Linux kernel, it > wraps around at 32 bits, and userland code actually relies on that. No > clue what I could be missing here... Does it means the userspace is actually limited to 32-bit addressing? > > > +#if 1 > > > + cc = tcg_temp_local_new_i32(); > > > + tcg_gen_mov_i32(cc, global_cc); > > > +#else > > > + cc = global_cc; > > > +#endif > > > > Why this? > > Because it didn't work otherwise. I don't claim to understand the > mysterious ways of the TCG to its full extent... What do you mean by didn't work? TCG error? Wrong emulation? Something else?
diff --git a/cpu-exec.c b/cpu-exec.c index 8aa92c7..6b3391c 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -249,6 +249,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_MIPS) #elif defined(TARGET_SH4) #elif defined(TARGET_CRIS) +#elif defined(TARGET_S390X) /* XXXXX */ #else #error unsupported target CPU @@ -673,6 +674,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_SH4) #elif defined(TARGET_ALPHA) #elif defined(TARGET_CRIS) +#elif defined(TARGET_S390X) /* XXXXX */ #else #error unsupported target CPU diff --git a/disas.c b/disas.c index ce342bc..14c8901 100644 --- a/disas.c +++ b/disas.c @@ -195,6 +195,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) #elif defined(TARGET_CRIS) disasm_info.mach = bfd_mach_cris_v32; print_insn = print_insn_crisv32; +#elif defined(TARGET_S390X) + disasm_info.mach = bfd_mach_s390_64; + print_insn = print_insn_s390; #elif defined(TARGET_MICROBLAZE) disasm_info.mach = bfd_arch_microblaze; print_insn = print_insn_microblaze; diff --git a/s390-dis.c b/s390-dis.c index 86dd84f..9a73a57 100644 --- a/s390-dis.c +++ b/s390-dis.c @@ -191,10 +191,10 @@ init_disasm (struct disassemble_info *info) // switch (info->mach) // { // case bfd_mach_s390_31: - current_arch_mask = 1 << S390_OPCODE_ESA; +// current_arch_mask = 1 << S390_OPCODE_ESA; // break; // case bfd_mach_s390_64: -// current_arch_mask = 1 << S390_OPCODE_ZARCH; + current_arch_mask = 1 << S390_OPCODE_ZARCH; // break; // default: // abort (); diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h new file mode 100644 index 0000000..93b09cd --- /dev/null +++ b/target-s390x/cpu.h @@ -0,0 +1,132 @@ +/* + * S/390 virtual CPU header + * + * Copyright (c) 2009 Ulrich Hecht + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ +#ifndef CPU_S390X_H +#define CPU_S390X_H + +#define TARGET_LONG_BITS 64 + +#define ELF_MACHINE EM_S390 + +#define CPUState struct CPUS390XState + +#include "cpu-defs.h" + +#include "softfloat.h" + +#define NB_MMU_MODES 2 // guess +#define MMU_USER_IDX 0 // guess + +typedef union FPReg { + struct { +#ifdef WORDS_BIGENDIAN + float32 e; + int32_t __pad; +#else + int32_t __pad; + float32 e; +#endif + }; + float64 d; + uint64_t i; +} FPReg; + +typedef struct CPUS390XState { + uint64_t regs[16]; /* GP registers */ + + uint32_t aregs[16]; /* access registers */ + + uint32_t fpc; /* floating-point control register */ + FPReg fregs[16]; /* FP registers */ + float_status fpu_status; /* passed to softfloat lib */ + + struct { + uint64_t mask; + uint64_t addr; + } psw; + + int cc; /* condition code (0-3) */ + + uint64_t __excp_addr; + + CPU_COMMON +} CPUS390XState; + +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) + env->regs[15] = newsp; + env->regs[0] = 0; +} +#endif + +CPUS390XState *cpu_s390x_init(const char *cpu_model); +void s390x_translate_init(void); +int cpu_s390x_exec(CPUS390XState *s); +void cpu_s390x_close(CPUS390XState *s); +void do_interrupt (CPUState *env); + +/* you can call this signal handler from your SIGBUS and SIGSEGV + signal handlers to inform the virtual CPU of exceptions. non zero + is returned if the signal was handled by the virtual CPU. */ +int cpu_s390x_signal_handler(int host_signum, void *pinfo, + void *puc); +int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw, + int mmu_idx, int is_softmuu); +#define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault + +void cpu_lock(void); +void cpu_unlock(void); + +static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) +{ + env->aregs[0] = newtls >> 32; + env->aregs[1] = newtls & 0xffffffffULL; +} + +#define TARGET_PAGE_BITS 12 // guess + +#define cpu_init cpu_s390x_init +#define cpu_exec cpu_s390x_exec +#define cpu_gen_code cpu_s390x_gen_code +#define cpu_signal_handler cpu_s390x_signal_handler +//#define cpu_list s390x_cpu_list + +#include "cpu-all.h" +#include "exec-all.h" + +#define EXCP_OPEX 1 /* operation exception (sigill) */ +#define EXCP_SVC 2 /* supervisor call (syscall) */ +#define EXCP_ADDR 5 /* addressing exception */ +#define EXCP_EXECUTE_SVC 0xff00000 /* supervisor call via execute insn */ + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock* tb) +{ + env->psw.addr = tb->pc; +} + +static inline void cpu_get_tb_cpu_state(CPUState* env, target_ulong *pc, + target_ulong *cs_base, int *flags) +{ + *pc = env->psw.addr; + *cs_base = 0; + *flags = env->psw.mask; // guess +} +#endif diff --git a/target-s390x/exec.h b/target-s390x/exec.h new file mode 100644 index 0000000..5198359 --- /dev/null +++ b/target-s390x/exec.h @@ -0,0 +1,51 @@ +/* + * S/390 execution defines + * + * Copyright (c) 2009 Ulrich Hecht + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ + +#include "dyngen-exec.h" + +register struct CPUS390XState *env asm(AREG0); + +#include "cpu.h" +#include "exec-all.h" + +static inline int cpu_has_work(CPUState *env) +{ + return env->interrupt_request & CPU_INTERRUPT_HARD; // guess +} + +static inline void regs_to_env(void) +{ +} + +static inline void env_to_regs(void) +{ +} + +static inline int cpu_halted(CPUState *env) +{ + if (!env->halted) { + return 0; + } + if (cpu_has_work(env)) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} diff --git a/target-s390x/helper.c b/target-s390x/helper.c new file mode 100644 index 0000000..5407c62 --- /dev/null +++ b/target-s390x/helper.c @@ -0,0 +1,81 @@ +/* + * S/390 helpers + * + * Copyright (c) 2009 Ulrich Hecht + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "cpu.h" +#include "exec-all.h" +#include "gdbstub.h" +#include "qemu-common.h" + +CPUS390XState *cpu_s390x_init(const char *cpu_model) +{ + CPUS390XState *env; + static int inited = 0; + + env = qemu_mallocz(sizeof(CPUS390XState)); + cpu_exec_init(env); + if (!inited) { + inited = 1; + s390x_translate_init(); + } + + env->cpu_model_str = cpu_model; + cpu_reset(env); + qemu_init_vcpu(env); + return env; +} + +#if defined(CONFIG_USER_ONLY) + +void do_interrupt (CPUState *env) +{ + env->exception_index = -1; +} + +int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int mmu_idx, int is_softmmu) +{ + //fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d is_softmmu %d\n", __FUNCTION__, address, rw, mmu_idx, is_softmmu); + env->exception_index = EXCP_ADDR; + env->__excp_addr = address; /* FIXME: find out how this works on a real machine */ + return 1; +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) +{ + return addr; +} + +#endif /* CONFIG_USER_ONLY */ + +void cpu_reset(CPUS390XState *env) +{ + if (qemu_loglevel_mask(CPU_LOG_RESET)) { + qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + log_cpu_state(env, 0); + } + + memset(env, 0, offsetof(CPUS390XState, breakpoints)); + /* FIXME: reset vector? */ + tlb_flush(env, 1); +} diff --git a/target-s390x/helpers.h b/target-s390x/helpers.h new file mode 100644 index 0000000..0ba2086 --- /dev/null +++ b/target-s390x/helpers.h @@ -0,0 +1,128 @@ +#include "def-helper.h" + +DEF_HELPER_1(exception, void, i32) +DEF_HELPER_4(nc, i32, i32, i32, i32, i32) +DEF_HELPER_4(oc, i32, i32, i32, i32, i32) +DEF_HELPER_4(xc, i32, i32, i32, i32, i32) +DEF_HELPER_4(mvc, void, i32, i32, i32, i32) +DEF_HELPER_4(clc, i32, i32, i32, i32, i32) +DEF_HELPER_4(lmg, void, i32, i32, i32, s32) +DEF_HELPER_4(stmg, void, i32, i32, i32, s32) +DEF_HELPER_FLAGS_1(set_cc_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) +DEF_HELPER_FLAGS_1(set_cc_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64) +DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) +DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64) +DEF_HELPER_FLAGS_1(set_cc_nz_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32) +DEF_HELPER_FLAGS_1(set_cc_nz_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64) +DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) +DEF_HELPER_4(brc, void, i32, i32, i64, s32) +DEF_HELPER_3(brctg, void, i64, i64, s32) +DEF_HELPER_3(brct, void, i32, i64, s32) +DEF_HELPER_4(brcl, void, i32, i32, i64, s64) +DEF_HELPER_4(bcr, void, i32, i32, i64, i64) +DEF_HELPER_4(bc, void, i32, i32, i64, i64) +DEF_HELPER_FLAGS_2(cmp_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64) +DEF_HELPER_FLAGS_2(cmp_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) +DEF_HELPER_FLAGS_2(cmp_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32) +DEF_HELPER_FLAGS_2(cmp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64) +DEF_HELPER_3(clm, i32, i32, i32, i64) +DEF_HELPER_3(stcm, void, i32, i32, i64) +DEF_HELPER_2(mlg, void, i32, i64) +DEF_HELPER_2(dlg, void, i32, i64) +DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) +DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) +DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) +DEF_HELPER_FLAGS_3(set_cc_addu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) +DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) +DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) +DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) +DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) +DEF_HELPER_3(srst, i32, i32, i32, i32) +DEF_HELPER_3(clst, i32, i32, i32, i32) +DEF_HELPER_3(mvst, i32, i32, i32, i32) +DEF_HELPER_3(csg, i32, i32, i64, i32) +DEF_HELPER_3(cdsg, i32, i32, i64, i32) +DEF_HELPER_3(cs, i32, i32, i64, i32) +DEF_HELPER_4(ex, i32, i32, i64, i64, i64) +DEF_HELPER_FLAGS_2(tm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) +DEF_HELPER_FLAGS_2(tmxx, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i32) +DEF_HELPER_2(abs_i32, i32, i32, s32) +DEF_HELPER_2(nabs_i32, i32, i32, s32) +DEF_HELPER_2(abs_i64, i32, i32, s64) +DEF_HELPER_2(nabs_i64, i32, i32, s64) +DEF_HELPER_3(stcmh, i32, i32, i64, i32) +DEF_HELPER_3(icmh, i32, i32, i64, i32) +DEF_HELPER_2(ipm, void, i32, i32) +DEF_HELPER_3(addc_u32, i32, i32, i32, i32) +DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) +DEF_HELPER_3(stam, void, i32, i64, i32) +DEF_HELPER_3(mvcle, i32, i32, i64, i32) +DEF_HELPER_3(clcle, i32, i32, i64, i32) +DEF_HELPER_4(slb, i32, i32, i32, i32, i32) +DEF_HELPER_4(slbg, i32, i32, i32, i64, i64) +DEF_HELPER_2(cefbr, void, i32, s32) +DEF_HELPER_2(cdfbr, void, i32, s32) +DEF_HELPER_2(cxfbr, void, i32, s32) +DEF_HELPER_2(cegbr, void, i32, s64) +DEF_HELPER_2(cdgbr, void, i32, s64) +DEF_HELPER_2(cxgbr, void, i32, s64) +DEF_HELPER_2(adbr, i32, i32, i32) +DEF_HELPER_2(aebr, i32, i32, i32) +DEF_HELPER_2(sebr, i32, i32, i32) +DEF_HELPER_2(sdbr, i32, i32, i32) +DEF_HELPER_2(debr, void, i32, i32) +DEF_HELPER_2(dxbr, void, i32, i32) +DEF_HELPER_2(mdbr, void, i32, i32) +DEF_HELPER_2(mxbr, void, i32, i32) +DEF_HELPER_2(ldebr, void, i32, i32) +DEF_HELPER_2(ldxbr, void, i32, i32) +DEF_HELPER_2(lxdbr, void, i32, i32) +DEF_HELPER_2(ledbr, void, i32, i32) +DEF_HELPER_2(lexbr, void, i32, i32) +DEF_HELPER_2(lpebr, i32, i32, i32) +DEF_HELPER_2(lpdbr, i32, i32, i32) +DEF_HELPER_2(lpxbr, i32, i32, i32) +DEF_HELPER_2(ltebr, i32, i32, i32) +DEF_HELPER_2(ltdbr, i32, i32, i32) +DEF_HELPER_2(ltxbr, i32, i32, i32) +DEF_HELPER_2(lcebr, i32, i32, i32) +DEF_HELPER_2(lcdbr, i32, i32, i32) +DEF_HELPER_2(lcxbr, i32, i32, i32) +DEF_HELPER_2(ceb, i32, i32, i64) +DEF_HELPER_2(aeb, i32, i32, i64) +DEF_HELPER_2(deb, void, i32, i64) +DEF_HELPER_2(meeb, void, i32, i64) +DEF_HELPER_2(cdb, i32, i32, i64) +DEF_HELPER_2(adb, i32, i32, i64) +DEF_HELPER_2(seb, i32, i32, i64) +DEF_HELPER_2(sdb, i32, i32, i64) +DEF_HELPER_2(mdb, void, i32, i64) +DEF_HELPER_2(ddb, void, i32, i64) +DEF_HELPER_FLAGS_2(cebr, TCG_CALL_PURE, i32, i32, i32) +DEF_HELPER_FLAGS_2(cdbr, TCG_CALL_PURE, i32, i32, i32) +DEF_HELPER_FLAGS_2(cxbr, TCG_CALL_PURE, i32, i32, i32) +DEF_HELPER_3(cgebr, i32, i32, i32, i32) +DEF_HELPER_3(cgdbr, i32, i32, i32, i32) +DEF_HELPER_3(cgxbr, i32, i32, i32, i32) +DEF_HELPER_1(lzer, void, i32) +DEF_HELPER_1(lzdr, void, i32) +DEF_HELPER_1(lzxr, void, i32) +DEF_HELPER_3(cfebr, i32, i32, i32, i32) +DEF_HELPER_3(cfdbr, i32, i32, i32, i32) +DEF_HELPER_3(cfxbr, i32, i32, i32, i32) +DEF_HELPER_2(axbr, i32, i32, i32) +DEF_HELPER_2(sxbr, i32, i32, i32) +DEF_HELPER_2(meebr, void, i32, i32) +DEF_HELPER_2(ddbr, void, i32, i32) +DEF_HELPER_3(madb, void, i32, i64, i32) +DEF_HELPER_3(maebr, void, i32, i32, i32) +DEF_HELPER_3(madbr, void, i32, i32, i32) +DEF_HELPER_3(msdbr, void, i32, i32, i32) +DEF_HELPER_2(lxdb, void, i32, i64) +DEF_HELPER_FLAGS_2(tceb, TCG_CALL_PURE, i32, i32, i64) +DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_PURE, i32, i32, i64) +DEF_HELPER_FLAGS_2(tcxb, TCG_CALL_PURE, i32, i32, i64) +DEF_HELPER_2(flogr, i32, i32, i64) +DEF_HELPER_2(sqdbr, void, i32, i32) + +#include "def-helper.h" diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c new file mode 100644 index 0000000..5de4d08 --- /dev/null +++ b/target-s390x/op_helper.c @@ -0,0 +1,1719 @@ +/* + * S/390 helper routines + * + * Copyright (c) 2009 Ulrich Hecht + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ + +#include "exec.h" +#include "helpers.h" +#include <string.h> + +//#define DEBUG_HELPER +#ifdef DEBUG_HELPER +#define HELPER_LOG(x...) qemu_log(x) +#else +#define HELPER_LOG(x...) +#endif + +/* raise an exception */ +void HELPER(exception)(uint32_t excp) +{ + HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp); + env->exception_index = excp; + cpu_loop_exit(); +} + +/* and on array */ +uint32_t HELPER(nc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) +{ + uint64_t dest = env->regs[b >> 4] + d1; + uint64_t src = env->regs[b & 0xf] + d2; + int i; + unsigned char x; + uint32_t cc = 0; + HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); + for (i = 0; i <= l; i++) { + x = ldub(dest + i) & ldub(src + i); + if (x) cc = 1; + stb(dest + i, x); + } + return cc; +} + +/* xor on array */ +uint32_t HELPER(xc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) +{ + uint64_t dest = env->regs[b >> 4] + d1; + uint64_t src = env->regs[b & 0xf] + d2; + int i; + unsigned char x; + uint32_t cc = 0; + HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); + for (i = 0; i <= l; i++) { + x = ldub(dest + i) ^ ldub(src + i); + if (x) cc = 1; + stb(dest + i, x); + } + return cc; +} + +/* or on array */ +uint32_t HELPER(oc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) +{ + uint64_t dest = env->regs[b >> 4] + d1; + uint64_t src = env->regs[b & 0xf] + d2; + int i; + unsigned char x; + uint32_t cc = 0; + HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); + for (i = 0; i <= l; i++) { + x = ldub(dest + i) | ldub(src + i); + if (x) cc = 1; + stb(dest + i, x); + } + return cc; +} + +/* memcopy */ +void HELPER(mvc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) +{ + uint64_t dest = env->regs[b >> 4] + d1; + uint64_t src = env->regs[b & 0xf] + d2; + int i; + HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); + for (i = 0; i <= l; i++) { + stb(dest + i, ldub(src + i)); + } +} + +/* compare unsigned byte arrays */ +uint32_t HELPER(clc)(uint32_t l, uint32_t b, uint32_t d1, uint32_t d2) +{ + uint64_t s1 = env->regs[b >> 4] + d1; + uint64_t s2 = env->regs[b & 0xf] + d2; + int i; + unsigned char x,y; + uint32_t cc; + HELPER_LOG("%s l %d b 0x%x d1 %d d2 %d\n", __FUNCTION__, l, b, d1, d2); + for (i = 0; i <= l; i++) { + x = ldub(s1 + i); + y = ldub(s2 + i); + HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y); + if (x < y) { + cc = 1; + goto done; + } + else if (x > y) { + cc = 2; + goto done; + } + } + cc = 0; +done: + HELPER_LOG("\n"); + return cc; +} + +/* load multiple 64-bit registers from memory */ +void HELPER(lmg)(uint32_t r1, uint32_t r3, uint32_t b2, int d2) +{ + uint64_t src = env->regs[b2] + d2; + for (;;) { + env->regs[r1] = ldq(src); + src += 8; + if (r1 == r3) break; + r1 = (r1 + 1) & 15; + } +} + +/* store multiple 64-bit registers to memory */ +void HELPER(stmg)(uint32_t r1, uint32_t r3, uint32_t b2, int d2) +{ + uint64_t dest = env->regs[b2] + d2; + HELPER_LOG("%s: r1 %d r3 %d\n", __FUNCTION__, r1, r3); + for (;;) { + HELPER_LOG("storing r%d in 0x%lx\n", r1, dest); + stq(dest, env->regs[r1]); + dest += 8; + if (r1 == r3) break; + r1 = (r1 + 1) & 15; + } +} + +/* set condition code for signed 32-bit arithmetics */ +uint32_t HELPER(set_cc_s32)(int32_t v) +{ + if (v < 0) return 1; + else if (v > 0) return 2; + else return 0; +} + +/* set condition code for signed 64-bit arithmetics */ +uint32_t HELPER(set_cc_s64)(int64_t v) +{ + if (v < 0) return 1; + else if (v > 0) return 2; + else return 0; +} + +/* set condition code for signed 32-bit two's complement */ +uint32_t HELPER(set_cc_comp_s32)(int32_t v) +{ + if ((uint32_t)v == 0x80000000UL) return 3; + else if (v < 0) return 1; + else if (v > 0) return 2; + else return 0; +} + +/* set condition code for signed 64-bit two's complement */ +uint32_t HELPER(set_cc_comp_s64)(int64_t v) +{ + if ((uint64_t)v == 0x8000000000000000ULL) return 3; + else if (v < 0) return 1; + else if (v > 0) return 2; + else return 0; +} + +/* set negative/zero condition code for 32-bit logical op */ +uint32_t HELPER(set_cc_nz_u32)(uint32_t v) +{ + if (v) return 1; + else return 0; +} + +/* set negative/zero condition code for 64-bit logical op */ +uint32_t HELPER(set_cc_nz_u64)(uint64_t v) +{ + if (v) return 1; + else return 0; +} + +/* set condition code for insert character under mask insn */ +uint32_t HELPER(set_cc_icm)(uint32_t mask, uint32_t val) +{ + HELPER_LOG("%s: mask 0x%x val %d\n", __FUNCTION__, mask, val); + uint32_t cc; + if (!val || !mask) cc = 0; + else { + while (mask != 1) { + mask >>= 1; + val >>= 8; + } + if (val & 0x80) cc = 1; + else cc = 2; + } + return cc; +} + +/* relative conditional branch */ +void HELPER(brc)(uint32_t cc, uint32_t mask, uint64_t pc, int32_t offset) +{ + if ( mask & ( 1 << (3 - cc) ) ) { + env->psw.addr = pc + offset; + } + else { + env->psw.addr = pc + 4; + } +} + +/* branch relative on 64-bit count (condition is computed inline, this only + does the branch */ +void HELPER(brctg)(uint64_t flag, uint64_t pc, int32_t offset) +{ + if (flag) { + env->psw.addr = pc + offset; + } + else { + env->psw.addr = pc + 4; + } + HELPER_LOG("%s: pc 0x%lx flag %ld psw.addr 0x%lx\n", __FUNCTION__, pc, flag, + env->psw.addr); +} + +/* branch relative on 32-bit count (condition is computed inline, this only + does the branch */ +void HELPER(brct)(uint32_t flag, uint64_t pc, int32_t offset) +{ + if (flag) { + env->psw.addr = pc + offset; + } + else { + env->psw.addr = pc + 4; + } + HELPER_LOG("%s: pc 0x%lx flag %d psw.addr 0x%lx\n", __FUNCTION__, pc, flag, + env->psw.addr); +} + +/* relative conditional branch with long displacement */ +void HELPER(brcl)(uint32_t cc, uint32_t mask, uint64_t pc, int64_t offset) +{ + if ( mask & ( 1 << (3 - cc) ) ) { + env->psw.addr = pc + offset; + } + else { + env->psw.addr = pc + 6; + } + HELPER_LOG("%s: pc 0x%lx psw.addr 0x%lx\n", __FUNCTION__, pc, env->psw.addr); +} + +/* conditional branch to register (register content is passed as target) */ +void HELPER(bcr)(uint32_t cc, uint32_t mask, uint64_t target, uint64_t pc) +{ + if ( mask & ( 1 << (3 - cc) ) ) { + env->psw.addr = target; + } + else { + env->psw.addr = pc + 2; + } +} + +/* conditional branch to address (address is passed as target) */ +void HELPER(bc)(uint32_t cc, uint32_t mask, uint64_t target, uint64_t pc) +{ + if ( mask & ( 1 << (3 - cc) ) ) { + env->psw.addr = target; + } + else { + env->psw.addr = pc + 4; + } + HELPER_LOG("%s: pc 0x%lx psw.addr 0x%lx r2 0x%lx r5 0x%lx\n", __FUNCTION__, + pc, env->psw.addr, env->regs[2], env->regs[5]); +} + +/* 64-bit unsigned comparison */ +uint32_t HELPER(cmp_u64)(uint64_t o1, uint64_t o2) +{ + if (o1 < o2) return 1; + else if (o1 > o2) return 2; + else return 0; +} + +/* 32-bit unsigned comparison */ +uint32_t HELPER(cmp_u32)(uint32_t o1, uint32_t o2) +{ + HELPER_LOG("%s: o1 0x%x o2 0x%x\n", __FUNCTION__, o1, o2); + if (o1 < o2) return 1; + else if (o1 > o2) return 2; + else return 0; +} + +/* 64-bit signed comparison */ +uint32_t HELPER(cmp_s64)(int64_t o1, int64_t o2) +{ + HELPER_LOG("%s: o1 %ld o2 %ld\n", __FUNCTION__, o1, o2); + if (o1 < o2) return 1; + else if (o1 > o2) return 2; + else return 0; +} + +/* 32-bit signed comparison */ +uint32_t HELPER(cmp_s32)(int32_t o1, int32_t o2) +{ + if (o1 < o2) return 1; + else if (o1 > o2) return 2; + else return 0; +} + +/* compare logical under mask */ +uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) +{ + uint8_t r,d; + uint32_t cc; + HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n",__FUNCTION__,r1,mask,addr); + cc = 0; + while (mask) { + if (mask & 8) { + d = ldub(addr); + r = (r1 & 0xff000000UL) >> 24; + HELPER_LOG("mask 0x%x %02x/%02x (0x%lx) ", mask, r, d, addr); + if (r < d) { + cc = 1; + break; + } + else if (r > d) { + cc = 2; + break; + } + addr++; + } + mask = (mask << 1) & 0xf; + r1 <<= 8; + } + HELPER_LOG("\n"); + return cc; +} + +/* store character under mask */ +void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) +{ + uint8_t r; + HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n",__FUNCTION__,r1,mask,addr); + while (mask) { + if (mask & 8) { + r = (r1 & 0xff000000UL) >> 24; + stb(addr, r); + HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); + addr++; + } + mask = (mask << 1) & 0xf; + r1 <<= 8; + } + HELPER_LOG("\n"); +} + +/* 64/64 -> 128 unsigned multiplication */ +void HELPER(mlg)(uint32_t r1, uint64_t v2) +{ + __uint128_t res = (__uint128_t)env->regs[r1 + 1]; + res *= (__uint128_t)v2; + env->regs[r1] = (uint64_t)(res >> 64); + env->regs[r1 + 1] = (uint64_t)res; +} + +/* 128 -> 64/64 unsigned division */ +void HELPER(dlg)(uint32_t r1, uint64_t v2) +{ + __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | + (env->regs[r1+1]); + uint64_t divisor = v2; + __uint128_t quotient = dividend / divisor; + env->regs[r1+1] = quotient; + __uint128_t remainder = dividend % divisor; + env->regs[r1] = remainder; + HELPER_LOG("%s: dividend 0x%016lx%016lx divisor 0x%lx quotient 0x%lx rem 0x%lx\n", + __FUNCTION__, (uint64_t)(dividend >> 64), (uint64_t)dividend, divisor, (uint64_t)quotient, + (uint64_t)remainder); +} + +/* set condition code for 64-bit signed addition */ +uint32_t HELPER(set_cc_add64)(int64_t a1, int64_t a2, int64_t ar) +{ + if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { + return 3; /* overflow */ + } + else { + if (ar < 0) return 1; + else if (ar > 0) return 2; + else return 0; + } +} + +/* set condition code for 64-bit unsigned addition */ +uint32_t HELPER(set_cc_addu64)(uint64_t a1, uint64_t a2, uint64_t ar) +{ + if (ar == 0) { + if (a1) return 2; + else return 0; + } + else { + if (ar < a1 || ar < a2) { + return 3; + } + else { + return 1; + } + } +} + +/* set condition code for 32-bit signed addition */ +uint32_t HELPER(set_cc_add32)(int32_t a1, int32_t a2, int32_t ar) +{ + if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { + return 3; /* overflow */ + } + else { + if (ar < 0) return 1; + else if (ar > 0) return 2; + else return 0; + } +} + +/* set condition code for 32-bit unsigned addition */ +uint32_t HELPER(set_cc_addu32)(uint32_t a1, uint32_t a2, uint32_t ar) +{ + if (ar == 0) { + if (a1) return 2; + else return 0; + } + else { + if (ar < a1 || ar < a2) { + return 3; + } + else { + return 1; + } + } +} + +/* set condition code for 64-bit signed subtraction */ +uint32_t HELPER(set_cc_sub64)(int64_t s1, int64_t s2, int64_t sr) +{ + if ((s1 > 0 && s2 < 0 && sr < 0) || (s1 < 0 && s2 > 0 && sr > 0)) { + return 3; /* overflow */ + } + else { + if (sr < 0) return 1; + else if (sr > 0) return 2; + else return 0; + } +} + +/* set condition code for 32-bit signed subtraction */ +uint32_t HELPER(set_cc_sub32)(int32_t s1, int32_t s2, int32_t sr) +{ + if ((s1 > 0 && s2 < 0 && sr < 0) || (s1 < 0 && s2 > 0 && sr > 0)) { + return 3; /* overflow */ + } + else { + if (sr < 0) return 1; + else if (sr > 0) return 2; + else return 0; + } +} + +/* set condition code for 32-bit unsigned subtraction */ +uint32_t HELPER(set_cc_subu32)(uint32_t s1, uint32_t s2, uint32_t sr) +{ + if (sr == 0) return 2; + else { + if (s2 > s1) return 1; + else return 3; + } +} + +/* set condition code for 64-bit unsigned subtraction */ +uint32_t HELPER(set_cc_subu64)(uint64_t s1, uint64_t s2, uint64_t sr) +{ + if (sr == 0) return 2; + else { + if (s2 > s1) return 1; + else return 3; + } +} + +/* search string (c is byte to search, r2 is string, r1 end of string) */ +uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) +{ + HELPER_LOG("%s: c %d *r1 0x%lx *r2 0x%lx\n", __FUNCTION__, c, env->regs[r1], + env->regs[r2]); + uint64_t i; + uint32_t cc; + for (i = env->regs[r2]; i != env->regs[r1]; i++) { + if (ldub(i) == c) { + env->regs[r1] = i; + cc = 1; + return cc; + } + } + cc = 2; + return cc; +} + +/* unsigned string compare (c is string terminator) */ +uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) +{ + uint64_t s1 = env->regs[r1]; + uint64_t s2 = env->regs[r2]; + uint8_t v1, v2; + uint32_t cc; + c = c & 0xff; +#ifdef CONFIG_USER_ONLY + if (!c) { + HELPER_LOG("%s: comparing '%s' and '%s'\n", + __FUNCTION__, (char*)s1, (char*)s2); + } +#endif + for (;;) { + v1 = ldub(s1); + v2 = ldub(s2); + if (v1 == c || v2 == c) break; + if (v1 != v2) break; + s1++; s2++; + } + + if (v1 == v2) cc = 0; + else { + if (v1 < v2) cc = 1; + else cc = 2; + env->regs[r1] = s1; + env->regs[r2] = s2; + } + return cc; +} + +/* string copy (c is string terminator) */ +uint32_t HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) +{ + uint64_t dest = env->regs[r1]; + uint64_t src = env->regs[r2]; + uint8_t v; + c = c & 0xff; +#ifdef CONFIG_USER_ONLY + if (!c) { + HELPER_LOG("%s: copying '%s' to 0x%lx\n", __FUNCTION__, (char*)src, dest); + } +#endif + for (;;) { + v = ldub(src); + stb(dest, v); + if (v == c) break; + src++; dest++; + } + env->regs[r1] = dest; + return 1; +} + +/* compare and swap 64-bit */ +uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + /* FIXME: locking? */ + uint32_t cc; + uint64_t v2 = ldq(a2); + if (env->regs[r1] == v2) { + cc = 0; + stq(a2, env->regs[r3]); + } + else { + cc = 1; + env->regs[r1] = v2; + } + return cc; +} + +/* compare double and swap 64-bit */ +uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + /* FIXME: locking? */ + uint32_t cc; + __uint128_t v2 = (((__uint128_t)ldq(a2)) << 64) | (__uint128_t)ldq(a2 + 8); + __uint128_t v1 = (((__uint128_t)env->regs[r1]) << 64) | (__uint128_t)env->regs[r1 + 1]; + if (v1 == v2) { + cc = 0; + stq(a2, env->regs[r3]); + stq(a2 + 8, env->regs[r3 + 1]); + } + else { + cc = 1; + env->regs[r1] = v2 >> 64; + env->regs[r1 + 1] = v2 & 0xffffffffffffffffULL; + } + return cc; +} + +/* compare and swap 32-bit */ +uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + /* FIXME: locking? */ + uint32_t cc; + HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __FUNCTION__, r1, a2, r3); + uint32_t v2 = ldl(a2); + if (((uint32_t)env->regs[r1]) == v2) { + cc = 0; + stl(a2, (uint32_t)env->regs[r3]); + } + else { + cc = 1; + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; + } + return cc; +} + +/* execute instruction + this instruction executes an insn modified with the contents of r1 + it does not change the executed instruction in memory + it does not change the program counter + in other words: tricky... + currently implemented by interpreting the cases it is most commonly used in + */ +uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) +{ + uint16_t insn = lduw(addr); + HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __FUNCTION__, v1, addr, + insn); + if ((insn & 0xf0ff) == 0xd000) { + uint32_t l, insn2, b, d1, d2; + l = v1 & 0xff; + insn2 = ldl(addr + 2); + b = (((insn2 >> 28) & 0xf) << 4) | ((insn2 >> 12) & 0xf); + d1 = (insn2 >> 16) & 0xfff; + d2 = insn2 & 0xfff; + switch (insn & 0xf00) { + case 0x200: helper_mvc(l, b, d1, d2); return cc; break; + case 0x500: return helper_clc(l, b, d1, d2); break; + case 0x700: return helper_xc(l, b, d1, d2); break; + default: helper_exception(23); break; + } + } + else if ((insn & 0xff00) == 0x0a00) { /* supervisor call */ + HELPER_LOG("%s: svc %ld via execute\n", __FUNCTION__, (insn|v1) & 0xff); + env->psw.addr = ret; + helper_exception(EXCP_EXECUTE_SVC + ((insn | v1) & 0xff)); + } + else { + helper_exception(23); + } + return cc; +} + +/* set condition code for test under mask */ +uint32_t HELPER(tm)(uint32_t val, uint32_t mask) +{ + HELPER_LOG("%s: val 0x%x mask 0x%x\n", __FUNCTION__, val, mask); + uint16_t r = val & mask; + if (r == 0) return 0; + else if (r == mask) return 3; + else return 1; +} + +/* set condition code for test under mask */ +uint32_t HELPER(tmxx)(uint64_t val, uint32_t mask) +{ + uint16_t r = val & mask; + HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __FUNCTION__, val, mask, r); + if (r == 0) return 0; + else if (r == mask) return 3; + else { + while (!(mask & 0x8000)) { + mask <<= 1; + val <<= 1; + } + if (val & 0x8000) return 2; + else return 1; + } +} + +/* absolute value 32-bit */ +uint32_t HELPER(abs_i32)(uint32_t reg, int32_t val) +{ + uint32_t cc; + if (val == 0x80000000UL) cc = 3; + else if (val) cc = 1; + else cc = 0; + + if (val < 0) { + env->regs[reg] = -val; + } + else { + env->regs[reg] = val; + } + return cc; +} + +/* negative absolute value 32-bit */ +uint32_t HELPER(nabs_i32)(uint32_t reg, int32_t val) +{ + uint32_t cc; + if (val) cc = 1; + else cc = 0; + + if (val < 0) { + env->regs[reg] = (env->regs[reg] & 0xffffffff00000000ULL) | val; + } + else { + env->regs[reg] = (env->regs[reg] & 0xffffffff00000000ULL) | ((uint32_t)-val); + } + return cc; +} + +/* absolute value 64-bit */ +uint32_t HELPER(abs_i64)(uint32_t reg, int64_t val) +{ + uint32_t cc; + if (val == 0x8000000000000000ULL) cc = 3; + else if (val) cc = 1; + else cc = 0; + + if (val < 0) { + env->regs[reg] = -val; + } + else { + env->regs[reg] = val; + } + return cc; +} + +/* negative absolute value 64-bit */ +uint32_t HELPER(nabs_i64)(uint32_t reg, int64_t val) +{ + uint32_t cc; + if (val) cc = 1; + else cc = 0; + + if (val < 0) { + env->regs[reg] = val; + } + else { + env->regs[reg] = -val; + } + return cc; +} + +/* add with carry 32-bit unsigned */ +uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t r1, uint32_t v2) +{ + uint32_t res; + uint32_t v1 = env->regs[r1] & 0xffffffffUL; + res = v1 + v2; + if (cc & 2) res++; + + if (res == 0) { + if (v1) cc = 2; + else cc = 0; + } + else { + if (res < v1 || res < v2) + cc = 3; + else + cc = 1; + } + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; + return cc; +} + +/* CC for add with carry 64-bit unsigned (isn't this a duplicate of some other CC function?) */ +uint32_t HELPER(set_cc_addc_u64)(uint64_t v1, uint64_t v2, uint64_t res) +{ + uint32_t cc; + if (res == 0) { + if (v1) cc = 2; + else cc = 0; + } + else { + if (res < v1 || res < v2) { + cc = 3; + } + else { + cc = 1; + } + } + return cc; +} + +/* store character under mask high + operates on the upper half of r1 */ +uint32_t HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) +{ + int pos = 56; /* top of the upper half of r1 */ + + while (mask) { + if (mask & 8) { + stb(address, (env->regs[r1] >> pos) & 0xff); + address++; + } + mask = (mask << 1) & 0xf; + pos -= 8; + } + return 0; +} + +/* insert character under mask high + same as icm, but operates on the upper half of r1 */ +uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) +{ + int pos = 56; /* top of the upper half of r1 */ + uint64_t rmask = 0xff00000000000000ULL; + uint8_t val = 0; + int ccd = 0; + uint32_t cc; + + cc = 0; + + while (mask) { + if (mask & 8) { + env->regs[r1] &= ~rmask; + val = ldub(address); + if ((val & 0x80) && !ccd) cc = 1; + ccd = 1; + if (val && cc == 0) cc = 2; + env->regs[r1] |= (uint64_t)val << pos; + address++; + } + mask = (mask << 1) & 0xf; + pos -= 8; + rmask >>= 8; + } + return cc; +} + +/* insert psw mask and condition code into r1 */ +void HELPER(ipm)(uint32_t cc, uint32_t r1) +{ + uint64_t r = env->regs[r1]; + r &= 0xffffffff00ffffffULL; + r |= (cc << 28) | ( (env->psw.mask >> 40) & 0xf ); + env->regs[r1] = r; + HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __FUNCTION__, cc, env->psw.mask, r); +} + +/* store access registers r1 to r3 in memory at a2 */ +void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + for (i = r1; i != ((r3 + 1) & 15); i = (i + 1) & 15) { + stl(a2, env->aregs[i]); + a2 += 4; + } +} + +/* move long extended + another memcopy insn with more bells and whistles */ +uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + uint64_t destlen = env->regs[r1 + 1]; + uint64_t dest = env->regs[r1]; + uint64_t srclen = env->regs[r3 + 1]; + uint64_t src = env->regs[r3]; + uint8_t pad = a2 & 0xff; + uint8_t v; + uint32_t cc; + if (destlen == srclen) cc = 0; + else if (destlen < srclen) cc = 1; + else cc = 2; + if (srclen > destlen) srclen = destlen; + for(;destlen && srclen;src++,dest++,destlen--,srclen--) { + v = ldub(src); + stb(dest, v); + } + for(;destlen;dest++,destlen--) { + stb(dest, pad); + } + env->regs[r1 + 1] = destlen; + env->regs[r3 + 1] -= src - env->regs[r3]; /* can't use srclen here, + we trunc'ed it */ + env->regs[r1] = dest; + env->regs[r3] = src; + + return cc; +} + +/* compare logical long extended + memcompare insn with padding */ +uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) +{ + uint64_t destlen = env->regs[r1 + 1]; + uint64_t dest = env->regs[r1]; + uint64_t srclen = env->regs[r3 + 1]; + uint64_t src = env->regs[r3]; + uint8_t pad = a2 & 0xff; + uint8_t v1 = 0,v2 = 0; + uint32_t cc = 0; + if (!(destlen || srclen)) return cc; + if (srclen > destlen) srclen = destlen; + for(;destlen || srclen;src++,dest++,destlen--,srclen--) { + if (srclen) v1 = ldub(src); + else v1 = pad; + if (destlen) v2 = ldub(dest); + else v2 = pad; + if (v1 != v2) break; + } + + env->regs[r1 + 1] = destlen; + env->regs[r3 + 1] -= src - env->regs[r3]; /* can't use srclen here, + we trunc'ed it */ + env->regs[r1] = dest; + env->regs[r3] = src; + + if (v1 < v2) cc = 1; + else if (v1 > v2) cc = 2; + + return cc; +} + +/* subtract unsigned v2 from v1 with borrow */ +uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v1, uint32_t v2) +{ + uint32_t res = v1 + (~v2) + (cc >> 1); + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; + if (cc & 2) { /* borrow */ + if (v1) return 1; + else return 0; + } + else { + if (v1) return 3; + else return 2; + } +} + +/* subtract unsigned v2 from v1 with borrow */ +uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) +{ + uint64_t res = v1 + (~v2) + (cc >> 1); + env->regs[r1] = res; + if (cc & 2) { /* borrow */ + if (v1) return 1; + else return 0; + } + else { + if (v1) return 3; + else return 2; + } +} + +/* union used for splitting/joining 128-bit floats to/from 64-bit FP regs */ +typedef union { + struct { +#ifdef WORDS_BIGENDIAN + uint64_t h; + uint64_t l; +#else + uint64_t l; + uint64_t h; +#endif + }; + float128 x; +} FP128; + +/* condition codes for binary FP ops */ +static uint32_t set_cc_f32(float32 v1, float32 v2) +{ + if (float32_is_nan(v1) || float32_is_nan(v2)) return 3; + else if (float32_eq(v1, v2, &env->fpu_status)) return 0; + else if (float32_lt(v1, v2, &env->fpu_status)) return 1; + else return 2; +} + +static uint32_t set_cc_f64(float64 v1, float64 v2) +{ + if (float64_is_nan(v1) || float64_is_nan(v2)) return 3; + else if (float64_eq(v1, v2, &env->fpu_status)) return 0; + else if (float64_lt(v1, v2, &env->fpu_status)) return 1; + else return 2; +} + +/* condition codes for unary FP ops */ +static uint32_t set_cc_nz_f32(float32 v) +{ + if (float32_is_nan(v)) return 3; + else if (float32_is_zero(v)) return 0; + else if (float32_is_neg(v)) return 1; + else return 2; +} + +static uint32_t set_cc_nz_f64(float64 v) +{ + if (float64_is_nan(v)) return 3; + else if (float64_is_zero(v)) return 0; + else if (float64_is_neg(v)) return 1; + else return 2; +} + +static uint32_t set_cc_nz_f128(float128 v) +{ + if (float128_is_nan(v)) return 3; + else if (float128_is_zero(v)) return 0; + else if (float128_is_neg(v)) return 1; + else return 2; +} + +/* convert 32-bit int to 64-bit float */ +void HELPER(cdfbr)(uint32_t f1, int32_t v2) +{ + HELPER_LOG("%s: converting %d to f%d\n", __FUNCTION__, v2, f1); + env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); +} + +/* convert 32-bit int to 128-bit float */ +void HELPER(cxfbr)(uint32_t f1, int32_t v2) +{ + FP128 v1; + v1.x = int32_to_float128(v2, &env->fpu_status); + env->fregs[f1].i = v1.h; + env->fregs[f1 + 2].i = v1.l; +} + +/* convert 64-bit int to 32-bit float */ +void HELPER(cegbr)(uint32_t f1, int64_t v2) +{ + HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1); + env->fregs[f1].e = int64_to_float32(v2, &env->fpu_status); +} + +/* convert 64-bit int to 64-bit float */ +void HELPER(cdgbr)(uint32_t f1, int64_t v2) +{ + HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1); + env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); +} + +/* convert 64-bit int to 128-bit float */ +void HELPER(cxgbr)(uint32_t f1, int64_t v2) +{ + FP128 x1; + x1.x = int64_to_float128(v2, &env->fpu_status); + HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __FUNCTION__, v2, x1.h, x1.l); + env->fregs[f1].i = x1.h; + env->fregs[f1 + 2].i = x1.l; +} + +/* convert 32-bit int to 32-bit float */ +void HELPER(cefbr)(uint32_t f1, int32_t v2) +{ + env->fregs[f1].e = int32_to_float32(v2, &env->fpu_status); + HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __FUNCTION__, v2, env->fregs[f1].e, f1); +} + +/* 32-bit FP addition RR */ +uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].e = float32_add(env->fregs[f1].e, env->fregs[f2].e, &env->fpu_status); + HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, env->fregs[f2].e, env->fregs[f1].e, f1); + return set_cc_nz_f32(env->fregs[f1].e); +} + +/* 64-bit FP addition RR */ +uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); + HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1); + return set_cc_nz_f64(env->fregs[f1].d); +} + +/* 32-bit FP subtraction RR */ +uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].e = float32_sub(env->fregs[f1].e, env->fregs[f2].e, &env->fpu_status); + HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, env->fregs[f2].e, env->fregs[f1].e, f1); + return set_cc_nz_f32(env->fregs[f1].e); +} + +/* 64-bit FP subtraction RR */ +uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); + HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1); + return set_cc_nz_f64(env->fregs[f1].d); +} + +/* 32-bit FP division RR */ +void HELPER(debr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].e = float32_div(env->fregs[f1].e, env->fregs[f2].e, &env->fpu_status); +} + +/* 128-bit FP division RR */ +void HELPER(dxbr)(uint32_t f1, uint32_t f2) +{ + FP128 v1; + v1.h = env->fregs[f1].i; + v1.l = env->fregs[f1 + 2].i; + FP128 v2; + v2.h = env->fregs[f2].i; + v2.l = env->fregs[f2 + 2].i; + FP128 res; + res.x = float128_div(v1.x, v2.x, &env->fpu_status); + env->fregs[f1].i = res.h; + env->fregs[f1 + 2].i = res.l; +} + +/* 64-bit FP multiplication RR */ +void HELPER(mdbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); +} + +/* 128-bit FP multiplication RR */ +void HELPER(mxbr)(uint32_t f1, uint32_t f2) +{ + FP128 v1; + v1.h = env->fregs[f1].i; + v1.l = env->fregs[f1 + 2].i; + FP128 v2; + v2.h = env->fregs[f2].i; + v2.l = env->fregs[f2 + 2].i; + FP128 res; + res.x = float128_mul(v1.x, v2.x, &env->fpu_status); + //HELPER_LOG("%s: 0x%ld * 0x%ld = 0x%ld\n", __FUNCTION__, v1.x, v2.x, res.x); + env->fregs[f1].i = res.h; + env->fregs[f1 + 2].i = res.l; +} + +/* convert 32-bit float to 64-bit float */ +void HELPER(ldebr)(uint32_t r1, uint32_t r2) +{ + env->fregs[r1].d = float32_to_float64(env->fregs[r2].e, &env->fpu_status); +} + +/* convert 128-bit float to 64-bit float */ +void HELPER(ldxbr)(uint32_t f1, uint32_t f2) +{ + FP128 x2; + x2.h = env->fregs[f2].i; + x2.l = env->fregs[f2 + 2].i; + //HELPER_LOG("%s: converted %llf ", __FUNCTION__, x2.x); + env->fregs[f1].d = float128_to_float64(x2.x, &env->fpu_status); + HELPER_LOG("%s: to 0x%ld\n", __FUNCTION__, env->fregs[f1].d); +} + +/* convert 64-bit float to 128-bit float */ +void HELPER(lxdbr)(uint32_t f1, uint32_t f2) +{ + FP128 res; + res.x = float64_to_float128(env->fregs[f2].d, &env->fpu_status); + env->fregs[f1].i = res.h; + env->fregs[f1 + 2].i = res.l; +} + +/* convert 64-bit float to 32-bit float */ +void HELPER(ledbr)(uint32_t f1, uint32_t f2) +{ + float64 d2 = env->fregs[f2].d; + env->fregs[f1].e = float64_to_float32(d2, &env->fpu_status); +} + +/* convert 128-bit float to 32-bit float */ +void HELPER(lexbr)(uint32_t f1, uint32_t f2) +{ + FP128 x2; + x2.h = env->fregs[f2].i; + x2.l = env->fregs[f2 + 2].i; + //HELPER_LOG("%s: converted %llf ", __FUNCTION__, x2.x); + env->fregs[f1].e = float128_to_float32(x2.x, &env->fpu_status); + HELPER_LOG("%s: to 0x%d\n", __FUNCTION__, env->fregs[f1].e); +} + +/* absolute value of 32-bit float */ +uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) +{ + float32 v1; + float32 v2 = env->fregs[f2].d; + if (float32_is_neg(v2)) { + v1 = float32_abs(v2); + } + else { + v1 = v2; + } + env->fregs[f1].d = v1; + return set_cc_nz_f32(v1); +} + +/* absolute value of 64-bit float */ +uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) +{ + float64 v1; + float64 v2 = env->fregs[f2].d; + if (float64_is_neg(v2)) { + v1 = float64_abs(v2); + } + else { + v1 = v2; + } + env->fregs[f1].d = v1; + return set_cc_nz_f64(v1); +} + +/* absolute value of 128-bit float */ +uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) +{ + FP128 v1; + FP128 v2; + v2.h = env->fregs[f2].i; + v2.l = env->fregs[f2 + 2].i; + if (float128_is_neg(v2.x)) { + v1.x = float128_abs(v2.x); + } + else { + v1 = v2; + } + env->fregs[f1].i = v1.h; + env->fregs[f1 + 2].i = v1.l; + return set_cc_nz_f128(v1.x); +} + +/* load and test 64-bit float */ +uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = env->fregs[f2].d; + return set_cc_nz_f64(env->fregs[f1].d); +} + +/* load and test 32-bit float */ +uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].e = env->fregs[f2].e; + return set_cc_nz_f32(env->fregs[f1].e); +} + +/* load and test 128-bit float */ +uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) +{ + FP128 x; + x.h = env->fregs[f2].i; + x.l = env->fregs[f2 + 2].i; + env->fregs[f1].i = x.h; + env->fregs[f1 + 2].i = x.l; + return set_cc_nz_f128(x.x); +} + +/* negative absolute of 32-bit float */ +uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].e = float32_sub(float32_zero, env->fregs[f2].e, &env->fpu_status); + return set_cc_nz_f32(env->fregs[f1].e); +} + +/* negative absolute of 64-bit float */ +uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_sub(float64_zero, env->fregs[f2].d, &env->fpu_status); + return set_cc_nz_f64(env->fregs[f1].d); +} + +/* convert 64-bit float to 128-bit float */ +uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) +{ + FP128 x1, x2; + x2.h = env->fregs[f2].i; + x2.l = env->fregs[f2 + 2].i; + x1.x = float128_sub(float64_to_float128(float64_zero, &env->fpu_status), x2.x, &env->fpu_status); + env->fregs[f1].i = x1.h; + env->fregs[f1 + 2].i = x1.l; + return set_cc_nz_f128(x1.x); +} + +/* 32-bit FP compare RM */ +uint32_t HELPER(ceb)(uint32_t f1, uint64_t a2) +{ + float32 v1 = env->fregs[f1].e; + union { + float32 e; + uint32_t i; + } v2; + v2.i = ldl(a2); + HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2.e); + return set_cc_f32(v1, v2.e); +} + +/* 32-bit FP addition RM */ +uint32_t HELPER(aeb)(uint32_t f1, uint64_t a2) +{ + float32 v1 = env->fregs[f1].e; + union { + float32 e; + uint32_t i; + } v2; + v2.i = ldl(a2); + HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2.e); + env->fregs[f1].e = float32_add(v1, v2.e, &env->fpu_status); + return set_cc_nz_f32(env->fregs[f1].e); +} + +/* 32-bit FP division RM */ +void HELPER(deb)(uint32_t f1, uint64_t a2) +{ + float32 v1 = env->fregs[f1].e; + union { + float32 e; + uint32_t i; + } v2; + v2.i = ldl(a2); + HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __FUNCTION__, v1, f1, v2.e); + env->fregs[f1].e = float32_div(v1, v2.e, &env->fpu_status); +} + +/* 32-bit FP multiplication RM */ +void HELPER(meeb)(uint32_t f1, uint64_t a2) +{ + float32 v1 = env->fregs[f1].e; + union { + float32 e; + uint32_t i; + } v2; + v2.i = ldl(a2); + HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2.e); + env->fregs[f1].e = float32_mul(v1, v2.e, &env->fpu_status); +} + +/* 32-bit FP compare RR */ +uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) +{ + float32 v1 = env->fregs[f1].e; + float32 v2 = env->fregs[f2].e;; + HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__, v1, f1, v2); + return set_cc_f32(v1, v2); +} + +/* 64-bit FP compare RR */ +uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) +{ + float64 v1 = env->fregs[f1].d; + float64 v2 = env->fregs[f2].d;; + HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __FUNCTION__, v1, f1, v2); + return set_cc_f64(v1, v2); +} + +/* 128-bit FP compare RR */ +uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) +{ + FP128 v1; + v1.h = env->fregs[f1].i; + v1.l = env->fregs[f1 + 2].i; + FP128 v2; + v2.h = env->fregs[f2].i; + v2.l = env->fregs[f2 + 2].i; + //HELPER_LOG("%s: comparing %llf from f%d and %llf\n", __FUNCTION__, v1.x, f1, v2.x); + if (float128_is_nan(v1.x) || float128_is_nan(v2.x)) return 3; + else if (float128_eq(v1.x, v2.x, &env->fpu_status)) return 0; + else if (float128_lt(v1.x, v2.x, &env->fpu_status)) return 1; + else return 2; +} + +/* 64-bit FP compare RM */ +uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + union { + float64 d; + uint64_t i; + } v2; + v2.i = ldq(a2); + HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __FUNCTION__, v1, f1, v2.d); + return set_cc_f64(v1, v2.d); +} + +/* 64-bit FP addition RM */ +uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + union { + float64 d; + uint64_t i; + } v2; + v2.i = ldq(a2); + HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __FUNCTION__, v1, f1, v2.d); + env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); + return set_cc_nz_f64(v1); +} + +/* 32-bit FP subtraction RM */ +uint32_t HELPER(seb)(uint32_t f1, uint64_t a2) +{ + float32 v1 = env->fregs[f1].e; + union { + float32 e; + uint32_t i; + } v2; + v2.i = ldl(a2); + env->fregs[f1].e = v1 = float32_sub(v1, v2.e, &env->fpu_status); + return set_cc_nz_f32(v1); +} + +/* 64-bit FP subtraction RM */ +uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + union { + float64 d; + uint64_t i; + } v2; + v2.i = ldq(a2); + env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); + return set_cc_nz_f64(v1); +} + +/* 64-bit FP multiplication RM */ +void HELPER(mdb)(uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + union { + float64 d; + uint64_t i; + } v2; + v2.i = ldq(a2); + HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __FUNCTION__, v1, f1, v2.d); + env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); +} + +/* 64-bit FP division RM */ +void HELPER(ddb)(uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + union { + float64 d; + uint64_t i; + } v2; + v2.i = ldq(a2); + HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __FUNCTION__, v1, f1, v2.d); + env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); +} + +static void set_round_mode(int m3) +{ + switch (m3) { + case 0: break; /* current mode */ + case 1: /* biased round no nearest */ + case 4: /* round to nearest */ + set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); + break; + case 5: /* round to zero */ + set_float_rounding_mode(float_round_to_zero, &env->fpu_status); + break; + case 6: /* round to +inf */ + set_float_rounding_mode(float_round_up, &env->fpu_status); + break; + case 7: /* round to -inf */ + set_float_rounding_mode(float_round_down, &env->fpu_status); + break; + } +} + +/* convert 32-bit float to 64-bit int */ +uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) +{ + float32 v2 = env->fregs[f2].e; + set_round_mode(m3); + env->regs[r1] = float32_to_int64(v2, &env->fpu_status); + return set_cc_nz_f32(v2); +} + +/* convert 64-bit float to 64-bit int */ +uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) +{ + float64 v2 = env->fregs[f2].d; + set_round_mode(m3); + env->regs[r1] = float64_to_int64(v2, &env->fpu_status); + return set_cc_nz_f64(v2); +} + +/* convert 128-bit float to 64-bit int */ +uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) +{ + FP128 v2; + v2.h = env->fregs[f2].i; + v2.l = env->fregs[f2 + 2].i; + set_round_mode(m3); + env->regs[r1] = float128_to_int64(v2.x, &env->fpu_status); + if (float128_is_nan(v2.x)) return 3; + else if (float128_is_zero(v2.x)) return 0; + else if (float128_is_neg(v2.x)) return 1; + else return 2; +} + +/* convert 32-bit float to 32-bit int */ +uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) +{ + float32 v2 = env->fregs[f2].e; + set_round_mode(m3); + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | float32_to_int32(v2, &env->fpu_status); + return set_cc_nz_f32(v2); +} + +/* convert 64-bit float to 32-bit int */ +uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) +{ + float64 v2 = env->fregs[f2].d; + set_round_mode(m3); + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | float64_to_int32(v2, &env->fpu_status); + return set_cc_nz_f64(v2); +} + +/* convert 128-bit float to 32-bit int */ +uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) +{ + FP128 v2; + v2.h = env->fregs[f2].i; + v2.l = env->fregs[f2 + 2].i; + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | float128_to_int32(v2.x, &env->fpu_status); + return set_cc_nz_f128(v2.x); +} + +/* load 32-bit FP zero */ +void HELPER(lzer)(uint32_t f1) +{ + env->fregs[f1].e = float32_zero; +} + +/* load 64-bit FP zero */ +void HELPER(lzdr)(uint32_t f1) +{ + env->fregs[f1].d = float64_zero; +} + +/* load 128-bit FP zero */ +void HELPER(lzxr)(uint32_t f1) +{ + FP128 x; + x.x = float64_to_float128(float64_zero, &env->fpu_status); + env->fregs[f1].i = x.h; + env->fregs[f1 + 1].i = x.l; +} + +/* 128-bit FP subtraction RR */ +uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) +{ + FP128 v1; + v1.h = env->fregs[f1].i; + v1.l = env->fregs[f1 + 2].i; + FP128 v2; + v2.h = env->fregs[f2].i; + v2.l = env->fregs[f2 + 2].i; + FP128 res; + res.x = float128_sub(v1.x, v2.x, &env->fpu_status); + env->fregs[f1].i = res.h; + env->fregs[f1 + 2].i = res.l; + return set_cc_nz_f128(res.x); +} + +/* 128-bit FP addition RR */ +uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) +{ + FP128 v1; + v1.h = env->fregs[f1].i; + v1.l = env->fregs[f1 + 2].i; + FP128 v2; + v2.h = env->fregs[f2].i; + v2.l = env->fregs[f2 + 2].i; + FP128 res; + res.x = float128_add(v1.x, v2.x, &env->fpu_status); + env->fregs[f1].i = res.h; + env->fregs[f1 + 2].i = res.l; + return set_cc_nz_f128(res.x); +} + +/* 32-bit FP multiplication RR */ +void HELPER(meebr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].e = float32_mul(env->fregs[f1].e, env->fregs[f2].e, &env->fpu_status); +} + +/* 64-bit FP division RR */ +void HELPER(ddbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, &env->fpu_status); +} + +/* 64-bit FP multiply and add RM */ +void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) +{ + HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __FUNCTION__, f1, a2, f3); + union { + float64 d; + uint64_t i; + } v2; + v2.i = ldq(a2); + env->fregs[f1].d = float64_add(env->fregs[f1].d, float64_mul(v2.d, env->fregs[f3].d, &env->fpu_status), &env->fpu_status); +} + +/* 64-bit FP multiply and add RR */ +void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) +{ + HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3); + env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, env->fregs[f3].d, &env->fpu_status), env->fregs[f1].d, &env->fpu_status); +} + +/* 64-bit FP multiply and subtract RR */ +void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) +{ + HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3); + env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, env->fregs[f3].d, &env->fpu_status), env->fregs[f1].d, &env->fpu_status); +} + +/* 32-bit FP multiply and add RR */ +void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) +{ + env->fregs[f1].e = float32_add(env->fregs[f1].e, float32_mul(env->fregs[f2].e, env->fregs[f3].e, &env->fpu_status), &env->fpu_status); +} + +/* convert 64-bit float to 128-bit float */ +void HELPER(lxdb)(uint32_t f1, uint64_t a2) +{ + union { + float64 d; + uint64_t i; + } v2; + v2.i = ldq(a2); + FP128 v1; + v1.x = float64_to_float128(v2.d, &env->fpu_status); + env->fregs[f1].i = v1.h; + env->fregs[f1 + 2].i = v1.l; +} + +/* test data class 32-bit */ +uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) +{ + float32 v1 = env->fregs[f1].e; + int neg = float32_is_neg(v1); + uint32_t cc = 0; + HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg); + if (float32_is_zero(v1) && (m2 & (1 << (11-neg)))) cc = 1; + else if (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) cc = 1; + else if (float32_is_nan(v1) && (m2 & (1 << (3-neg)))) cc = 1; + else if (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg)))) cc = 1; + else /* assume normalized number */ if (m2 & (1 << (9-neg))) cc = 1; + /* FIXME: denormalized? */ + return cc; +} + +/* test data class 64-bit */ +uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) +{ + float64 v1 = env->fregs[f1].d; + int neg = float64_is_neg(v1); + uint32_t cc = 0; + HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg); + if (float64_is_zero(v1) && (m2 & (1 << (11-neg)))) cc = 1; + else if (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) cc = 1; + else if (float64_is_nan(v1) && (m2 & (1 << (3-neg)))) cc = 1; + else if (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg)))) cc = 1; + else /* assume normalized number */ if (m2 & (1 << (9-neg))) cc = 1; + /* FIXME: denormalized? */ + return cc; +} + +/* test data class 128-bit */ +uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) +{ + FP128 v1; + uint32_t cc = 0; + v1.h = env->fregs[f1].i; + v1.l = env->fregs[f1 + 2].i; + + int neg = float128_is_neg(v1.x); + if (float128_is_zero(v1.x) && (m2 & (1 << (11-neg)))) cc = 1; + else if (float128_is_infinity(v1.x) && (m2 & (1 << (5-neg)))) cc = 1; + else if (float128_is_nan(v1.x) && (m2 & (1 << (3-neg)))) cc = 1; + else if (float128_is_signaling_nan(v1.x) && (m2 & (1 << (1-neg)))) cc = 1; + else /* assume normalized number */ if (m2 & (1 << (9-neg))) cc = 1; + /* FIXME: denormalized? */ + return cc; +} + +/* find leftmost one */ +uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) +{ + uint64_t res = 0; + uint64_t ov2 = v2; + while (!(v2 & 0x8000000000000000ULL) && v2) { + v2 <<= 1; + res++; + } + if (!v2) { + env->regs[r1] = 64; + env->regs[r1 + 1] = 0; + return 0; + } + else { + env->regs[r1] = res; + env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); + return 2; + } +} + +/* square root 64-bit RR */ +void HELPER(sqdbr)(uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); +} diff --git a/target-s390x/translate.c b/target-s390x/translate.c new file mode 100644 index 0000000..a1948bf --- /dev/null +++ b/target-s390x/translate.c @@ -0,0 +1,2479 @@ +/* + * S/390 translation + * + * Copyright (c) 2009 Ulrich Hecht + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#define S390X_DEBUG_DISAS +#ifdef S390X_DEBUG_DISAS +# define LOG_DISAS(...) qemu_log(__VA_ARGS__) +#else +# define LOG_DISAS(...) do { } while (0) +#endif + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" +#include "tcg-op.h" +#include "qemu-log.h" + +/* global register indexes */ +static TCGv_ptr cpu_env; + +#include "gen-icount.h" +#include "helpers.h" +#define GEN_HELPER 1 +#include "helpers.h" + +typedef struct DisasContext DisasContext; +struct DisasContext { + uint64_t pc; + int is_jmp; + CPUS390XState *env; +}; + +#define DISAS_EXCP 4 +#define DISAS_SVC 5 + +void cpu_dump_state(CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + int i; + for (i = 0; i < 16; i++) { + cpu_fprintf(f, "R%02d=%016lx", i, env->regs[i]); + if ((i % 4) == 3) cpu_fprintf(f, "\n"); + else cpu_fprintf(f, " "); + } + for (i = 0; i < 16; i++) { + cpu_fprintf(f, "F%02d=%016lx", i, env->fregs[i]); + if ((i % 4) == 3) cpu_fprintf(f, "\n"); + else cpu_fprintf(f, " "); + } + cpu_fprintf(f, "PSW=mask %016lx addr %016lx cc %02x\n", env->psw.mask, env->psw.addr, env->cc); +} + +#define TCGREGS + +static TCGv global_cc; +#ifdef TCGREGS +/* registers stored in TCG variables enhance performance */ +static TCGv tcgregs[16]; +static TCGv tcgregs32[16]; +#endif +static TCGv cc; +static TCGv psw_addr; + +void s390x_translate_init(void) +{ + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + global_cc = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, cc), "global_cc"); +#ifdef TCGREGS + int i; + char rn[4]; + for (i = 0; i < 16; i++) { + sprintf(rn, "R%d", i); + tcgregs[i] = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, regs[i]), strdup(rn)); + sprintf(rn, "r%d", i); + tcgregs32[i] = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, regs[i]) +#ifdef WORDS_BIGENDIAN + + 4 +#endif + , strdup(rn)); + } +#endif + psw_addr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, psw.addr), "psw_addr"); +} + +#ifdef TCGREGS +static inline void sync_reg64(int reg) +{ + tcg_gen_sync_i64(tcgregs[reg]); +} +static inline void sync_reg32(int reg) +{ + tcg_gen_sync_i32(tcgregs32[reg]); +} +#endif + +static TCGv load_reg(int reg) +{ + TCGv r = tcg_temp_new_i64(); +#ifdef TCGREGS + sync_reg32(reg); + tcg_gen_mov_i64(r, tcgregs[reg]); + return r; +#else + tcg_gen_ld_i64(r, cpu_env, offsetof(CPUState, regs[reg])); + return r; +#endif +} + +static TCGv load_freg(int reg) +{ + TCGv r = tcg_temp_new_i64(); + tcg_gen_ld_i64(r, cpu_env, offsetof(CPUState, fregs[reg].d)); + return r; +} + +static TCGv load_freg32(int reg) +{ + TCGv r = tcg_temp_new_i32(); + tcg_gen_ld_i32(r, cpu_env, offsetof(CPUState, fregs[reg].e)); + return r; +} + +static void load_reg32_var(TCGv r, int reg) +{ +#ifdef TCGREGS + sync_reg64(reg); + tcg_gen_mov_i32(r, tcgregs32[reg]); +#else +#ifdef WORDS_BIGENDIAN + tcg_gen_ld_i32(r, cpu_env, offsetof(CPUState, regs[reg]) + 4); +#else + tcg_gen_ld_i32(r, cpu_env, offsetof(CPUState, regs[reg])); +#endif +#endif +} + +static TCGv load_reg32(int reg) +{ + TCGv r = tcg_temp_new_i32(); + load_reg32_var(r, reg); + return r; +} + +static void store_reg(int reg, TCGv v) +{ +#ifdef TCGREGS + sync_reg32(reg); + tcg_gen_mov_i64(tcgregs[reg], v); +#else + tcg_gen_st_i64(v, cpu_env, offsetof(CPUState, regs[reg])); +#endif +} + +static void store_freg(int reg, TCGv v) +{ + tcg_gen_st_i64(v, cpu_env, offsetof(CPUState, fregs[reg].d)); +} + +static void store_reg32(int reg, TCGv v) +{ +#ifdef TCGREGS + sync_reg64(reg); + tcg_gen_mov_i32(tcgregs32[reg], v); +#else +#ifdef WORDS_BIGENDIAN + tcg_gen_st_i32(v, cpu_env, offsetof(CPUState, regs[reg]) + 4); +#else + tcg_gen_st_i32(v, cpu_env, offsetof(CPUState, regs[reg])); +#endif +#endif +} + +static void store_reg8(int reg, TCGv v) +{ +#ifdef TCGREGS + TCGv tmp = tcg_temp_new_i32(); + sync_reg64(reg); + tcg_gen_andi_i32(tmp, tcgregs32[reg], 0xffffff00UL); + tcg_gen_or_i32(tcgregs32[reg], tmp, v); + tcg_temp_free(tmp); +#else +#ifdef WORDS_BIGENDIAN + tcg_gen_st8_i32(v, cpu_env, offsetof(CPUState, regs[reg]) + 7); +#else + tcg_gen_st8_i32(v, cpu_env, offsetof(CPUState, regs[reg])); +#endif +#endif +} + +static void store_freg32(int reg, TCGv v) +{ + tcg_gen_st_i32(v, cpu_env, offsetof(CPUState, fregs[reg].e)); +} + +static void gen_illegal_opcode(DisasContext *s) +{ + TCGv tmp = tcg_temp_new_i64(); + tcg_gen_movi_i64(tmp, 42); + gen_helper_exception(tmp); + s->is_jmp = DISAS_EXCP; +} + +#define DEBUGINSN LOG_DISAS("insn: 0x%lx\n", insn); + +static TCGv get_address(int x2, int b2, int d2) +{ + TCGv tmp = 0,tmp2 = 0; + if (d2) tmp = tcg_const_i64(d2); + if (x2) { + if (d2) { + tmp2 = load_reg(x2); + tcg_gen_add_i64(tmp, tmp, tmp2); + tcg_temp_free(tmp2); + } + else { + tmp = load_reg(x2); + } + } + if (b2) { + if (d2 || x2) { + tmp2 = load_reg(b2); + tcg_gen_add_i64(tmp, tmp, tmp2); + tcg_temp_free(tmp2); + } + else { + tmp = load_reg(b2); + } + } + + if (!(d2 || x2 || b2)) tmp = tcg_const_i64(0); + + return tmp; +} + +static inline void set_cc_nz_u32(TCGv val) +{ + gen_helper_set_cc_nz_u32(cc, val); +} + +static inline void set_cc_nz_u64(TCGv val) +{ + gen_helper_set_cc_nz_u64(cc, val); +} + +static inline void set_cc_s32(TCGv val) +{ + gen_helper_set_cc_s32(cc, val); +} + +static inline void set_cc_s64(TCGv val) +{ + gen_helper_set_cc_s64(cc, val); +} + +static inline void cmp_s32(TCGv v1, TCGv v2) +{ + gen_helper_cmp_s32(cc, v1, v2); +} + +static inline void cmp_u32(TCGv v1, TCGv v2) +{ + gen_helper_cmp_u32(cc, v1, v2); +} + +/* this is a hysterical raisin */ +static inline void cmp_s32c(TCGv v1, int32_t v2) +{ + gen_helper_cmp_s32(cc, v1, tcg_const_i32(v2)); +} +static inline void cmp_u32c(TCGv v1, uint32_t v2) +{ + gen_helper_cmp_u32(cc, v1, tcg_const_i32(v2)); +} + + +static inline void cmp_s64(TCGv v1, TCGv v2) +{ + gen_helper_cmp_s64(cc, v1, v2); +} + +static inline void cmp_u64(TCGv v1, TCGv v2) +{ + gen_helper_cmp_u64(cc, v1, v2); +} + +/* see cmp_[su]32c() */ +static inline void cmp_s64c(TCGv v1, int64_t v2) +{ + gen_helper_cmp_s64(cc, v1, tcg_const_i64(v2)); +} +static inline void cmp_u64c(TCGv v1, uint64_t v2) +{ + gen_helper_cmp_u64(cc, v1, tcg_const_i64(v2)); +} + +static void gen_bcr(uint32_t mask, int tr, uint64_t offset) +{ + TCGv target; + if (mask == 0xf) { /* unconditional */ + target = load_reg(tr); + tcg_gen_mov_i64(psw_addr, target); + } + else { + gen_helper_bcr(cc, tcg_const_i32(mask), (target = load_reg(tr)), tcg_const_i64(offset)); + } + tcg_temp_free(target); +} + +static void gen_brc(uint32_t mask, uint64_t pc, int32_t offset) +{ + if (mask == 0xf) { /* unconditional */ + tcg_gen_movi_i64(psw_addr, pc + offset); + } + else { + gen_helper_brc(cc, tcg_const_i32(mask), tcg_const_i64(pc), tcg_const_i32(offset)); + } +} + +static void gen_set_cc_add64(TCGv v1, TCGv v2, TCGv vr) +{ + gen_helper_set_cc_add64(cc, v1, v2, vr); +} + +static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) +{ + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; + + LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", op, r1, x2, b2, d2); + tmp = get_address(x2, b2, d2); + switch (op) { + case 0x2: /* LTG R1,D2(X2,B2) [RXY] */ + case 0x4: /* lg r1,d2(x2,b2) */ + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp2, tmp, 1); + store_reg(r1, tmp2); + if (op == 0x2) set_cc_s64(tmp2); + break; + case 0x12: /* LT R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32s(tmp2, tmp, 1); + store_reg32(r1, tmp2); + set_cc_s32(tmp2); + break; + case 0xc: /* MSG R1,D2(X2,B2) [RXY] */ + case 0x1c: /* MSGF R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + if (op == 0xc) { + tcg_gen_qemu_ld64(tmp2, tmp, 1); + } + else { + tcg_gen_qemu_ld32s(tmp2, tmp, 1); + tcg_gen_ext32s_i64(tmp2, tmp2); + } + tmp = load_reg(r1); + tcg_gen_mul_i64(tmp, tmp, tmp2); + store_reg(r1, tmp); + break; + case 0xd: /* DSG R1,D2(X2,B2) [RXY] */ + case 0x1d: /* DSGF R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + if (op == 0x1d) { + tcg_gen_qemu_ld32s(tmp2, tmp, 1); + tcg_gen_ext32s_i64(tmp2, tmp2); + } + else { + tcg_gen_qemu_ld64(tmp2, tmp, 1); + } + tmp = load_reg(r1 + 1); + tmp3 = tcg_temp_new_i64(); + tcg_gen_div_i64(tmp3, tmp, tmp2); + store_reg(r1 + 1, tmp3); + tcg_gen_rem_i64(tmp3, tmp, tmp2); + store_reg(r1, tmp3); + break; + case 0x8: /* AG R1,D2(X2,B2) [RXY] */ + case 0xa: /* ALG R1,D2(X2,B2) [RXY] */ + case 0x18: /* AGF R1,D2(X2,B2) [RXY] */ + case 0x1a: /* ALGF R1,D2(X2,B2) [RXY] */ + if (op == 0x1a) { + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + tcg_gen_ext32u_i64(tmp2, tmp2); + } + else if (op == 0x18) { + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32s(tmp2, tmp, 1); + tcg_gen_ext32s_i64(tmp2, tmp2); + } + else { + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp2, tmp, 1); + } + tmp = load_reg(r1); + tmp3 = tcg_temp_new_i64(); + tcg_gen_add_i64(tmp3, tmp, tmp2); + store_reg(r1, tmp3); + switch (op) { + case 0x8: case 0x18: gen_set_cc_add64(tmp, tmp2, tmp3); break; + case 0xa: case 0x1a: gen_helper_set_cc_addu64(cc, tmp, tmp2, tmp3); break; + default: tcg_abort(); + } + break; + case 0x9: /* SG R1,D2(X2,B2) [RXY] */ + case 0xb: /* SLG R1,D2(X2,B2) [RXY] */ + case 0x19: /* SGF R1,D2(X2,B2) [RXY] */ + case 0x1b: /* SLGF R1,D2(X2,B2) [RXY] */ + if (op == 0x19) { + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32s(tmp2, tmp, 1); + tcg_gen_ext32s_i64(tmp2, tmp2); + } + else if (op == 0x1b) { + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + tcg_gen_ext32u_i64(tmp2, tmp2); + } + else { + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp2, tmp, 1); + } + tmp = load_reg(r1); + tmp3 = tcg_temp_new_i64(); + tcg_gen_sub_i64(tmp3, tmp, tmp2); + store_reg(r1, tmp3); + switch (op) { + case 0x9: case 0x19: gen_helper_set_cc_sub64(cc, tmp, tmp2, tmp3); break; + case 0xb: case 0x1b: gen_helper_set_cc_subu64(cc, tmp, tmp2, tmp3); break; + default: tcg_abort(); + } + break; + case 0x14: /* LGF R1,D2(X2,B2) [RXY] */ + case 0x16: /* LLGF R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + switch (op) { + case 0x14: tcg_gen_ext32s_i64(tmp2, tmp2); break; + case 0x16: tcg_gen_ext32u_i64(tmp2, tmp2); break; + default: tcg_abort(); + } + store_reg(r1, tmp2); + break; + case 0x15: /* LGH R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld16s(tmp2, tmp, 1); + tcg_gen_ext16s_i64(tmp2, tmp2); + store_reg(r1, tmp2); + break; + case 0x17: /* LLGT R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + tcg_gen_ext32u_i64(tmp2, tmp2); + tcg_gen_andi_i64(tmp2, tmp2, 0x7fffffffULL); + store_reg(r1, tmp2); + break; + case 0x1e: /* LRV R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + tcg_gen_bswap32_i32(tmp2, tmp2); + store_reg(r1, tmp2); + break; + case 0x20: /* CG R1,D2(X2,B2) [RXY] */ + case 0x21: /* CLG R1,D2(X2,B2) */ + case 0x30: /* CGF R1,D2(X2,B2) [RXY] */ + case 0x31: /* CLGF R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + switch (op) { + case 0x20: + case 0x21: + tcg_gen_qemu_ld64(tmp2, tmp, 1); + break; + case 0x30: + tcg_gen_qemu_ld32s(tmp2, tmp, 1); + tcg_gen_ext32s_i64(tmp2, tmp2); + break; + case 0x31: + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + tcg_gen_ext32u_i64(tmp2, tmp2); + break; + default: + tcg_abort(); + } + tmp = load_reg(r1); + switch (op) { + case 0x20: case 0x30: cmp_s64(tmp, tmp2); break; + case 0x21: case 0x31: cmp_u64(tmp, tmp2); break; + default: tcg_abort(); + } + break; + case 0x24: /* stg r1, d2(x2,b2) */ + tmp2 = load_reg(r1); + tcg_gen_qemu_st64(tmp2, tmp, 1); + break; + case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */ + tmp2 = load_reg32(r1); + tcg_gen_bswap32_i32(tmp2, tmp2); + tcg_gen_qemu_st32(tmp2, tmp, 1); + break; + case 0x50: /* STY R1,D2(X2,B2) [RXY] */ + tmp2 = load_reg32(r1); + tcg_gen_qemu_st32(tmp2, tmp, 1); + break; + case 0x57: /* XY R1,D2(X2,B2) [RXY] */ + tmp2 = load_reg32(r1); + tmp3 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp3, tmp, 1); + tcg_gen_xor_i32(tmp, tmp2, tmp3); + store_reg32(r1, tmp); + set_cc_nz_u32(tmp); + break; + case 0x58: /* LY R1,D2(X2,B2) [RXY] */ + tmp3 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp3, tmp, 1); + store_reg32(r1, tmp3); + break; + case 0x5a: /* AY R1,D2(X2,B2) [RXY] */ + case 0x5b: /* SY R1,D2(X2,B2) [RXY] */ + tmp2 = load_reg32(r1); + tmp3 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32s(tmp3, tmp, 1); + switch (op) { + case 0x5a: tcg_gen_add_i32(tmp, tmp2, tmp3); break; + case 0x5b: tcg_gen_sub_i32(tmp, tmp2, tmp3); break; + default: tcg_abort(); + } + store_reg32(r1, tmp); + switch (op) { + case 0x5a: gen_helper_set_cc_add32(cc, tmp2, tmp3, tmp); break; + case 0x5b: gen_helper_set_cc_sub32(cc, tmp2, tmp3, tmp); break; + default: tcg_abort(); + } + break; + case 0x71: /* LAY R1,D2(X2,B2) [RXY] */ + store_reg(r1, tmp); + break; + case 0x72: /* STCY R1,D2(X2,B2) [RXY] */ + tmp2 = load_reg32(r1); + tcg_gen_qemu_st8(tmp2, tmp, 1); + break; + case 0x73: /* ICY R1,D2(X2,B2) [RXY] */ + tmp3 = tcg_temp_new_i32(); + tcg_gen_qemu_ld8u(tmp3, tmp, 1); + store_reg8(r1, tmp3); + break; + case 0x76: /* LB R1,D2(X2,B2) [RXY] */ + case 0x77: /* LGB R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld8s(tmp2, tmp, 1); + switch (op) { + case 0x76: + tcg_gen_ext8s_i32(tmp2, tmp2); + store_reg32(r1, tmp2); + break; + case 0x77: + tcg_gen_ext8s_i64(tmp2, tmp2); + store_reg(r1, tmp2); + break; + default: tcg_abort(); + } + break; + case 0x78: /* LHY R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld16s(tmp2, tmp, 1); + tcg_gen_ext16s_i32(tmp2, tmp2); + store_reg32(r1, tmp2); + break; + case 0x80: /* NG R1,D2(X2,B2) [RXY] */ + case 0x81: /* OG R1,D2(X2,B2) [RXY] */ + case 0x82: /* XG R1,D2(X2,B2) [RXY] */ + tmp2 = load_reg(r1); + tmp3 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp3, tmp, 1); + switch (op) { + case 0x80: tcg_gen_and_i64(tmp, tmp2, tmp3); break; + case 0x81: tcg_gen_or_i64(tmp, tmp2, tmp3); break; + case 0x82: tcg_gen_xor_i64(tmp, tmp2, tmp3); break; + default: tcg_abort(); + } + store_reg(r1, tmp); + set_cc_nz_u64(tmp); + break; + case 0x86: /* MLG R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp2, tmp, 1); + tmp = tcg_const_i32(r1); + gen_helper_mlg(tmp, tmp2); + break; + case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp2, tmp, 1); + tmp = tcg_const_i32(r1); + gen_helper_dlg(tmp, tmp2); + break; + case 0x88: /* ALCG R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp2, tmp, 1); + tmp = load_reg(r1); + tmp3 = tcg_temp_new_i64(); + tcg_gen_shri_i64(tmp3, cc, 1); + tcg_gen_andi_i64(tmp3, tmp3, 1); + tcg_gen_add_i64(tmp3, tmp2, tmp3);; + tcg_gen_add_i64(tmp3, tmp, tmp3); + store_reg(r1, tmp3); + gen_helper_set_cc_addc_u64(cc, tmp, tmp2, tmp3); + break; + case 0x89: /* SLBG R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp2, tmp, 1); + tmp = load_reg(r1); + tmp3 = tcg_const_i32(r1); + gen_helper_slbg(cc, cc, tmp3, tmp, tmp2); + break; + case 0x90: /* LLGC R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld8u(tmp2, tmp, 1); + store_reg(r1, tmp2); + break; + case 0x91: /* LLGH R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld16u(tmp2, tmp, 1); + store_reg(r1, tmp2); + break; + case 0x94: /* LLC R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld8u(tmp2, tmp, 1); + store_reg32(r1, tmp2); + break; + case 0x95: /* LLH R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld16u(tmp2, tmp, 1); + store_reg32(r1, tmp2); + break; + case 0x98: /* ALC R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + tmp = tcg_const_i32(r1); + gen_helper_addc_u32(cc, cc, tmp, tmp2); + break; + case 0x99: /* SLB R1,D2(X2,B2) [RXY] */ + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + tmp = load_reg32(r1); + tmp3 = tcg_const_i32(r1); + gen_helper_slb(cc, cc, tmp3, tmp, tmp2); + break; + default: + LOG_DISAS("illegal e3 operation 0x%x\n", op); + gen_illegal_opcode(s); + break; + } + tcg_temp_free(tmp); + if (tmp2) tcg_temp_free(tmp2); + if (tmp3) tcg_temp_free(tmp3); +} + +static void disas_eb(DisasContext *s, int op, int r1, int r3, int b2, int d2) +{ + TCGv tmp = 0,tmp2 = 0,tmp3 = 0,tmp4 = 0; + int i; + + LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); + switch (op) { + case 0xc: /* SRLG R1,R3,D2(B2) [RSY] */ + case 0xd: /* SLLG R1,R3,D2(B2) [RSY] */ + case 0xa: /* SRAG R1,R3,D2(B2) [RSY] */ + case 0x1c: /* RLLG R1,R3,D2(B2) [RSY] */ + if (b2) { + tmp = get_address(0, b2, d2); + tcg_gen_andi_i64(tmp, tmp, 0x3f); + } + else tmp = tcg_const_i32(d2 & 0x3f); + tmp2 = load_reg(r3); + tmp3 = tcg_temp_new_i64(); + switch (op) { + case 0xc: tcg_gen_shr_i64(tmp3, tmp2, tmp); break; + case 0xd: tcg_gen_shl_i64(tmp3, tmp2, tmp); break; + case 0xa: tcg_gen_sar_i64(tmp3, tmp2, tmp); break; + case 0x1c: tcg_gen_rotl_i64(tmp3, tmp2, tmp); break; + default: tcg_abort(); break; + } + store_reg(r1, tmp3); + if (op == 0xa) set_cc_s64(tmp3); + break; + case 0x1d: /* RLL R1,R3,D2(B2) [RSY] */ + if (b2) { + tmp = get_address(0, b2, d2); + tcg_gen_andi_i64(tmp, tmp, 0x3f); + } + else tmp = tcg_const_i32(d2 & 0x3f); + tmp2 = load_reg32(r3); + tmp3 = tcg_temp_new_i32(); + switch (op) { + case 0x1d: tcg_gen_rotl_i32(tmp3, tmp2, tmp); break; + default: tcg_abort(); break; + } + store_reg32(r1, tmp3); + break; + case 0x4: /* LMG R1,R3,D2(B2) [RSY] */ + case 0x24: /* stmg */ + /* Apparently, unrolling lmg/stmg of any size gains performance - + even for very long ones... */ + if (r3 > r1) { + tmp = get_address(0, b2, d2); + for (i = r1; i <= r3; i++) { + if (op == 0x4) { + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp2, tmp, 1); + store_reg(i, tmp2); + /* At least one register is usually read after an lmg + (br %rsomething), which is why freeing them is + detrimental to performance */ + } + else { + tmp2 = load_reg(i); + tcg_gen_qemu_st64(tmp2, tmp, 1); + /* R15 is usually read after an stmg; other registers + generally aren't and can be free'd */ + if (i != 15) tcg_temp_free(tmp2); + } + tcg_gen_addi_i64(tmp, tmp, 8); + } + tmp2 = 0; + } + else { + tmp = tcg_const_i32(r1); + tmp2 = tcg_const_i32(r3); + tmp3 = tcg_const_i32(b2); + tmp4 = tcg_const_i32(d2); + if (op == 0x4) gen_helper_lmg(tmp, tmp2, tmp3, tmp4); + else gen_helper_stmg(tmp, tmp2, tmp3, tmp4); + } + break; + case 0x2c: /* STCMH R1,M3,D2(B2) [RSY] */ + tmp2 = get_address(0, b2, d2); + tmp = tcg_const_i32(r1); + tmp3 = tcg_const_i32(r3); + gen_helper_stcmh(cc, tmp, tmp2, tmp3); + break; + case 0x30: /* CSG R1,R3,D2(B2) [RSY] */ + tmp2 = get_address(0, b2, d2); + tmp = tcg_const_i32(r1); + tmp3 = tcg_const_i32(r3); + gen_helper_csg(cc, tmp, tmp2, tmp3); + break; + case 0x3e: /* CDSG R1,R3,D2(B2) [RSY] */ + tmp2 = get_address(0, b2, d2); + tmp = tcg_const_i32(r1); + tmp3 = tcg_const_i32(r3); + gen_helper_cdsg(cc, tmp, tmp2, tmp3); + break; + case 0x51: /* TMY D1(B1),I2 [SIY] */ + tmp = get_address(0, b2, d2); /* SIY -> this is the destination */ + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld8u(tmp2, tmp, 1); + tmp = tcg_const_i32((r1 << 4) | r3); + gen_helper_tm(cc, tmp2, tmp); + break; + case 0x52: /* MVIY D1(B1),I2 [SIY] */ + tmp2 = tcg_const_i32((r1 << 4) | r3); + tmp = get_address(0, b2, d2); /* SIY -> this is the destination */ + tcg_gen_qemu_st8(tmp2, tmp, 1); + break; + case 0x55: /* CLIY D1(B1),I2 [SIY] */ + tmp3 = get_address(0, b2, d2); /* SIY -> this is the 1st operand */ + tmp = tcg_temp_new_i32(); + tcg_gen_qemu_ld8u(tmp, tmp3, 1); + cmp_u32c(tmp, (r1 << 4) | r3); + break; + case 0x80: /* ICMH R1,M3,D2(B2) [RSY] */ + tmp2 = get_address(0, b2, d2); + tmp = tcg_const_i32(r1); + tmp3 = tcg_const_i32(r3); + gen_helper_icmh(cc, tmp, tmp2, tmp3); + break; + default: + LOG_DISAS("illegal eb operation 0x%x\n", op); + gen_illegal_opcode(s); + break; + } + if (tmp) tcg_temp_free(tmp); + if (tmp2) tcg_temp_free(tmp2); + if (tmp3) tcg_temp_free(tmp3); + if (tmp4) tcg_temp_free(tmp4); +} + +static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, int r1b) +{ + TCGv tmp, tmp2, tmp3 = 0; + tmp2 = get_address(x2, b2, d2); + tmp = tcg_const_i32(r1); + switch (op) { + case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */ + gen_helper_lxdb(tmp, tmp2); + break; + case 0x9: /* CEB R1,D2(X2,B2) [RXE] */ + gen_helper_ceb(cc, tmp, tmp2); + break; + case 0xa: /* AEB R1,D2(X2,B2) [RXE] */ + gen_helper_aeb(cc, tmp, tmp2); + break; + case 0xb: /* SEB R1,D2(X2,B2) [RXE] */ + gen_helper_seb(cc, tmp, tmp2); + break; + case 0xd: /* DEB R1,D2(X2,B2) [RXE] */ + gen_helper_deb(tmp, tmp2); + break; + case 0x10: /* TCEB R1,D2(X2,B2) [RXE] */ + gen_helper_tceb(cc, tmp, tmp2); + break; + case 0x11: /* TCDB R1,D2(X2,B2) [RXE] */ + gen_helper_tcdb(cc, tmp, tmp2); + break; + case 0x12: /* TCXB R1,D2(X2,B2) [RXE] */ + gen_helper_tcxb(cc, tmp, tmp2); + break; + case 0x17: /* MEEB R1,D2(X2,B2) [RXE] */ + gen_helper_meeb(tmp, tmp2); + break; + case 0x19: /* CDB R1,D2(X2,B2) [RXE] */ + gen_helper_cdb(cc, tmp, tmp2); + break; + case 0x1a: /* ADB R1,D2(X2,B2) [RXE] */ + gen_helper_adb(cc, tmp, tmp2); + break; + case 0x1b: /* SDB R1,D2(X2,B2) [RXE] */ + gen_helper_sdb(cc, tmp, tmp2); + break; + case 0x1c: /* MDB R1,D2(X2,B2) [RXE] */ + gen_helper_mdb(tmp, tmp2); + break; + case 0x1d: /* DDB R1,D2(X2,B2) [RXE] */ + gen_helper_ddb(tmp, tmp2); + break; + case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ + /* for RXF insns, r1 is R3 and r1b is R1 */ + tmp3 = tcg_const_i32(r1b); + gen_helper_madb(tmp3, tmp2, tmp); + break; + default: + LOG_DISAS("illegal ed operation 0x%x\n", op); + gen_illegal_opcode(s); + break; + } + tcg_temp_free(tmp); + tcg_temp_free(tmp2); +} + +static void disas_a5(DisasContext *s, int op, int r1, int i2) +{ + TCGv tmp = 0,tmp2 = 0; + uint64_t vtmp; + LOG_DISAS("disas_a5: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); + switch (op) { + case 0x0: /* IIHH R1,I2 [RI] */ + case 0x1: /* IIHL R1,I2 [RI] */ + tmp = load_reg(r1); + vtmp = i2; + switch (op) { + case 0x0: tcg_gen_andi_i64(tmp, tmp, 0x0000ffffffffffffULL); vtmp <<= 48; break; + case 0x1: tcg_gen_andi_i64(tmp, tmp, 0xffff0000ffffffffULL); vtmp <<= 32; break; + default: tcg_abort(); + } + tcg_gen_ori_i64(tmp, tmp, vtmp); + store_reg(r1, tmp); + break; + case 0x4: /* NIHH R1,I2 [RI] */ + case 0x8: /* OIHH R1,I2 [RI] */ + tmp = load_reg(r1); + switch (op) { + case 0x4: + tmp2 = tcg_const_i64( (((uint64_t)i2) << 48) | 0x0000ffffffffffffULL); + tcg_gen_and_i64(tmp, tmp, tmp2); + break; + case 0x8: + tmp2 = tcg_const_i64(((uint64_t)i2) << 48); + tcg_gen_or_i64(tmp, tmp, tmp2); + break; + default: tcg_abort(); + } + store_reg(r1, tmp); + tcg_gen_shri_i64(tmp2, tmp, 48); + tcg_gen_trunc_i64_i32(tmp2, tmp2); + set_cc_nz_u32(tmp2); + break; + case 0x5: /* NIHL R1,I2 [RI] */ + case 0x9: /* OIHL R1,I2 [RI] */ + tmp = load_reg(r1); + switch (op) { + case 0x5: + tmp2 = tcg_const_i64( (((uint64_t)i2) << 32) | 0xffff0000ffffffffULL); + tcg_gen_and_i64(tmp, tmp, tmp2); + break; + case 0x9: + tmp2 = tcg_const_i64(((uint64_t)i2) << 32); + tcg_gen_or_i64(tmp, tmp, tmp2); + break; + default: tcg_abort(); + } + store_reg(r1, tmp); + tcg_gen_shri_i64(tmp2, tmp, 32); + tcg_gen_trunc_i64_i32(tmp2, tmp2); + tcg_gen_andi_i32(tmp2, tmp2, 0xffff); + set_cc_nz_u32(tmp2); + break; + case 0x6: /* NILH R1,I2 [RI] */ + case 0xa: /* OILH R1,I2 [RI] */ + tmp = load_reg(r1); + switch (op) { + case 0x6: + tmp2 = tcg_const_i64( (((uint64_t)i2) << 16) | 0xffffffff0000ffffULL); + tcg_gen_and_i64(tmp, tmp, tmp2); + break; + case 0xa: + tmp2 = tcg_const_i64(((uint64_t)i2) << 16); + tcg_gen_or_i64(tmp, tmp, tmp2); + break; + default: tcg_abort(); + } + store_reg(r1, tmp); + tcg_gen_shri_i64(tmp2, tmp, 16); + tcg_gen_trunc_i64_i32(tmp2, tmp2); + tcg_gen_andi_i32(tmp2, tmp2, 0xffff); + set_cc_nz_u32(tmp2); + break; + case 0x7: /* NILL R1,I2 [RI] */ + case 0xb: /* OILL R1,I2 [RI] */ + tmp = load_reg(r1); + switch (op) { + case 0x7: + tmp2 = tcg_const_i64(i2 | 0xffffffffffff0000ULL); + tcg_gen_and_i64(tmp, tmp, tmp2); + break; + case 0xb: + tmp2 = tcg_const_i64(i2); + tcg_gen_or_i64(tmp, tmp, tmp2); + break; + default: tcg_abort(); break; + } + store_reg(r1, tmp); + tcg_gen_trunc_i64_i32(tmp, tmp); + tcg_gen_andi_i32(tmp, tmp, 0xffff); + set_cc_nz_u32(tmp); /* signedness should not matter here */ + break; + case 0xc: /* LLIHH R1,I2 [RI] */ + tmp = tcg_const_i64( ((uint64_t)i2) << 48 ); + store_reg(r1, tmp); + break; + case 0xd: /* LLIHL R1,I2 [RI] */ + tmp = tcg_const_i64( ((uint64_t)i2) << 32 ); + store_reg(r1, tmp); + break; + case 0xe: /* LLILH R1,I2 [RI] */ + tmp = tcg_const_i64( ((uint64_t)i2) << 16 ); + store_reg(r1, tmp); + break; + case 0xf: /* LLILL R1,I2 [RI] */ + tmp = tcg_const_i64(i2); + store_reg(r1, tmp); + break; + default: + LOG_DISAS("illegal a5 operation 0x%x\n", op); + gen_illegal_opcode(s); + break; + } + if (tmp) tcg_temp_free(tmp); + if (tmp2) tcg_temp_free(tmp2); +} + +static void disas_a7(DisasContext *s, int op, int r1, int i2) +{ + TCGv tmp = 0,tmp2 = 0,tmp3 = 0; + LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); + switch (op) { + case 0x0: /* TMLH or TMH R1,I2 [RI] */ + tmp = load_reg(r1); + tcg_gen_shri_i64(tmp, tmp, 16); + tmp2 = tcg_const_i32((uint16_t)i2); + gen_helper_tmxx(cc, tmp, tmp2); + break; + case 0x1: /* TMLL or TML R1,I2 [RI] */ + tmp = load_reg(r1); + tmp2 = tcg_const_i32((uint16_t)i2); + gen_helper_tmxx(cc, tmp, tmp2); + break; + case 0x2: /* TMHH R1,I2 [RI] */ + tmp = load_reg(r1); + tcg_gen_shri_i64(tmp, tmp, 48); + tmp2 = tcg_const_i32((uint16_t)i2); + gen_helper_tmxx(cc, tmp, tmp2); + break; + case 0x3: /* TMHL R1,I2 [RI] */ + tmp = load_reg(r1); + tcg_gen_shri_i64(tmp, tmp, 32); + tmp2 = tcg_const_i32((uint16_t)i2); + gen_helper_tmxx(cc, tmp, tmp2); + break; + case 0x4: /* brc m1, i2 */ + /* FIXME: optimize m1 == 0xf (unconditional) case */ + gen_brc(r1, s->pc, i2 * 2); + s->is_jmp = DISAS_JUMP; + break; + case 0x5: /* BRAS R1,I2 [RI] */ + tmp = tcg_const_i64(s->pc + 4); + store_reg(r1, tmp); + tmp = tcg_const_i64(s->pc + i2 * 2); + tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, psw.addr)); + s->is_jmp = DISAS_JUMP; + break; + case 0x6: /* BRCT R1,I2 [RI] */ + tmp = load_reg32(r1); + tcg_gen_subi_i32(tmp, tmp, 1); + store_reg32(r1, tmp); + tmp2 = tcg_const_i64(s->pc); + tmp3 = tcg_const_i32(i2 * 2); + gen_helper_brct(tmp, tmp2, tmp3); + s->is_jmp = DISAS_JUMP; + break; + case 0x7: /* BRCTG R1,I2 [RI] */ + tmp = load_reg(r1); + tcg_gen_subi_i64(tmp, tmp, 1); + store_reg(r1, tmp); + tmp2 = tcg_const_i64(s->pc); + tmp3 = tcg_const_i32(i2 * 2); + gen_helper_brctg(tmp, tmp2, tmp3); + s->is_jmp = DISAS_JUMP; + break; + case 0x8: /* lhi r1, i2 */ + tmp = tcg_const_i32(i2); + store_reg32(r1, tmp); + break; + case 0x9: /* lghi r1, i2 */ + tmp = tcg_const_i64(i2); + store_reg(r1, tmp); + break; + case 0xa: /* AHI R1,I2 [RI] */ + tmp = load_reg32(r1); + tmp3 = tcg_temp_new_i32(); + tcg_gen_addi_i32(tmp3, tmp, i2); + store_reg32(r1, tmp3); + tmp2 = tcg_const_i32(i2); + gen_helper_set_cc_add32(cc, tmp, tmp2, tmp3); + break; + case 0xb: /* aghi r1, i2 */ + tmp = load_reg(r1); + tmp3 = tcg_temp_new_i64(); + tcg_gen_addi_i64(tmp3, tmp, i2); + store_reg(r1, tmp3); + tmp2 = tcg_const_i64(i2); + gen_set_cc_add64(tmp, tmp2, tmp3); + break; + case 0xc: /* MHI R1,I2 [RI] */ + tmp = load_reg32(r1); + tcg_gen_muli_i32(tmp, tmp, i2); + store_reg32(r1, tmp); + break; + case 0xd: /* MGHI R1,I2 [RI] */ + tmp = load_reg(r1); + tcg_gen_muli_i64(tmp, tmp, i2); + store_reg(r1, tmp); + break; + case 0xe: /* CHI R1,I2 [RI] */ + tmp = load_reg32(r1); + cmp_s32c(tmp, i2); + break; + case 0xf: /* CGHI R1,I2 [RI] */ + tmp = load_reg(r1); + cmp_s64c(tmp, i2); + break; + default: + LOG_DISAS("illegal a7 operation 0x%x\n", op); + gen_illegal_opcode(s); + break; + } + if (tmp) tcg_temp_free(tmp); + if (tmp2) tcg_temp_free(tmp2); + if (tmp3) tcg_temp_free(tmp3); +} + +static void disas_b2(DisasContext *s, int op, int r1, int r2) +{ + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; + LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); + switch (op) { + case 0x22: /* IPM R1 [RRE] */ + tmp = tcg_const_i32(r1); + gen_helper_ipm(cc, tmp); + break; + case 0x4e: /* SAR R1,R2 [RRE] */ + tmp = load_reg32(r2); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, aregs[r1])); + break; + case 0x4f: /* EAR R1,R2 [RRE] */ + tmp = tcg_temp_new_i32(); + tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, aregs[r2])); + store_reg32(r1, tmp); + break; + case 0x52: /* MSR R1,R2 [RRE] */ + tmp = load_reg32(r1); + tmp2 = load_reg32(r2); + tcg_gen_mul_i32(tmp, tmp, tmp2); + store_reg32(r1, tmp); + break; + case 0x55: /* MVST R1,R2 [RRE] */ + tmp = load_reg32(0); + tmp2 = tcg_const_i32(r1); + tmp3 = tcg_const_i32(r2); + gen_helper_mvst(cc, tmp, tmp2, tmp3); + break; + case 0x5d: /* CLST R1,R2 [RRE] */ + tmp = load_reg32(0); + tmp2 = tcg_const_i32(r1); + tmp3 = tcg_const_i32(r2); + gen_helper_clst(cc, tmp, tmp2, tmp3); + break; + case 0x5e: /* SRST R1,R2 [RRE] */ + tmp = load_reg32(0); + tmp2 = tcg_const_i32(r1); + tmp3 = tcg_const_i32(r2); + gen_helper_srst(cc, tmp, tmp2, tmp3); + break; + default: + LOG_DISAS("illegal b2 operation 0x%x\n", op); + gen_illegal_opcode(s); + break; + } + if (tmp) tcg_temp_free(tmp); + if (tmp2) tcg_temp_free(tmp2); + if (tmp3) tcg_temp_free(tmp3); +} + +static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) +{ + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; + LOG_DISAS("disas_b3: op 0x%x m3 0x%x r1 %d r2 %d\n", op, m3, r1, r2); +#define FP_HELPER(i) \ + tmp = tcg_const_i32(r1); \ + tmp2 = tcg_const_i32(r2); \ + gen_helper_ ## i (tmp, tmp2); +#define FP_HELPER_CC(i) \ + tmp = tcg_const_i32(r1); \ + tmp2 = tcg_const_i32(r2); \ + gen_helper_ ## i (cc, tmp, tmp2); + + switch (op) { + case 0x0: /* LPEBR R1,R2 [RRE] */ + FP_HELPER_CC(lpebr); break; + case 0x2: /* LTEBR R1,R2 [RRE] */ + FP_HELPER_CC(ltebr); break; + case 0x3: /* LCEBR R1,R2 [RRE] */ + FP_HELPER_CC(lcebr); break; + case 0x4: /* LDEBR R1,R2 [RRE] */ + FP_HELPER(ldebr); break; + case 0x5: /* LXDBR R1,R2 [RRE] */ + FP_HELPER(lxdbr); break; + case 0x9: /* CEBR R1,R2 [RRE] */ + FP_HELPER_CC(cebr); break; + case 0xa: /* AEBR R1,R2 [RRE] */ + FP_HELPER_CC(aebr); break; + case 0xb: /* SEBR R1,R2 [RRE] */ + FP_HELPER_CC(sebr); break; + case 0xd: /* DEBR R1,R2 [RRE] */ + FP_HELPER(debr); break; + case 0x10: /* LPDBR R1,R2 [RRE] */ + FP_HELPER_CC(lpdbr); break; + case 0x12: /* LTDBR R1,R2 [RRE] */ + FP_HELPER_CC(ltdbr); break; + case 0x13: /* LCDBR R1,R2 [RRE] */ + FP_HELPER_CC(lcdbr); break; + case 0x15: /* SQBDR R1,R2 [RRE] */ + FP_HELPER(sqdbr); break; + case 0x17: /* MEEBR R1,R2 [RRE] */ + FP_HELPER(meebr); break; + case 0x19: /* CDBR R1,R2 [RRE] */ + FP_HELPER_CC(cdbr); break; + case 0x1a: /* ADBR R1,R2 [RRE] */ + FP_HELPER_CC(adbr); break; + case 0x1b: /* SDBR R1,R2 [RRE] */ + FP_HELPER_CC(sdbr); break; + case 0x1c: /* MDBR R1,R2 [RRE] */ + FP_HELPER(mdbr); break; + case 0x1d: /* DDBR R1,R2 [RRE] */ + FP_HELPER(ddbr); break; + case 0xe: /* MAEBR R1,R3,R2 [RRF] */ + case 0x1e: /* MADBR R1,R3,R2 [RRF] */ + case 0x1f: /* MSDBR R1,R3,R2 [RRF] */ + /* for RRF insns, m3 is R1, r1 is R3, and r2 is R2 */ + tmp = tcg_const_i32(m3); + tmp2 = tcg_const_i32(r2); + tmp3 = tcg_const_i32(r1); + switch (op) { + case 0xe: gen_helper_maebr(tmp, tmp3, tmp2); break; + case 0x1e: gen_helper_madbr(tmp, tmp3, tmp2); break; + case 0x1f: gen_helper_msdbr(tmp, tmp3, tmp2); break; + default: tcg_abort(); + } + break; + case 0x40: /* LPXBR R1,R2 [RRE] */ + FP_HELPER_CC(lpxbr); break; + case 0x42: /* LTXBR R1,R2 [RRE] */ + FP_HELPER_CC(ltxbr); break; + case 0x43: /* LCXBR R1,R2 [RRE] */ + FP_HELPER_CC(lcxbr); break; + case 0x44: /* LEDBR R1,R2 [RRE] */ + FP_HELPER(ledbr); break; + case 0x45: /* LDXBR R1,R2 [RRE] */ + FP_HELPER(ldxbr); break; + case 0x46: /* LEXBR R1,R2 [RRE] */ + FP_HELPER(lexbr); break; + case 0x49: /* CXBR R1,R2 [RRE] */ + FP_HELPER_CC(cxbr); break; + case 0x4a: /* AXBR R1,R2 [RRE] */ + FP_HELPER_CC(axbr); break; + case 0x4b: /* SXBR R1,R2 [RRE] */ + FP_HELPER_CC(sxbr); break; + case 0x4c: /* MXBR R1,R2 [RRE] */ + FP_HELPER(mxbr); break; + case 0x4d: /* DXBR R1,R2 [RRE] */ + FP_HELPER(dxbr); break; + case 0x65: /* LXR R1,R2 [RRE] */ + tmp = load_freg(r2); + store_freg(r1, tmp); + tmp = load_freg(r2 + 2); + store_freg(r1 + 2, tmp); + break; + case 0x74: /* LZER R1 [RRE] */ + tmp = tcg_const_i32(r1); + gen_helper_lzer(tmp); + break; + case 0x75: /* LZDR R1 [RRE] */ + tmp = tcg_const_i32(r1); + gen_helper_lzdr(tmp); + break; + case 0x76: /* LZXR R1 [RRE] */ + tmp = tcg_const_i32(r1); + gen_helper_lzxr(tmp); + break; + case 0x84: /* SFPC R1 [RRE] */ + tmp = load_reg32(r1); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, fpc)); + break; + case 0x8c: /* EFPC R1 [RRE] */ + tmp = tcg_temp_new_i32(); + tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, fpc)); + store_reg32(r1, tmp); + break; + case 0x94: /* CEFBR R1,R2 [RRE] */ + case 0x95: /* CDFBR R1,R2 [RRE] */ + case 0x96: /* CXFBR R1,R2 [RRE] */ + tmp = tcg_const_i32(r1); + tmp2 = load_reg32(r2); + switch (op) { + case 0x94: gen_helper_cefbr(tmp, tmp2); break; + case 0x95: gen_helper_cdfbr(tmp, tmp2); break; + case 0x96: gen_helper_cxfbr(tmp, tmp2); break; + default: tcg_abort(); + } + break; + case 0x98: /* CFEBR R1,R2 [RRE] */ + case 0x99: /* CFDBR R1,R2 [RRE] */ + case 0x9a: /* CFXBR R1,R2 [RRE] */ + tmp = tcg_const_i32(r1); + tmp2 = tcg_const_i32(r2); + tmp3 = tcg_const_i32(m3); + switch (op) { + case 0x98: gen_helper_cfebr(cc, tmp, tmp2, tmp3); break; + case 0x99: gen_helper_cfdbr(cc, tmp, tmp2, tmp3); break; + case 0x9a: gen_helper_cfxbr(cc, tmp, tmp2, tmp3); break; + default: tcg_abort(); + } + break; + case 0xa4: /* CEGBR R1,R2 [RRE] */ + case 0xa5: /* CDGBR R1,R2 [RRE] */ + tmp = tcg_const_i32(r1); + tmp2 = load_reg(r2); + switch (op) { + case 0xa4: gen_helper_cegbr(tmp, tmp2); break; + case 0xa5: gen_helper_cdgbr(tmp, tmp2); break; + default: tcg_abort(); + } + break; + case 0xa6: /* CXGBR R1,R2 [RRE] */ + tmp = tcg_const_i32(r1); + tmp2 = load_reg(r2); + gen_helper_cxgbr(tmp, tmp2); + break; + case 0xa8: /* CGEBR R1,R2 [RRE] */ + tmp = tcg_const_i32(r1); + tmp2 = tcg_const_i32(r2); + tmp3 = tcg_const_i32(m3); + gen_helper_cgebr(cc, tmp, tmp2, tmp3); + break; + case 0xa9: /* CGDBR R1,R2 [RRE] */ + tmp = tcg_const_i32(r1); + tmp2 = tcg_const_i32(r2); + tmp3 = tcg_const_i32(m3); + gen_helper_cgdbr(cc, tmp, tmp2, tmp3); + break; + case 0xaa: /* CGXBR R1,R2 [RRE] */ + tmp = tcg_const_i32(r1); + tmp2 = tcg_const_i32(r2); + tmp3 = tcg_const_i32(m3); + gen_helper_cgxbr(cc, tmp, tmp2, tmp3); + break; + default: + LOG_DISAS("illegal b3 operation 0x%x\n", op); + gen_illegal_opcode(s); + break; + } + if (tmp) tcg_temp_free(tmp); + if (tmp2) tcg_temp_free(tmp2); + if (tmp3) tcg_temp_free(tmp3); +} + +static void disas_b9(DisasContext *s, int op, int r1, int r2) +{ + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; + LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); + switch (op) { + case 0: /* LPGR R1,R2 [RRE] */ + case 0x10: /* LPGFR R1,R2 [RRE] */ + if (op == 0) { + tmp2 = load_reg(r2); + } + else { + tmp2 = load_reg32(r2); + tcg_gen_ext32s_i64(tmp2, tmp2); + } + tmp = tcg_const_i32(r1); + gen_helper_abs_i64(cc, tmp, tmp2); + break; + case 1: /* LNGR R1,R2 [RRE] */ + tmp2 = load_reg(r2); + tmp = tcg_const_i32(r1); + gen_helper_nabs_i64(cc, tmp, tmp2); + break; + case 2: /* LTGR R1,R2 [RRE] */ + tmp = load_reg(r2); + if (r1 != r2) store_reg(r1, tmp); + set_cc_s64(tmp); + break; + case 3: /* LCGR R1,R2 [RRE] */ + case 0x13: /* LCGFR R1,R2 [RRE] */ + if (op == 0x13) { + tmp = load_reg32(r2); + tcg_gen_ext32s_i64(tmp, tmp); + } + else { + tmp = load_reg(r2); + } + tcg_gen_neg_i64(tmp, tmp); + store_reg(r1, tmp); + gen_helper_set_cc_comp_s64(cc, tmp); + break; + case 4: /* LGR R1,R2 [RRE] */ + tmp = load_reg(r2); + store_reg(r1, tmp); + break; + case 0x6: /* LGBR R1,R2 [RRE] */ + tmp2 = load_reg(r2); + tcg_gen_ext8s_i64(tmp2, tmp2); + store_reg(r1, tmp2); + break; + case 8: /* AGR R1,R2 [RRE] */ + case 0xa: /* ALGR R1,R2 [RRE] */ + tmp = load_reg(r1); + tmp2 = load_reg(r2); + tmp3 = tcg_temp_new_i64(); + tcg_gen_add_i64(tmp3, tmp, tmp2); + store_reg(r1, tmp3); + switch (op) { + case 0x8: gen_set_cc_add64(tmp, tmp2, tmp3); break; + case 0xa: gen_helper_set_cc_addu64(cc, tmp, tmp2, tmp3); break; + default: tcg_abort(); + } + break; + case 9: /* SGR R1,R2 [RRE] */ + case 0xb: /* SLGR R1,R2 [RRE] */ + case 0x1b: /* SLGFR R1,R2 [RRE] */ + case 0x19: /* SGFR R1,R2 [RRE] */ + tmp = load_reg(r1); + switch (op) { + case 0x1b: case 0x19: + tmp2 = load_reg32(r2); + if (op == 0x19) tcg_gen_ext32s_i64(tmp2, tmp2); + else tcg_gen_ext32u_i64(tmp2, tmp2); + break; + default: + tmp2 = load_reg(r2); + break; + } + tmp3 = tcg_temp_new_i64(); + tcg_gen_sub_i64(tmp3, tmp, tmp2); + store_reg(r1, tmp3); + switch (op) { + case 9: case 0x19: gen_helper_set_cc_sub64(cc, tmp,tmp2,tmp3); break; + case 0xb: case 0x1b: gen_helper_set_cc_subu64(cc, tmp, tmp2, tmp3); break; + default: tcg_abort(); + } + break; + case 0xc: /* MSGR R1,R2 [RRE] */ + case 0x1c: /* MSGFR R1,R2 [RRE] */ + tmp = load_reg(r1); + tmp2 = load_reg(r2); + if (op == 0x1c) tcg_gen_ext32s_i64(tmp2, tmp2); + tcg_gen_mul_i64(tmp, tmp, tmp2); + store_reg(r1, tmp); + break; + case 0xd: /* DSGR R1,R2 [RRE] */ + case 0x1d: /* DSGFR R1,R2 [RRE] */ + tmp = load_reg(r1 + 1); + if (op == 0xd) { + tmp2 = load_reg(r2); + } + else { + tmp2 = load_reg32(r2); + tcg_gen_ext32s_i64(tmp2, tmp2); + } + tmp3 = tcg_temp_new_i64(); + tcg_gen_div_i64(tmp3, tmp, tmp2); + store_reg(r1 + 1, tmp3); + tcg_gen_rem_i64(tmp3, tmp, tmp2); + store_reg(r1, tmp3); + break; + case 0x14: /* LGFR R1,R2 [RRE] */ + tmp = load_reg32(r2); + tmp2 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(tmp2, tmp); + store_reg(r1, tmp2); + break; + case 0x16: /* LLGFR R1,R2 [RRE] */ + tmp = load_reg32(r2); + tcg_gen_ext32u_i64(tmp, tmp); + store_reg(r1, tmp); + break; + case 0x17: /* LLGTR R1,R2 [RRE] */ + tmp = load_reg32(r2); + tcg_gen_andi_i32(tmp, tmp, 0x7fffffffUL); + tcg_gen_ext32u_i64(tmp, tmp); + store_reg(r1, tmp); + break; + case 0x18: /* AGFR R1,R2 [RRE] */ + case 0x1a: /* ALGFR R1,R2 [RRE] */ + tmp2 = load_reg32(r2); + switch (op) { + case 0x18: tcg_gen_ext32s_i64(tmp2, tmp2); break; + case 0x1a: tcg_gen_ext32u_i64(tmp2, tmp2); break; + default: tcg_abort(); + } + tmp = load_reg(r1); + tmp3 = tcg_temp_new_i64(); + tcg_gen_add_i64(tmp3, tmp, tmp2); + store_reg(r1, tmp3); + switch (op) { + case 0x18: gen_set_cc_add64(tmp, tmp2, tmp3); break; + case 0x1a: gen_helper_set_cc_addu64(cc, tmp, tmp2, tmp3); break; + default: tcg_abort(); + } + break; + case 0x20: /* CGR R1,R2 [RRE] */ + case 0x30: /* CGFR R1,R2 [RRE] */ + tmp2 = load_reg(r2); + if (op == 0x30) tcg_gen_ext32s_i64(tmp2, tmp2); + tmp = load_reg(r1); + cmp_s64(tmp, tmp2); + break; + case 0x21: /* CLGR R1,R2 [RRE] */ + case 0x31: /* CLGFR R1,R2 [RRE] */ + tmp2 = load_reg(r2); + if (op == 0x31) tcg_gen_ext32u_i64(tmp2, tmp2); + tmp = load_reg(r1); + cmp_u64(tmp, tmp2); + break; + case 0x26: /* LBR R1,R2 [RRE] */ + tmp2 = load_reg32(r2); + tcg_gen_ext8s_i32(tmp2, tmp2); + store_reg32(r1, tmp2); + break; + case 0x27: /* LHR R1,R2 [RRE] */ + tmp2 = load_reg32(r2); + tcg_gen_ext16s_i32(tmp2, tmp2); + store_reg32(r1, tmp2); + break; + case 0x80: /* NGR R1,R2 [RRE] */ + case 0x81: /* OGR R1,R2 [RRE] */ + case 0x82: /* XGR R1,R2 [RRE] */ + tmp = load_reg(r1); + tmp2 = load_reg(r2); + switch (op) { + case 0x80: tcg_gen_and_i64(tmp, tmp, tmp2); break; + case 0x81: tcg_gen_or_i64(tmp, tmp, tmp2); break; + case 0x82: tcg_gen_xor_i64(tmp, tmp, tmp2); break; + default: tcg_abort(); + } + store_reg(r1, tmp); + set_cc_nz_u64(tmp); + break; + case 0x83: /* FLOGR R1,R2 [RRE] */ + tmp2 = load_reg(r2); + tmp = tcg_const_i32(r1); + gen_helper_flogr(cc, tmp, tmp2); + break; + case 0x84: /* LLGCR R1,R2 [RRE] */ + tmp = load_reg(r2); + tcg_gen_andi_i64(tmp, tmp, 0xff); + store_reg(r1, tmp); + break; + case 0x85: /* LLGHR R1,R2 [RRE] */ + tmp = load_reg(r2); + tcg_gen_andi_i64(tmp, tmp, 0xffff); + store_reg(r1, tmp); + break; + case 0x87: /* DLGR R1,R2 [RRE] */ + tmp = tcg_const_i32(r1); + tmp2 = load_reg(r2); + gen_helper_dlg(tmp, tmp2); + break; + case 0x88: /* ALCGR R1,R2 [RRE] */ + tmp = load_reg(r1); + tmp2 = load_reg(r2); + tmp3 = tcg_temp_new_i64(); + tcg_gen_shri_i64(tmp3, cc, 1); + tcg_gen_andi_i64(tmp3, tmp3, 1); + tcg_gen_add_i64(tmp3, tmp2, tmp3); + tcg_gen_add_i64(tmp3, tmp, tmp3); + store_reg(r1, tmp3); + gen_helper_set_cc_addc_u64(cc, tmp, tmp2, tmp3); + break; + case 0x89: /* SLBGR R1,R2 [RRE] */ + tmp = load_reg(r1); + tmp2 = load_reg(r2); + tmp3 = tcg_const_i32(r1); + gen_helper_slbg(cc, cc, tmp3, tmp, tmp2); + break; + case 0x94: /* LLCR R1,R2 [RRE] */ + tmp = load_reg32(r2); + tcg_gen_andi_i32(tmp, tmp, 0xff); + store_reg32(r1, tmp); + break; + case 0x95: /* LLHR R1,R2 [RRE] */ + tmp = load_reg32(r2); + tcg_gen_andi_i32(tmp, tmp, 0xffff); + store_reg32(r1, tmp); + break; + case 0x98: /* ALCR R1,R2 [RRE] */ + tmp = tcg_const_i32(r1); + tmp2 = load_reg32(r2); + gen_helper_addc_u32(cc, cc, tmp, tmp2); + break; + case 0x99: /* SLBR R1,R2 [RRE] */ + tmp = load_reg32(r1); + tmp2 = load_reg32(r2); + tmp3 = tcg_const_i32(r1); + gen_helper_slb(cc, cc, tmp3, tmp, tmp2); + break; + default: + LOG_DISAS("illegal b9 operation 0x%x\n", op); + gen_illegal_opcode(s); + break; + } + if (tmp) tcg_temp_free(tmp); + if (tmp2) tcg_temp_free(tmp2); + if (tmp3) tcg_temp_free(tmp3); +} + +static void disas_c0(DisasContext *s, int op, int r1, int i2) +{ + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; + LOG_DISAS("disas_c0: op 0x%x r1 %d i2 %d\n", op, r1, i2); + uint64_t target = s->pc + i2 * 2; + /* FIXME: huh? */ target &= 0xffffffff; + switch (op) { + case 0: /* larl r1, i2 */ + tmp = tcg_const_i64(target); + store_reg(r1, tmp); + break; + case 0x1: /* LGFI R1,I2 [RIL] */ + tmp = tcg_const_i64((int64_t)i2); + store_reg(r1, tmp); + break; + case 0x4: /* BRCL M1,I2 [RIL] */ + tmp = tcg_const_i32(r1); /* aka m1 */ + tmp2 = tcg_const_i64(s->pc); + tmp3 = tcg_const_i64(i2 * 2); + gen_helper_brcl(cc, tmp, tmp2, tmp3); + s->is_jmp = DISAS_JUMP; + break; + case 0x5: /* brasl r1, i2 */ + tmp = tcg_const_i64(s->pc + 6); + store_reg(r1, tmp); + tmp = tcg_const_i64(target); + tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, psw.addr)); + s->is_jmp = DISAS_JUMP; + break; + case 0x7: /* XILF R1,I2 [RIL] */ + case 0xb: /* NILF R1,I2 [RIL] */ + case 0xd: /* OILF R1,I2 [RIL] */ + tmp = load_reg32(r1); + switch (op) { + case 0x7: tcg_gen_xori_i32(tmp, tmp, (uint32_t)i2); break; + case 0xb: tcg_gen_andi_i32(tmp, tmp, (uint32_t)i2); break; + case 0xd: tcg_gen_ori_i32(tmp, tmp, (uint32_t)i2); break; + default: tcg_abort(); + } + store_reg32(r1, tmp); + tcg_gen_trunc_i64_i32(tmp, tmp); + set_cc_nz_u32(tmp); + break; + case 0x9: /* IILF R1,I2 [RIL] */ + tmp = tcg_const_i32((uint32_t)i2); + store_reg32(r1, tmp); + break; + case 0xa: /* NIHF R1,I2 [RIL] */ + tmp = load_reg(r1); + switch (op) { + case 0xa: tcg_gen_andi_i64(tmp, tmp, (((uint64_t)((uint32_t)i2)) << 32) | 0xffffffffULL); break; + default: tcg_abort(); + } + store_reg(r1, tmp); + tcg_gen_shr_i64(tmp, tmp, 32); + tcg_gen_trunc_i64_i32(tmp, tmp); + set_cc_nz_u32(tmp); + break; + case 0xe: /* LLIHF R1,I2 [RIL] */ + tmp = tcg_const_i64(((uint64_t)(uint32_t)i2) << 32); + store_reg(r1, tmp); + break; + case 0xf: /* LLILF R1,I2 [RIL] */ + tmp = tcg_const_i64((uint32_t)i2); + store_reg(r1, tmp); + break; + default: + LOG_DISAS("illegal c0 operation 0x%x\n", op); + gen_illegal_opcode(s); + break; + } + if (tmp) tcg_temp_free(tmp); + if (tmp2) tcg_temp_free(tmp2); + if (tmp3) tcg_temp_free(tmp3); +} + +static void disas_c2(DisasContext *s, int op, int r1, int i2) +{ + TCGv tmp = 0, tmp2 = 0, tmp3 = 0; + switch (op) { + case 0x4: /* SLGFI R1,I2 [RIL] */ + case 0xa: /* ALGFI R1,I2 [RIL] */ + tmp = load_reg(r1); + tmp2 = tcg_const_i64((uint64_t)(uint32_t)i2); + tmp3 = tcg_temp_new_i64(); + switch (op) { + case 0x4: + tcg_gen_sub_i64(tmp3, tmp, tmp2); + gen_helper_set_cc_subu64(cc, tmp, tmp2, tmp3); + break; + case 0xa: + tcg_gen_add_i64(tmp3, tmp, tmp2); + gen_helper_set_cc_addu64(cc, tmp, tmp2, tmp3); + break; + default: tcg_abort(); + } + store_reg(r1, tmp3); + break; + case 0x5: /* SLFI R1,I2 [RIL] */ + case 0xb: /* ALFI R1,I2 [RIL] */ + tmp = load_reg32(r1); + tmp2 = tcg_const_i32(i2); + tmp3 = tcg_temp_new_i32(); + switch (op) { + case 0x5: + tcg_gen_sub_i32(tmp3, tmp, tmp2); + gen_helper_set_cc_subu32(cc, tmp, tmp2, tmp3); + break; + case 0xb: + tcg_gen_add_i32(tmp3, tmp, tmp2); + gen_helper_set_cc_addu32(cc, tmp, tmp2, tmp3); + break; + default: tcg_abort(); + } + store_reg32(r1, tmp3); + break; + case 0xc: /* CGFI R1,I2 [RIL] */ + tmp = load_reg(r1); + cmp_s64c(tmp, (int64_t)i2); + break; + case 0xe: /* CLGFI R1,I2 [RIL] */ + tmp = load_reg(r1); + cmp_u64c(tmp, (uint64_t)(uint32_t)i2); + break; + case 0xd: /* CFI R1,I2 [RIL] */ + case 0xf: /* CLFI R1,I2 [RIL] */ + tmp = load_reg32(r1); + switch (op) { + case 0xd: cmp_s32c(tmp, i2); break; + case 0xf: cmp_u32c(tmp, i2); break; + default: tcg_abort(); + } + break; + default: + LOG_DISAS("illegal c2 operation 0x%x\n", op); + gen_illegal_opcode(s); + break; + } + if (tmp) tcg_temp_free(tmp); + if (tmp2) tcg_temp_free(tmp2); + if (tmp3) tcg_temp_free(tmp3); +} + +static inline uint64_t ld_code2(uint64_t pc) { return (uint64_t)lduw_code(pc); } +static inline uint64_t ld_code4(uint64_t pc) { return (uint64_t)ldl_code(pc); } +static inline uint64_t ld_code6(uint64_t pc) +{ + uint64_t opc; + opc = (uint64_t)lduw_code(pc) << 32; + opc |= (uint64_t)(unsigned int)ldl_code(pc+2); + return opc; +} + +static void disas_s390_insn(CPUState *env, DisasContext *s) +{ + TCGv tmp = 0,tmp2 = 0,tmp3 = 0; + unsigned char opc; + uint64_t insn; + int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; + TCGv vl, vd1, vd2, vb; + + opc = ldub_code(s->pc); + LOG_DISAS("opc 0x%x\n", opc); + +#define FETCH_DECODE_RR \ + insn = ld_code2(s->pc); \ + DEBUGINSN \ + r1 = (insn >> 4) & 0xf; \ + r2 = insn & 0xf; + +#define FETCH_DECODE_RX \ + insn = ld_code4(s->pc); \ + DEBUGINSN \ + r1 = (insn >> 20) & 0xf; \ + x2 = (insn >> 16) & 0xf; \ + b2 = (insn >> 12) & 0xf; \ + d2 = insn & 0xfff; \ + tmp = get_address(x2, b2, d2); + +#define FETCH_DECODE_RS \ + insn = ld_code4(s->pc); \ + DEBUGINSN \ + r1 = (insn >> 20) & 0xf; \ + r3 = (insn >> 16) & 0xf; /* aka m3 */ \ + b2 = (insn >> 12) & 0xf; \ + d2 = insn & 0xfff; + +#define FETCH_DECODE_SI \ + insn = ld_code4(s->pc); \ + i2 = (insn >> 16) & 0xff; \ + b1 = (insn >> 12) & 0xf; \ + d1 = insn & 0xfff; \ + tmp = get_address(0, b1, d1); + + switch (opc) { + case 0x7: /* BCR M1,R2 [RR] */ + FETCH_DECODE_RR + if (r2) { + gen_bcr(r1, r2, s->pc); + s->is_jmp = DISAS_JUMP; + } + else { + /* FIXME: "serialization and checkpoint-synchronization function"? */ + } + s->pc += 2; + break; + case 0xa: /* SVC I [RR] */ + insn = ld_code2(s->pc); + DEBUGINSN + i = insn & 0xff; + tmp = tcg_const_i64(s->pc); + tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, psw.addr)); + s->is_jmp = DISAS_SVC; + s->pc += 2; + break; + case 0xd: /* BASR R1,R2 [RR] */ + FETCH_DECODE_RR + tmp = tcg_const_i64(s->pc + 2); + store_reg(r1, tmp); + if (r2) { + tmp2 = load_reg(r2); + tcg_gen_st_i64(tmp2, cpu_env, offsetof(CPUState, psw.addr)); + s->is_jmp = DISAS_JUMP; + } + s->pc += 2; + break; + case 0x10: /* LPR R1,R2 [RR] */ + FETCH_DECODE_RR + tmp2 = load_reg32(r2); + tmp = tcg_const_i32(r1); + gen_helper_abs_i32(cc, tmp, tmp2); + s->pc += 2; + break; + case 0x11: /* LNR R1,R2 [RR] */ + FETCH_DECODE_RR + tmp2 = load_reg32(r2); + tmp = tcg_const_i32(r1); + gen_helper_nabs_i32(cc, tmp, tmp2); + s->pc += 2; + break; + case 0x12: /* LTR R1,R2 [RR] */ + FETCH_DECODE_RR + tmp = load_reg32(r2); + if (r1 != r2) store_reg32(r1, tmp); + set_cc_s32(tmp); + s->pc += 2; + break; + case 0x13: /* LCR R1,R2 [RR] */ + FETCH_DECODE_RR + tmp = load_reg32(r2); + tcg_gen_neg_i32(tmp, tmp); + store_reg32(r1, tmp); + gen_helper_set_cc_comp_s32(cc, tmp); + s->pc += 2; + break; + case 0x14: /* NR R1,R2 [RR] */ + case 0x16: /* OR R1,R2 [RR] */ + case 0x17: /* XR R1,R2 [RR] */ + FETCH_DECODE_RR + tmp2 = load_reg32(r2); + tmp = load_reg32(r1); + switch (opc) { + case 0x14: tcg_gen_and_i32(tmp, tmp, tmp2); break; + case 0x16: tcg_gen_or_i32(tmp, tmp, tmp2); break; + case 0x17: tcg_gen_xor_i32(tmp, tmp, tmp2); break; + default: tcg_abort(); + } + store_reg32(r1, tmp); + set_cc_nz_u32(tmp); + s->pc += 2; + break; + case 0x18: /* LR R1,R2 [RR] */ + FETCH_DECODE_RR + tmp = load_reg32(r2); + store_reg32(r1, tmp); + s->pc += 2; + break; + case 0x15: /* CLR R1,R2 [RR] */ + case 0x19: /* CR R1,R2 [RR] */ + FETCH_DECODE_RR + tmp = load_reg32(r1); + tmp2 = load_reg32(r2); + switch (opc) { + case 0x15: cmp_u32(tmp, tmp2); break; + case 0x19: cmp_s32(tmp, tmp2); break; + default: tcg_abort(); + } + s->pc += 2; + break; + case 0x1a: /* AR R1,R2 [RR] */ + case 0x1e: /* ALR R1,R2 [RR] */ + FETCH_DECODE_RR + tmp = load_reg32(r1); + tmp2 = load_reg32(r2); + tmp3 = tcg_temp_new_i32(); + tcg_gen_add_i32(tmp3, tmp, tmp2); + store_reg32(r1, tmp3); + switch (opc) { + case 0x1a: gen_helper_set_cc_add32(cc, tmp, tmp2, tmp3); break; + case 0x1e: gen_helper_set_cc_addu32(cc, tmp, tmp2, tmp3); break; + default: tcg_abort(); + } + s->pc += 2; + break; + case 0x1b: /* SR R1,R2 [RR] */ + case 0x1f: /* SLR R1,R2 [RR] */ + FETCH_DECODE_RR + tmp = load_reg32(r1); + tmp2 = load_reg32(r2); + tmp3 = tcg_temp_new_i32(); + tcg_gen_sub_i32(tmp3, tmp, tmp2); + store_reg32(r1, tmp3); + switch (opc) { + case 0x1b: gen_helper_set_cc_sub32(cc, tmp, tmp2, tmp3); break; + case 0x1f: gen_helper_set_cc_subu32(cc, tmp, tmp2, tmp3); break; + default: tcg_abort(); + } + s->pc += 2; + break; + case 0x28: /* LDR R1,R2 [RR] */ + FETCH_DECODE_RR + tmp = load_freg(r2); + store_freg(r1, tmp); + s->pc += 2; + break; + case 0x38: /* LER R1,R2 [RR] */ + FETCH_DECODE_RR + tmp = load_freg32(r2); + store_freg32(r1, tmp); + s->pc += 2; + break; + case 0x40: /* STH R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = load_reg32(r1); + tcg_gen_qemu_st16(tmp2, tmp, 1); + s->pc += 4; + break; + case 0x41: /* la */ + FETCH_DECODE_RX + store_reg(r1, tmp); /* FIXME: 31/24-bit addressing */ + s->pc += 4; + break; + case 0x42: /* STC R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = load_reg32(r1); + tcg_gen_qemu_st8(tmp2, tmp, 1); + s->pc += 4; + break; + case 0x43: /* IC R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld8u(tmp2, tmp, 1); + store_reg8(r1, tmp2); + s->pc += 4; + break; + case 0x44: /* EX R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = load_reg(r1); + tmp3 = tcg_const_i64(s->pc + 4); + gen_helper_ex(cc, cc, tmp2, tmp, tmp3); + s->pc += 4; + break; + case 0x47: /* BC M1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + /* FIXME: optimize m1 == 0xf (unconditional) case */ + tmp2 = tcg_const_i32(r1); /* aka m1 */ + tmp3 = tcg_const_i64(s->pc); + gen_helper_bc(cc, tmp2, tmp, tmp3); + s->is_jmp = DISAS_JUMP; + s->pc += 4; + break; + case 0x48: /* LH R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld16s(tmp2, tmp, 1); + store_reg32(r1, tmp2); + s->pc += 4; + break; + case 0x49: /* CH R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld16s(tmp2, tmp, 1); + tmp = load_reg32(r1); + cmp_s32(tmp, tmp2); + s->pc += 4; + break; + case 0x4a: /* AH R1,D2(X2,B2) [RX] */ + case 0x4b: /* SH R1,D2(X2,B2) [RX] */ + case 0x4c: /* MH R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld16s(tmp2, tmp, 1); + tmp = load_reg32(r1); + tmp3 = tcg_temp_new_i32(); + switch (opc) { + case 0x4a: + tcg_gen_add_i32(tmp3, tmp, tmp2); + gen_helper_set_cc_add32(cc, tmp, tmp2, tmp3); + break; + case 0x4b: + tcg_gen_sub_i32(tmp3, tmp, tmp2); + gen_helper_set_cc_sub32(cc, tmp, tmp2, tmp3); + break; + case 0x4c: + tcg_gen_mul_i32(tmp3, tmp, tmp2); + break; + default: tcg_abort(); + } + store_reg32(r1, tmp3); + s->pc += 4; + break; + case 0x50: /* st r1, d2(x2, b2) */ + FETCH_DECODE_RX + tmp2 = load_reg32(r1); + tcg_gen_qemu_st32(tmp2, tmp, 1); + s->pc += 4; + break; + case 0x55: /* CL R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + tmp = load_reg32(r1); + cmp_u32(tmp, tmp2); + s->pc += 4; + break; + case 0x54: /* N R1,D2(X2,B2) [RX] */ + case 0x56: /* O R1,D2(X2,B2) [RX] */ + case 0x57: /* X R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + tmp = load_reg32(r1); + switch (opc) { + case 0x54: tcg_gen_and_i32(tmp, tmp, tmp2); break; + case 0x56: tcg_gen_or_i32(tmp, tmp, tmp2); break; + case 0x57: tcg_gen_xor_i32(tmp, tmp, tmp2); break; + default: tcg_abort(); + } + store_reg32(r1, tmp); + set_cc_nz_u32(tmp); + s->pc += 4; + break; + case 0x58: /* l r1, d2(x2, b2) */ + FETCH_DECODE_RX + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + store_reg32(r1, tmp2); + s->pc += 4; + break; + case 0x59: /* C R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32s(tmp2, tmp, 1); + tmp = load_reg32(r1); + cmp_s32(tmp, tmp2); + s->pc += 4; + break; + case 0x5a: /* A R1,D2(X2,B2) [RX] */ + case 0x5b: /* S R1,D2(X2,B2) [RX] */ + case 0x5e: /* AL R1,D2(X2,B2) [RX] */ + case 0x5f: /* SL R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = load_reg32(r1); + tcg_gen_qemu_ld32s(tmp, tmp, 1); + tmp3 = tcg_temp_new_i32(); + switch (opc) { + case 0x5a: case 0x5e: tcg_gen_add_i32(tmp3, tmp2, tmp); break; + case 0x5b: case 0x5f: tcg_gen_sub_i32(tmp3, tmp2, tmp); break; + default: tcg_abort(); + } + store_reg32(r1, tmp3); + switch (opc) { + case 0x5a: gen_helper_set_cc_add32(cc, tmp2, tmp, tmp3); break; + case 0x5e: gen_helper_set_cc_addu32(cc, tmp2, tmp, tmp3); break; + case 0x5b: gen_helper_set_cc_sub32(cc, tmp2, tmp, tmp3); break; + case 0x5f: gen_helper_set_cc_subu32(cc, tmp2, tmp, tmp3); break; + default: tcg_abort(); + } + s->pc += 4; + break; + case 0x60: /* STD R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = load_freg(r1); + tcg_gen_qemu_st64(tmp2, tmp, 1); + s->pc += 4; + break; + case 0x68: /* LD R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp2, tmp, 1); + store_freg(r1, tmp2); + s->pc += 4; + break; + case 0x70: /* STE R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = load_freg32(r1); + tcg_gen_qemu_st32(tmp2, tmp, 1); + s->pc += 4; + break; + case 0x71: /* MS R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32s(tmp2, tmp, 1); + tmp = load_reg(r1); + tcg_gen_mul_i32(tmp, tmp, tmp2); + store_reg(r1, tmp); + s->pc += 4; + break; + case 0x78: /* LE R1,D2(X2,B2) [RX] */ + FETCH_DECODE_RX + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + store_freg32(r1, tmp2); + s->pc += 4; + break; + case 0x88: /* SRL R1,D2(B2) [RS] */ + case 0x89: /* SLL R1,D2(B2) [RS] */ + case 0x8a: /* SRA R1,D2(B2) [RS] */ + FETCH_DECODE_RS + tmp = get_address(0, b2, d2); + tcg_gen_andi_i64(tmp, tmp, 0x3f); + tmp2 = load_reg32(r1); + switch (opc) { + case 0x88: tcg_gen_shr_i32(tmp2, tmp2, tmp); break; + case 0x89: tcg_gen_shl_i32(tmp2, tmp2, tmp); break; + case 0x8a: tcg_gen_sar_i32(tmp2, tmp2, tmp); break; + default: tcg_abort(); + } + store_reg32(r1, tmp2); + if (opc == 0x8a) set_cc_s32(tmp2); + s->pc += 4; + break; + case 0x91: /* TM D1(B1),I2 [SI] */ + FETCH_DECODE_SI + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld8u(tmp2, tmp, 1); + tmp = tcg_const_i32(i2); + gen_helper_tm(cc, tmp2, tmp); + s->pc += 4; + break; + case 0x92: /* MVI D1(B1),I2 [SI] */ + FETCH_DECODE_SI + tmp2 = tcg_const_i32(i2); + tcg_gen_qemu_st8(tmp2, tmp, 1); + s->pc += 4; + break; + case 0x94: /* NI D1(B1),I2 [SI] */ + case 0x96: /* OI D1(B1),I2 [SI] */ + case 0x97: /* XI D1(B1),I2 [SI] */ + FETCH_DECODE_SI + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld8u(tmp2, tmp, 1); + switch (opc) { + case 0x94: tcg_gen_andi_i32(tmp2, tmp2, i2); break; + case 0x96: tcg_gen_ori_i32(tmp2, tmp2, i2); break; + case 0x97: tcg_gen_xori_i32(tmp2, tmp2, i2); break; + default: tcg_abort(); + } + tcg_gen_qemu_st8(tmp2, tmp, 1); + set_cc_nz_u32(tmp2); + s->pc += 4; + break; + case 0x95: /* CLI D1(B1),I2 [SI] */ + FETCH_DECODE_SI + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld8u(tmp2, tmp, 1); + cmp_u32c(tmp2, i2); + s->pc += 4; + break; + case 0x9b: /* STAM R1,R3,D2(B2) [RS] */ + FETCH_DECODE_RS + tmp = tcg_const_i32(r1); + tmp2 = get_address(0, b2, d2); + tmp3 = tcg_const_i32(r3); + gen_helper_stam(tmp, tmp2, tmp3); + s->pc += 4; + break; + case 0xa5: + insn = ld_code4(s->pc); + r1 = (insn >> 20) & 0xf; + op = (insn >> 16) & 0xf; + i2 = insn & 0xffff; + disas_a5(s, op, r1, i2); + s->pc += 4; + break; + case 0xa7: + insn = ld_code4(s->pc); + r1 = (insn >> 20) & 0xf; + op = (insn >> 16) & 0xf; + i2 = (short)insn; + disas_a7(s, op, r1, i2); + s->pc += 4; + break; + case 0xa8: /* MVCLE R1,R3,D2(B2) [RS] */ + FETCH_DECODE_RS + tmp = tcg_const_i32(r1); + tmp3 = tcg_const_i32(r3); + tmp2 = get_address(0, b2, d2); + gen_helper_mvcle(cc, tmp, tmp2, tmp3); + s->pc += 4; + break; + case 0xa9: /* CLCLE R1,R3,D2(B2) [RS] */ + FETCH_DECODE_RS + tmp = tcg_const_i32(r1); + tmp3 = tcg_const_i32(r3); + tmp2 = get_address(0, b2, d2); + gen_helper_clcle(cc, tmp, tmp2, tmp3); + s->pc += 4; + break; + case 0xb2: + insn = ld_code4(s->pc); + op = (insn >> 16) & 0xff; + switch (op) { + case 0x9c: /* STFPC D2(B2) [S] */ + d2 = insn & 0xfff; + b2 = (insn >> 12) & 0xf; + tmp = tcg_temp_new_i32(); + tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, fpc)); + tmp2 = get_address(0, b2, d2); + tcg_gen_qemu_st32(tmp, tmp2, 1); + break; + default: + r1 = (insn >> 4) & 0xf; + r2 = insn & 0xf; + disas_b2(s, op, r1, r2); + break; + } + s->pc += 4; + break; + case 0xb3: + insn = ld_code4(s->pc); + op = (insn >> 16) & 0xff; + r3 = (insn >> 12) & 0xf; /* aka m3 */ + r1 = (insn >> 4) & 0xf; + r2 = insn & 0xf; + disas_b3(s, op, r3, r1, r2); + s->pc += 4; + break; + case 0xb9: + insn = ld_code4(s->pc); + r1 = (insn >> 4) & 0xf; + r2 = insn & 0xf; + op = (insn >> 16) & 0xff; + disas_b9(s, op, r1, r2); + s->pc += 4; + break; + case 0xba: /* CS R1,R3,D2(B2) [RS] */ + FETCH_DECODE_RS + tmp = tcg_const_i32(r1); + tmp2 = get_address(0, b2, d2); + tmp3 = tcg_const_i32(r3); + gen_helper_cs(cc, tmp, tmp2, tmp3); + s->pc += 4; + break; + case 0xbd: /* CLM R1,M3,D2(B2) [RS] */ + FETCH_DECODE_RS + tmp3 = get_address(0, b2, d2); + tmp2 = tcg_const_i32(r3); /* aka m3 */ + tmp = load_reg32(r1); + gen_helper_clm(cc, tmp, tmp2, tmp3); + s->pc += 4; + break; + case 0xbe: /* STCM R1,M3,D2(B2) [RS] */ + FETCH_DECODE_RS + tmp3 = get_address(0, b2, d2); + tmp2 = tcg_const_i32(r3); /* aka m3 */ + tmp = load_reg32(r1); + gen_helper_stcm(tmp, tmp2, tmp3); + s->pc += 4; + break; + case 0xbf: /* ICM R1,M3,D2(B2) [RS] */ + FETCH_DECODE_RS + if (r3 == 15) { /* effectively a 32-bit load */ + tmp = get_address(0, b2, d2); + tmp2 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp2, tmp, 1); + store_reg32(r1, tmp2); + tmp = tcg_const_i32(r3); + gen_helper_set_cc_icm(cc, tmp, tmp2); + } + else if (r3) { + uint32_t mask = 0x00ffffffUL; + uint32_t shift = 24; + int m3 = r3; + tmp3 = load_reg32(r1); + tmp = get_address(0, b2, d2); + tmp2 = tcg_temp_new_i32(); + while (m3) { + if (m3 & 8) { + tcg_gen_qemu_ld8u(tmp2, tmp, 1); + if (shift) tcg_gen_shli_i32(tmp2, tmp2, shift); + tcg_gen_andi_i32(tmp3, tmp3, mask); + tcg_gen_or_i32(tmp3, tmp3, tmp2); + tcg_gen_addi_i64(tmp, tmp, 1); + } + m3 = (m3 << 1) & 0xf; + mask = (mask >> 8) | 0xff000000UL; + shift -= 8; + } + store_reg32(r1, tmp3); + tmp = tcg_const_i32(r3); + gen_helper_set_cc_icm(cc, tmp, tmp2); + } + else { + tmp = tcg_const_i32(0); + gen_helper_set_cc_icm(cc, tmp, tmp); /* i.e. env->cc = 0 */ + } + s->pc += 4; + break; + case 0xc0: + case 0xc2: + insn = ld_code6(s->pc); + r1 = (insn >> 36) & 0xf; + op = (insn >> 32) & 0xf; + i2 = (int)insn; + switch (opc) { + case 0xc0: disas_c0(s, op, r1, i2); break; + case 0xc2: disas_c2(s, op, r1, i2); break; + default: tcg_abort(); + } + s->pc += 6; + break; + case 0xd2: /* mvc d1(l, b1), d2(b2) */ + case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ + case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ + case 0xd6: /* OC D1(L,B1),D2(B2) [SS] */ + case 0xd7: /* xc d1(l, b1), d2(b2) */ + insn = ld_code6(s->pc); + vl = tcg_const_i32((insn >> 32) & 0xff); + b1 = (insn >> 28) & 0xf; + vd1 = tcg_const_i32((insn >> 16) & 0xfff); + b2 = (insn >> 12) & 0xf; + vd2 = tcg_const_i32(insn & 0xfff); + vb = tcg_const_i32((b1 << 4) | b2); + switch (opc) { + case 0xd2: gen_helper_mvc(vl, vb, vd1, vd2); break; + case 0xd4: gen_helper_nc(cc, vl, vb, vd1, vd2); break; + case 0xd5: gen_helper_clc(cc, vl, vb, vd1, vd2); break; + case 0xd6: gen_helper_oc(cc, vl, vb, vd1, vd2); break; + case 0xd7: gen_helper_xc(cc, vl, vb, vd1, vd2); break; + default: tcg_abort(); break; + } + s->pc += 6; + break; + case 0xe3: + insn = ld_code6(s->pc); + DEBUGINSN + d2 = ( (int) ( (((insn >> 16) & 0xfff) | ((insn << 4) & 0xff000)) << 12 ) ) >> 12; + disas_e3(s, /* op */ insn & 0xff, /* r1 */ (insn >> 36) & 0xf, /* x2 */ (insn >> 32) & 0xf, /* b2 */ (insn >> 28) & 0xf, d2 ); + s->pc += 6; + break; + case 0xeb: + insn = ld_code6(s->pc); + DEBUGINSN + op = insn & 0xff; + r1 = (insn >> 36) & 0xf; + r3 = (insn >> 32) & 0xf; + b2 = (insn >> 28) & 0xf; + d2 = ( (int) ( (((insn >> 16) & 0xfff) | ((insn << 4) & 0xff000)) << 12 ) ) >> 12; + disas_eb(s, op, r1, r3, b2, d2); + s->pc += 6; + break; + case 0xed: + insn = ld_code6(s->pc); + DEBUGINSN + op = insn & 0xff; + r1 = (insn >> 36) & 0xf; + x2 = (insn >> 32) & 0xf; + b2 = (insn >> 28) & 0xf; + d2 = (short)((insn >> 16) & 0xfff); + r1b = (insn >> 12) & 0xf; + disas_ed(s, op, r1, x2, b2, d2, r1b); + s->pc += 6; + break; + default: + LOG_DISAS("unimplemented opcode 0x%x\n", opc); + gen_illegal_opcode(s); + s->pc += 6; + break; + } + if (tmp) tcg_temp_free(tmp); + if (tmp2) tcg_temp_free(tmp2); + if (tmp3) tcg_temp_free(tmp3); +} + +static inline void gen_intermediate_code_internal (CPUState *env, + TranslationBlock *tb, + int search_pc) +{ + DisasContext dc; + target_ulong pc_start; + uint64_t next_page_start; + uint16_t *gen_opc_end; + int j, lj = -1; + int num_insns, max_insns; + + pc_start = tb->pc; + + dc.pc = tb->pc; + dc.env = env; + dc.pc = pc_start; + dc.is_jmp = DISAS_NEXT; + + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + + gen_icount_start(); +#if 1 + cc = tcg_temp_local_new_i32(); + tcg_gen_mov_i32(cc, global_cc); +#else + cc = global_cc; +#endif + do { + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + } + gen_opc_pc[lj] = dc.pc; + gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; + } + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); +#if defined S390X_DEBUG_DISAS + LOG_DISAS("pc " TARGET_FMT_lx "\n", + dc.pc); +#endif + disas_s390_insn(env, &dc); + + num_insns++; + } while (!dc.is_jmp && gen_opc_ptr < gen_opc_end && dc.pc < next_page_start && num_insns < max_insns); + tcg_gen_mov_i32(global_cc, cc); + tcg_temp_free(cc); + + if (!dc.is_jmp) { + tcg_gen_st_i64(tcg_const_i64(dc.pc), cpu_env, offsetof(CPUState, psw.addr)); + } + + if (dc.is_jmp == DISAS_SVC) { + tcg_gen_st_i64(tcg_const_i64(dc.pc), cpu_env, offsetof(CPUState, psw.addr)); + TCGv tmp = tcg_const_i32(EXCP_SVC); + gen_helper_exception(tmp); + } + + if (tb->cflags & CF_LAST_IO) + gen_io_end(); + /* Generate the return instruction */ + tcg_gen_exit_tb(0); + gen_icount_end(tb, num_insns); + *gen_opc_ptr = INDEX_op_end; + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + } else { + tb->size = dc.pc - pc_start; + tb->icount = num_insns; + } +#if defined S390X_DEBUG_DISAS + log_cpu_state_mask(CPU_LOG_TB_CPU, env, 0); + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { + qemu_log("IN: %s\n", lookup_symbol(pc_start)); + log_target_disas(pc_start, dc.pc - pc_start, 1); + qemu_log("\n"); + } +#endif +} + +void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 0); +} + +void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 1); +} + +void gen_pc_load(CPUState *env, TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) +{ + env->psw.addr = gen_opc_pc[pc_pos]; +}
Currently only does userspace with 64-bit addressing, but it's quite good at that. replaced always_inline with inline Signed-off-by: Ulrich Hecht <uli@suse.de> --- cpu-exec.c | 2 + disas.c | 3 + s390-dis.c | 4 +- target-s390x/cpu.h | 132 +++ target-s390x/exec.h | 51 + target-s390x/helper.c | 81 ++ target-s390x/helpers.h | 128 +++ target-s390x/op_helper.c | 1719 ++++++++++++++++++++++++++++++++ target-s390x/translate.c | 2479 ++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 4597 insertions(+), 2 deletions(-) create mode 100644 target-s390x/cpu.h create mode 100644 target-s390x/exec.h create mode 100644 target-s390x/helper.c create mode 100644 target-s390x/helpers.h create mode 100644 target-s390x/op_helper.c create mode 100644 target-s390x/translate.c