1*3a0eae85SDavid Hildenbrand /* 2*3a0eae85SDavid Hildenbrand * QEMU TCG support -- s390x vector floating point instruction support 3*3a0eae85SDavid Hildenbrand * 4*3a0eae85SDavid Hildenbrand * Copyright (C) 2019 Red Hat Inc 5*3a0eae85SDavid Hildenbrand * 6*3a0eae85SDavid Hildenbrand * Authors: 7*3a0eae85SDavid Hildenbrand * David Hildenbrand <david@redhat.com> 8*3a0eae85SDavid Hildenbrand * 9*3a0eae85SDavid Hildenbrand * This work is licensed under the terms of the GNU GPL, version 2 or later. 10*3a0eae85SDavid Hildenbrand * See the COPYING file in the top-level directory. 11*3a0eae85SDavid Hildenbrand */ 12*3a0eae85SDavid Hildenbrand #include "qemu/osdep.h" 13*3a0eae85SDavid Hildenbrand #include "qemu-common.h" 14*3a0eae85SDavid Hildenbrand #include "cpu.h" 15*3a0eae85SDavid Hildenbrand #include "internal.h" 16*3a0eae85SDavid Hildenbrand #include "vec.h" 17*3a0eae85SDavid Hildenbrand #include "tcg_s390x.h" 18*3a0eae85SDavid Hildenbrand #include "tcg/tcg-gvec-desc.h" 19*3a0eae85SDavid Hildenbrand #include "exec/exec-all.h" 20*3a0eae85SDavid Hildenbrand #include "exec/helper-proto.h" 21*3a0eae85SDavid Hildenbrand #include "fpu/softfloat.h" 22*3a0eae85SDavid Hildenbrand 23*3a0eae85SDavid Hildenbrand #define VIC_INVALID 0x1 24*3a0eae85SDavid Hildenbrand #define VIC_DIVBYZERO 0x2 25*3a0eae85SDavid Hildenbrand #define VIC_OVERFLOW 0x3 26*3a0eae85SDavid Hildenbrand #define VIC_UNDERFLOW 0x4 27*3a0eae85SDavid Hildenbrand #define VIC_INEXACT 0x5 28*3a0eae85SDavid Hildenbrand 29*3a0eae85SDavid Hildenbrand /* returns the VEX. If the VEX is 0, there is no trap */ 30*3a0eae85SDavid Hildenbrand static uint8_t check_ieee_exc(CPUS390XState *env, uint8_t enr, bool XxC, 31*3a0eae85SDavid Hildenbrand uint8_t *vec_exc) 32*3a0eae85SDavid Hildenbrand { 33*3a0eae85SDavid Hildenbrand uint8_t vece_exc = 0, trap_exc; 34*3a0eae85SDavid Hildenbrand unsigned qemu_exc; 35*3a0eae85SDavid Hildenbrand 36*3a0eae85SDavid Hildenbrand /* Retrieve and clear the softfloat exceptions */ 37*3a0eae85SDavid Hildenbrand qemu_exc = env->fpu_status.float_exception_flags; 38*3a0eae85SDavid Hildenbrand if (qemu_exc == 0) { 39*3a0eae85SDavid Hildenbrand return 0; 40*3a0eae85SDavid Hildenbrand } 41*3a0eae85SDavid Hildenbrand env->fpu_status.float_exception_flags = 0; 42*3a0eae85SDavid Hildenbrand 43*3a0eae85SDavid Hildenbrand vece_exc = s390_softfloat_exc_to_ieee(qemu_exc); 44*3a0eae85SDavid Hildenbrand 45*3a0eae85SDavid Hildenbrand /* Add them to the vector-wide s390x exception bits */ 46*3a0eae85SDavid Hildenbrand *vec_exc |= vece_exc; 47*3a0eae85SDavid Hildenbrand 48*3a0eae85SDavid Hildenbrand /* Check for traps and construct the VXC */ 49*3a0eae85SDavid Hildenbrand trap_exc = vece_exc & env->fpc >> 24; 50*3a0eae85SDavid Hildenbrand if (trap_exc) { 51*3a0eae85SDavid Hildenbrand if (trap_exc & S390_IEEE_MASK_INVALID) { 52*3a0eae85SDavid Hildenbrand return enr << 4 | VIC_INVALID; 53*3a0eae85SDavid Hildenbrand } else if (trap_exc & S390_IEEE_MASK_DIVBYZERO) { 54*3a0eae85SDavid Hildenbrand return enr << 4 | VIC_DIVBYZERO; 55*3a0eae85SDavid Hildenbrand } else if (trap_exc & S390_IEEE_MASK_OVERFLOW) { 56*3a0eae85SDavid Hildenbrand return enr << 4 | VIC_OVERFLOW; 57*3a0eae85SDavid Hildenbrand } else if (trap_exc & S390_IEEE_MASK_UNDERFLOW) { 58*3a0eae85SDavid Hildenbrand return enr << 4 | VIC_UNDERFLOW; 59*3a0eae85SDavid Hildenbrand } else if (!XxC) { 60*3a0eae85SDavid Hildenbrand g_assert(trap_exc & S390_IEEE_MASK_INEXACT); 61*3a0eae85SDavid Hildenbrand /* inexact has lowest priority on traps */ 62*3a0eae85SDavid Hildenbrand return enr << 4 | VIC_INEXACT; 63*3a0eae85SDavid Hildenbrand } 64*3a0eae85SDavid Hildenbrand } 65*3a0eae85SDavid Hildenbrand return 0; 66*3a0eae85SDavid Hildenbrand } 67*3a0eae85SDavid Hildenbrand 68*3a0eae85SDavid Hildenbrand static void handle_ieee_exc(CPUS390XState *env, uint8_t vxc, uint8_t vec_exc, 69*3a0eae85SDavid Hildenbrand uintptr_t retaddr) 70*3a0eae85SDavid Hildenbrand { 71*3a0eae85SDavid Hildenbrand if (vxc) { 72*3a0eae85SDavid Hildenbrand /* on traps, the fpc flags are not updated, instruction is suppressed */ 73*3a0eae85SDavid Hildenbrand tcg_s390_vector_exception(env, vxc, retaddr); 74*3a0eae85SDavid Hildenbrand } 75*3a0eae85SDavid Hildenbrand if (vec_exc) { 76*3a0eae85SDavid Hildenbrand /* indicate exceptions for all elements combined */ 77*3a0eae85SDavid Hildenbrand env->fpc |= vec_exc << 16; 78*3a0eae85SDavid Hildenbrand } 79*3a0eae85SDavid Hildenbrand } 80*3a0eae85SDavid Hildenbrand 81*3a0eae85SDavid Hildenbrand typedef uint64_t (*vop64_3_fn)(uint64_t a, uint64_t b, float_status *s); 82*3a0eae85SDavid Hildenbrand static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3, 83*3a0eae85SDavid Hildenbrand CPUS390XState *env, bool s, vop64_3_fn fn, 84*3a0eae85SDavid Hildenbrand uintptr_t retaddr) 85*3a0eae85SDavid Hildenbrand { 86*3a0eae85SDavid Hildenbrand uint8_t vxc, vec_exc = 0; 87*3a0eae85SDavid Hildenbrand S390Vector tmp = {}; 88*3a0eae85SDavid Hildenbrand int i; 89*3a0eae85SDavid Hildenbrand 90*3a0eae85SDavid Hildenbrand for (i = 0; i < 2; i++) { 91*3a0eae85SDavid Hildenbrand const uint64_t a = s390_vec_read_element64(v2, i); 92*3a0eae85SDavid Hildenbrand const uint64_t b = s390_vec_read_element64(v3, i); 93*3a0eae85SDavid Hildenbrand 94*3a0eae85SDavid Hildenbrand s390_vec_write_element64(&tmp, i, fn(a, b, &env->fpu_status)); 95*3a0eae85SDavid Hildenbrand vxc = check_ieee_exc(env, i, false, &vec_exc); 96*3a0eae85SDavid Hildenbrand if (s || vxc) { 97*3a0eae85SDavid Hildenbrand break; 98*3a0eae85SDavid Hildenbrand } 99*3a0eae85SDavid Hildenbrand } 100*3a0eae85SDavid Hildenbrand handle_ieee_exc(env, vxc, vec_exc, retaddr); 101*3a0eae85SDavid Hildenbrand *v1 = tmp; 102*3a0eae85SDavid Hildenbrand } 103*3a0eae85SDavid Hildenbrand 104*3a0eae85SDavid Hildenbrand static uint64_t vfa64(uint64_t a, uint64_t b, float_status *s) 105*3a0eae85SDavid Hildenbrand { 106*3a0eae85SDavid Hildenbrand return float64_add(a, b, s); 107*3a0eae85SDavid Hildenbrand } 108*3a0eae85SDavid Hildenbrand 109*3a0eae85SDavid Hildenbrand void HELPER(gvec_vfa64)(void *v1, const void *v2, const void *v3, 110*3a0eae85SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 111*3a0eae85SDavid Hildenbrand { 112*3a0eae85SDavid Hildenbrand vop64_3(v1, v2, v3, env, false, vfa64, GETPC()); 113*3a0eae85SDavid Hildenbrand } 114*3a0eae85SDavid Hildenbrand 115*3a0eae85SDavid Hildenbrand void HELPER(gvec_vfa64s)(void *v1, const void *v2, const void *v3, 116*3a0eae85SDavid Hildenbrand CPUS390XState *env, uint32_t desc) 117*3a0eae85SDavid Hildenbrand { 118*3a0eae85SDavid Hildenbrand vop64_3(v1, v2, v3, env, true, vfa64, GETPC()); 119*3a0eae85SDavid Hildenbrand } 120