160e9e3f1SDavid Hildenbrand /* 260e9e3f1SDavid Hildenbrand * QEMU TCG support -- s390x vector support instructions 360e9e3f1SDavid Hildenbrand * 460e9e3f1SDavid Hildenbrand * Copyright (C) 2019 Red Hat Inc 560e9e3f1SDavid Hildenbrand * 660e9e3f1SDavid Hildenbrand * Authors: 760e9e3f1SDavid Hildenbrand * David Hildenbrand <david@redhat.com> 860e9e3f1SDavid Hildenbrand * 960e9e3f1SDavid Hildenbrand * This work is licensed under the terms of the GNU GPL, version 2 or later. 1060e9e3f1SDavid Hildenbrand * See the COPYING file in the top-level directory. 1160e9e3f1SDavid Hildenbrand */ 1260e9e3f1SDavid Hildenbrand #include "qemu/osdep.h" 1360e9e3f1SDavid Hildenbrand #include "qemu-common.h" 1460e9e3f1SDavid Hildenbrand #include "cpu.h" 1560e9e3f1SDavid Hildenbrand #include "internal.h" 1660e9e3f1SDavid Hildenbrand #include "vec.h" 1760e9e3f1SDavid Hildenbrand #include "tcg/tcg.h" 1873946f0dSDavid Hildenbrand #include "tcg/tcg-gvec-desc.h" 1960e9e3f1SDavid Hildenbrand #include "exec/helper-proto.h" 2060e9e3f1SDavid Hildenbrand #include "exec/cpu_ldst.h" 2160e9e3f1SDavid Hildenbrand #include "exec/exec-all.h" 2260e9e3f1SDavid Hildenbrand 2360e9e3f1SDavid Hildenbrand void HELPER(vll)(CPUS390XState *env, void *v1, uint64_t addr, uint64_t bytes) 2460e9e3f1SDavid Hildenbrand { 2560e9e3f1SDavid Hildenbrand if (likely(bytes >= 16)) { 2660e9e3f1SDavid Hildenbrand uint64_t t0, t1; 2760e9e3f1SDavid Hildenbrand 2860e9e3f1SDavid Hildenbrand t0 = cpu_ldq_data_ra(env, addr, GETPC()); 2960e9e3f1SDavid Hildenbrand addr = wrap_address(env, addr + 8); 3060e9e3f1SDavid Hildenbrand t1 = cpu_ldq_data_ra(env, addr, GETPC()); 3160e9e3f1SDavid Hildenbrand s390_vec_write_element64(v1, 0, t0); 3260e9e3f1SDavid Hildenbrand s390_vec_write_element64(v1, 1, t1); 3360e9e3f1SDavid Hildenbrand } else { 3460e9e3f1SDavid Hildenbrand S390Vector tmp = {}; 3560e9e3f1SDavid Hildenbrand int i; 3660e9e3f1SDavid Hildenbrand 3760e9e3f1SDavid Hildenbrand for (i = 0; i < bytes; i++) { 3860e9e3f1SDavid Hildenbrand uint8_t byte = cpu_ldub_data_ra(env, addr, GETPC()); 3960e9e3f1SDavid Hildenbrand 4060e9e3f1SDavid Hildenbrand s390_vec_write_element8(&tmp, i, byte); 4160e9e3f1SDavid Hildenbrand addr = wrap_address(env, addr + 1); 4260e9e3f1SDavid Hildenbrand } 4360e9e3f1SDavid Hildenbrand *(S390Vector *)v1 = tmp; 4460e9e3f1SDavid Hildenbrand } 4560e9e3f1SDavid Hildenbrand } 4673946f0dSDavid Hildenbrand 4773946f0dSDavid Hildenbrand #define DEF_VPK_HFN(BITS, TBITS) \ 4873946f0dSDavid Hildenbrand typedef uint##TBITS##_t (*vpk##BITS##_fn)(uint##BITS##_t, int *); \ 4973946f0dSDavid Hildenbrand static int vpk##BITS##_hfn(S390Vector *v1, const S390Vector *v2, \ 5073946f0dSDavid Hildenbrand const S390Vector *v3, vpk##BITS##_fn fn) \ 5173946f0dSDavid Hildenbrand { \ 5273946f0dSDavid Hildenbrand int i, saturated = 0; \ 5373946f0dSDavid Hildenbrand S390Vector tmp; \ 5473946f0dSDavid Hildenbrand \ 5573946f0dSDavid Hildenbrand for (i = 0; i < (128 / TBITS); i++) { \ 5673946f0dSDavid Hildenbrand uint##BITS##_t src; \ 5773946f0dSDavid Hildenbrand \ 5873946f0dSDavid Hildenbrand if (i < (128 / BITS)) { \ 5973946f0dSDavid Hildenbrand src = s390_vec_read_element##BITS(v2, i); \ 6073946f0dSDavid Hildenbrand } else { \ 6173946f0dSDavid Hildenbrand src = s390_vec_read_element##BITS(v3, i - (128 / BITS)); \ 6273946f0dSDavid Hildenbrand } \ 6373946f0dSDavid Hildenbrand s390_vec_write_element##TBITS(&tmp, i, fn(src, &saturated)); \ 6473946f0dSDavid Hildenbrand } \ 6573946f0dSDavid Hildenbrand *v1 = tmp; \ 6673946f0dSDavid Hildenbrand return saturated; \ 6773946f0dSDavid Hildenbrand } 6873946f0dSDavid Hildenbrand DEF_VPK_HFN(64, 32) 6973946f0dSDavid Hildenbrand DEF_VPK_HFN(32, 16) 7073946f0dSDavid Hildenbrand DEF_VPK_HFN(16, 8) 7173946f0dSDavid Hildenbrand 7273946f0dSDavid Hildenbrand #define DEF_VPK(BITS, TBITS) \ 7373946f0dSDavid Hildenbrand static uint##TBITS##_t vpk##BITS##e(uint##BITS##_t src, int *saturated) \ 7473946f0dSDavid Hildenbrand { \ 7573946f0dSDavid Hildenbrand return src; \ 7673946f0dSDavid Hildenbrand } \ 7773946f0dSDavid Hildenbrand void HELPER(gvec_vpk##BITS)(void *v1, const void *v2, const void *v3, \ 7873946f0dSDavid Hildenbrand uint32_t desc) \ 7973946f0dSDavid Hildenbrand { \ 8073946f0dSDavid Hildenbrand vpk##BITS##_hfn(v1, v2, v3, vpk##BITS##e); \ 8173946f0dSDavid Hildenbrand } 8273946f0dSDavid Hildenbrand DEF_VPK(64, 32) 8373946f0dSDavid Hildenbrand DEF_VPK(32, 16) 8473946f0dSDavid Hildenbrand DEF_VPK(16, 8) 8573946f0dSDavid Hildenbrand 8673946f0dSDavid Hildenbrand #define DEF_VPKS(BITS, TBITS) \ 8773946f0dSDavid Hildenbrand static uint##TBITS##_t vpks##BITS##e(uint##BITS##_t src, int *saturated) \ 8873946f0dSDavid Hildenbrand { \ 8973946f0dSDavid Hildenbrand if ((int##BITS##_t)src > INT##TBITS##_MAX) { \ 9073946f0dSDavid Hildenbrand (*saturated)++; \ 9173946f0dSDavid Hildenbrand return INT##TBITS##_MAX; \ 9273946f0dSDavid Hildenbrand } else if ((int##BITS##_t)src < INT##TBITS##_MIN) { \ 9373946f0dSDavid Hildenbrand (*saturated)++; \ 9473946f0dSDavid Hildenbrand return INT##TBITS##_MIN; \ 9573946f0dSDavid Hildenbrand } \ 9673946f0dSDavid Hildenbrand return src; \ 9773946f0dSDavid Hildenbrand } \ 9873946f0dSDavid Hildenbrand void HELPER(gvec_vpks##BITS)(void *v1, const void *v2, const void *v3, \ 9973946f0dSDavid Hildenbrand uint32_t desc) \ 10073946f0dSDavid Hildenbrand { \ 10173946f0dSDavid Hildenbrand vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e); \ 10273946f0dSDavid Hildenbrand } \ 10373946f0dSDavid Hildenbrand void HELPER(gvec_vpks_cc##BITS)(void *v1, const void *v2, const void *v3, \ 10473946f0dSDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 10573946f0dSDavid Hildenbrand { \ 10673946f0dSDavid Hildenbrand int saturated = vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e); \ 10773946f0dSDavid Hildenbrand \ 10873946f0dSDavid Hildenbrand if (saturated == (128 / TBITS)) { \ 10973946f0dSDavid Hildenbrand env->cc_op = 3; \ 11073946f0dSDavid Hildenbrand } else if (saturated) { \ 11173946f0dSDavid Hildenbrand env->cc_op = 1; \ 11273946f0dSDavid Hildenbrand } else { \ 11373946f0dSDavid Hildenbrand env->cc_op = 0; \ 11473946f0dSDavid Hildenbrand } \ 11573946f0dSDavid Hildenbrand } 11673946f0dSDavid Hildenbrand DEF_VPKS(64, 32) 11773946f0dSDavid Hildenbrand DEF_VPKS(32, 16) 11873946f0dSDavid Hildenbrand DEF_VPKS(16, 8) 11973946f0dSDavid Hildenbrand 12073946f0dSDavid Hildenbrand #define DEF_VPKLS(BITS, TBITS) \ 12173946f0dSDavid Hildenbrand static uint##TBITS##_t vpkls##BITS##e(uint##BITS##_t src, int *saturated) \ 12273946f0dSDavid Hildenbrand { \ 12373946f0dSDavid Hildenbrand if (src > UINT##TBITS##_MAX) { \ 12473946f0dSDavid Hildenbrand (*saturated)++; \ 12573946f0dSDavid Hildenbrand return UINT##TBITS##_MAX; \ 12673946f0dSDavid Hildenbrand } \ 12773946f0dSDavid Hildenbrand return src; \ 12873946f0dSDavid Hildenbrand } \ 12973946f0dSDavid Hildenbrand void HELPER(gvec_vpkls##BITS)(void *v1, const void *v2, const void *v3, \ 13073946f0dSDavid Hildenbrand uint32_t desc) \ 13173946f0dSDavid Hildenbrand { \ 13273946f0dSDavid Hildenbrand vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e); \ 13373946f0dSDavid Hildenbrand } \ 13473946f0dSDavid Hildenbrand void HELPER(gvec_vpkls_cc##BITS)(void *v1, const void *v2, const void *v3, \ 13573946f0dSDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 13673946f0dSDavid Hildenbrand { \ 13773946f0dSDavid Hildenbrand int saturated = vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e); \ 13873946f0dSDavid Hildenbrand \ 13973946f0dSDavid Hildenbrand if (saturated == (128 / TBITS)) { \ 14073946f0dSDavid Hildenbrand env->cc_op = 3; \ 14173946f0dSDavid Hildenbrand } else if (saturated) { \ 14273946f0dSDavid Hildenbrand env->cc_op = 1; \ 14373946f0dSDavid Hildenbrand } else { \ 14473946f0dSDavid Hildenbrand env->cc_op = 0; \ 14573946f0dSDavid Hildenbrand } \ 14673946f0dSDavid Hildenbrand } 14773946f0dSDavid Hildenbrand DEF_VPKLS(64, 32) 14873946f0dSDavid Hildenbrand DEF_VPKLS(32, 16) 14973946f0dSDavid Hildenbrand DEF_VPKLS(16, 8) 1507aaf844dSDavid Hildenbrand 1517aaf844dSDavid Hildenbrand void HELPER(gvec_vperm)(void *v1, const void *v2, const void *v3, 1527aaf844dSDavid Hildenbrand const void *v4, uint32_t desc) 1537aaf844dSDavid Hildenbrand { 1547aaf844dSDavid Hildenbrand S390Vector tmp; 1557aaf844dSDavid Hildenbrand int i; 1567aaf844dSDavid Hildenbrand 1577aaf844dSDavid Hildenbrand for (i = 0; i < 16; i++) { 1587aaf844dSDavid Hildenbrand const uint8_t selector = s390_vec_read_element8(v4, i) & 0x1f; 1597aaf844dSDavid Hildenbrand uint8_t byte; 1607aaf844dSDavid Hildenbrand 1617aaf844dSDavid Hildenbrand if (selector < 16) { 1627aaf844dSDavid Hildenbrand byte = s390_vec_read_element8(v2, selector); 1637aaf844dSDavid Hildenbrand } else { 1647aaf844dSDavid Hildenbrand byte = s390_vec_read_element8(v3, selector - 16); 1657aaf844dSDavid Hildenbrand } 1667aaf844dSDavid Hildenbrand s390_vec_write_element8(&tmp, i, byte); 1677aaf844dSDavid Hildenbrand } 1687aaf844dSDavid Hildenbrand *(S390Vector *)v1 = tmp; 1697aaf844dSDavid Hildenbrand } 170*0e0a5b49SDavid Hildenbrand 171*0e0a5b49SDavid Hildenbrand void HELPER(vstl)(CPUS390XState *env, const void *v1, uint64_t addr, 172*0e0a5b49SDavid Hildenbrand uint64_t bytes) 173*0e0a5b49SDavid Hildenbrand { 174*0e0a5b49SDavid Hildenbrand /* Probe write access before actually modifying memory */ 175*0e0a5b49SDavid Hildenbrand probe_write_access(env, addr, bytes, GETPC()); 176*0e0a5b49SDavid Hildenbrand 177*0e0a5b49SDavid Hildenbrand if (likely(bytes >= 16)) { 178*0e0a5b49SDavid Hildenbrand cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 0), GETPC()); 179*0e0a5b49SDavid Hildenbrand addr = wrap_address(env, addr + 8); 180*0e0a5b49SDavid Hildenbrand cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 1), GETPC()); 181*0e0a5b49SDavid Hildenbrand } else { 182*0e0a5b49SDavid Hildenbrand S390Vector tmp = {}; 183*0e0a5b49SDavid Hildenbrand int i; 184*0e0a5b49SDavid Hildenbrand 185*0e0a5b49SDavid Hildenbrand for (i = 0; i < bytes; i++) { 186*0e0a5b49SDavid Hildenbrand uint8_t byte = s390_vec_read_element8(v1, i); 187*0e0a5b49SDavid Hildenbrand 188*0e0a5b49SDavid Hildenbrand cpu_stb_data_ra(env, addr, byte, GETPC()); 189*0e0a5b49SDavid Hildenbrand addr = wrap_address(env, addr + 1); 190*0e0a5b49SDavid Hildenbrand } 191*0e0a5b49SDavid Hildenbrand *(S390Vector *)v1 = tmp; 192*0e0a5b49SDavid Hildenbrand } 193*0e0a5b49SDavid Hildenbrand } 194