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 "cpu.h" 1460e9e3f1SDavid Hildenbrand #include "internal.h" 1560e9e3f1SDavid Hildenbrand #include "vec.h" 1660e9e3f1SDavid Hildenbrand #include "tcg/tcg.h" 1773946f0dSDavid Hildenbrand #include "tcg/tcg-gvec-desc.h" 1860e9e3f1SDavid Hildenbrand #include "exec/helper-proto.h" 1960e9e3f1SDavid Hildenbrand #include "exec/cpu_ldst.h" 2060e9e3f1SDavid Hildenbrand #include "exec/exec-all.h" 2160e9e3f1SDavid Hildenbrand 22*2a785dfbSDavid Hildenbrand void HELPER(gvec_vbperm)(void *v1, const void *v2, const void *v3, 23*2a785dfbSDavid Hildenbrand uint32_t desc) 24*2a785dfbSDavid Hildenbrand { 25*2a785dfbSDavid Hildenbrand S390Vector tmp = {}; 26*2a785dfbSDavid Hildenbrand uint16_t result = 0; 27*2a785dfbSDavid Hildenbrand int i; 28*2a785dfbSDavid Hildenbrand 29*2a785dfbSDavid Hildenbrand for (i = 0; i < 16; i++) { 30*2a785dfbSDavid Hildenbrand const uint8_t bit_nr = s390_vec_read_element8(v3, i); 31*2a785dfbSDavid Hildenbrand uint16_t bit; 32*2a785dfbSDavid Hildenbrand 33*2a785dfbSDavid Hildenbrand if (bit_nr >= 128) { 34*2a785dfbSDavid Hildenbrand continue; 35*2a785dfbSDavid Hildenbrand } 36*2a785dfbSDavid Hildenbrand bit = (s390_vec_read_element8(v2, bit_nr / 8) 37*2a785dfbSDavid Hildenbrand >> (7 - (bit_nr % 8))) & 1; 38*2a785dfbSDavid Hildenbrand result |= (bit << (15 - i)); 39*2a785dfbSDavid Hildenbrand } 40*2a785dfbSDavid Hildenbrand s390_vec_write_element16(&tmp, 3, result); 41*2a785dfbSDavid Hildenbrand *(S390Vector *)v1 = tmp; 42*2a785dfbSDavid Hildenbrand } 43*2a785dfbSDavid Hildenbrand 4460e9e3f1SDavid Hildenbrand void HELPER(vll)(CPUS390XState *env, void *v1, uint64_t addr, uint64_t bytes) 4560e9e3f1SDavid Hildenbrand { 4660e9e3f1SDavid Hildenbrand if (likely(bytes >= 16)) { 4760e9e3f1SDavid Hildenbrand uint64_t t0, t1; 4860e9e3f1SDavid Hildenbrand 4960e9e3f1SDavid Hildenbrand t0 = cpu_ldq_data_ra(env, addr, GETPC()); 5060e9e3f1SDavid Hildenbrand addr = wrap_address(env, addr + 8); 5160e9e3f1SDavid Hildenbrand t1 = cpu_ldq_data_ra(env, addr, GETPC()); 5260e9e3f1SDavid Hildenbrand s390_vec_write_element64(v1, 0, t0); 5360e9e3f1SDavid Hildenbrand s390_vec_write_element64(v1, 1, t1); 5460e9e3f1SDavid Hildenbrand } else { 5560e9e3f1SDavid Hildenbrand S390Vector tmp = {}; 5660e9e3f1SDavid Hildenbrand int i; 5760e9e3f1SDavid Hildenbrand 5860e9e3f1SDavid Hildenbrand for (i = 0; i < bytes; i++) { 5960e9e3f1SDavid Hildenbrand uint8_t byte = cpu_ldub_data_ra(env, addr, GETPC()); 6060e9e3f1SDavid Hildenbrand 6160e9e3f1SDavid Hildenbrand s390_vec_write_element8(&tmp, i, byte); 6260e9e3f1SDavid Hildenbrand addr = wrap_address(env, addr + 1); 6360e9e3f1SDavid Hildenbrand } 6460e9e3f1SDavid Hildenbrand *(S390Vector *)v1 = tmp; 6560e9e3f1SDavid Hildenbrand } 6660e9e3f1SDavid Hildenbrand } 6773946f0dSDavid Hildenbrand 6873946f0dSDavid Hildenbrand #define DEF_VPK_HFN(BITS, TBITS) \ 6973946f0dSDavid Hildenbrand typedef uint##TBITS##_t (*vpk##BITS##_fn)(uint##BITS##_t, int *); \ 7073946f0dSDavid Hildenbrand static int vpk##BITS##_hfn(S390Vector *v1, const S390Vector *v2, \ 7173946f0dSDavid Hildenbrand const S390Vector *v3, vpk##BITS##_fn fn) \ 7273946f0dSDavid Hildenbrand { \ 7373946f0dSDavid Hildenbrand int i, saturated = 0; \ 7473946f0dSDavid Hildenbrand S390Vector tmp; \ 7573946f0dSDavid Hildenbrand \ 7673946f0dSDavid Hildenbrand for (i = 0; i < (128 / TBITS); i++) { \ 7773946f0dSDavid Hildenbrand uint##BITS##_t src; \ 7873946f0dSDavid Hildenbrand \ 7973946f0dSDavid Hildenbrand if (i < (128 / BITS)) { \ 8073946f0dSDavid Hildenbrand src = s390_vec_read_element##BITS(v2, i); \ 8173946f0dSDavid Hildenbrand } else { \ 8273946f0dSDavid Hildenbrand src = s390_vec_read_element##BITS(v3, i - (128 / BITS)); \ 8373946f0dSDavid Hildenbrand } \ 8473946f0dSDavid Hildenbrand s390_vec_write_element##TBITS(&tmp, i, fn(src, &saturated)); \ 8573946f0dSDavid Hildenbrand } \ 8673946f0dSDavid Hildenbrand *v1 = tmp; \ 8773946f0dSDavid Hildenbrand return saturated; \ 8873946f0dSDavid Hildenbrand } 8973946f0dSDavid Hildenbrand DEF_VPK_HFN(64, 32) 9073946f0dSDavid Hildenbrand DEF_VPK_HFN(32, 16) 9173946f0dSDavid Hildenbrand DEF_VPK_HFN(16, 8) 9273946f0dSDavid Hildenbrand 9373946f0dSDavid Hildenbrand #define DEF_VPK(BITS, TBITS) \ 9473946f0dSDavid Hildenbrand static uint##TBITS##_t vpk##BITS##e(uint##BITS##_t src, int *saturated) \ 9573946f0dSDavid Hildenbrand { \ 9673946f0dSDavid Hildenbrand return src; \ 9773946f0dSDavid Hildenbrand } \ 9873946f0dSDavid Hildenbrand void HELPER(gvec_vpk##BITS)(void *v1, const void *v2, const void *v3, \ 9973946f0dSDavid Hildenbrand uint32_t desc) \ 10073946f0dSDavid Hildenbrand { \ 10173946f0dSDavid Hildenbrand vpk##BITS##_hfn(v1, v2, v3, vpk##BITS##e); \ 10273946f0dSDavid Hildenbrand } 10373946f0dSDavid Hildenbrand DEF_VPK(64, 32) 10473946f0dSDavid Hildenbrand DEF_VPK(32, 16) 10573946f0dSDavid Hildenbrand DEF_VPK(16, 8) 10673946f0dSDavid Hildenbrand 10773946f0dSDavid Hildenbrand #define DEF_VPKS(BITS, TBITS) \ 10873946f0dSDavid Hildenbrand static uint##TBITS##_t vpks##BITS##e(uint##BITS##_t src, int *saturated) \ 10973946f0dSDavid Hildenbrand { \ 11073946f0dSDavid Hildenbrand if ((int##BITS##_t)src > INT##TBITS##_MAX) { \ 11173946f0dSDavid Hildenbrand (*saturated)++; \ 11273946f0dSDavid Hildenbrand return INT##TBITS##_MAX; \ 11373946f0dSDavid Hildenbrand } else if ((int##BITS##_t)src < INT##TBITS##_MIN) { \ 11473946f0dSDavid Hildenbrand (*saturated)++; \ 11573946f0dSDavid Hildenbrand return INT##TBITS##_MIN; \ 11673946f0dSDavid Hildenbrand } \ 11773946f0dSDavid Hildenbrand return src; \ 11873946f0dSDavid Hildenbrand } \ 11973946f0dSDavid Hildenbrand void HELPER(gvec_vpks##BITS)(void *v1, const void *v2, const void *v3, \ 12073946f0dSDavid Hildenbrand uint32_t desc) \ 12173946f0dSDavid Hildenbrand { \ 12273946f0dSDavid Hildenbrand vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e); \ 12373946f0dSDavid Hildenbrand } \ 12473946f0dSDavid Hildenbrand void HELPER(gvec_vpks_cc##BITS)(void *v1, const void *v2, const void *v3, \ 12573946f0dSDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 12673946f0dSDavid Hildenbrand { \ 12773946f0dSDavid Hildenbrand int saturated = vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e); \ 12873946f0dSDavid Hildenbrand \ 12973946f0dSDavid Hildenbrand if (saturated == (128 / TBITS)) { \ 13073946f0dSDavid Hildenbrand env->cc_op = 3; \ 13173946f0dSDavid Hildenbrand } else if (saturated) { \ 13273946f0dSDavid Hildenbrand env->cc_op = 1; \ 13373946f0dSDavid Hildenbrand } else { \ 13473946f0dSDavid Hildenbrand env->cc_op = 0; \ 13573946f0dSDavid Hildenbrand } \ 13673946f0dSDavid Hildenbrand } 13773946f0dSDavid Hildenbrand DEF_VPKS(64, 32) 13873946f0dSDavid Hildenbrand DEF_VPKS(32, 16) 13973946f0dSDavid Hildenbrand DEF_VPKS(16, 8) 14073946f0dSDavid Hildenbrand 14173946f0dSDavid Hildenbrand #define DEF_VPKLS(BITS, TBITS) \ 14273946f0dSDavid Hildenbrand static uint##TBITS##_t vpkls##BITS##e(uint##BITS##_t src, int *saturated) \ 14373946f0dSDavid Hildenbrand { \ 14473946f0dSDavid Hildenbrand if (src > UINT##TBITS##_MAX) { \ 14573946f0dSDavid Hildenbrand (*saturated)++; \ 14673946f0dSDavid Hildenbrand return UINT##TBITS##_MAX; \ 14773946f0dSDavid Hildenbrand } \ 14873946f0dSDavid Hildenbrand return src; \ 14973946f0dSDavid Hildenbrand } \ 15073946f0dSDavid Hildenbrand void HELPER(gvec_vpkls##BITS)(void *v1, const void *v2, const void *v3, \ 15173946f0dSDavid Hildenbrand uint32_t desc) \ 15273946f0dSDavid Hildenbrand { \ 15373946f0dSDavid Hildenbrand vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e); \ 15473946f0dSDavid Hildenbrand } \ 15573946f0dSDavid Hildenbrand void HELPER(gvec_vpkls_cc##BITS)(void *v1, const void *v2, const void *v3, \ 15673946f0dSDavid Hildenbrand CPUS390XState *env, uint32_t desc) \ 15773946f0dSDavid Hildenbrand { \ 15873946f0dSDavid Hildenbrand int saturated = vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e); \ 15973946f0dSDavid Hildenbrand \ 16073946f0dSDavid Hildenbrand if (saturated == (128 / TBITS)) { \ 16173946f0dSDavid Hildenbrand env->cc_op = 3; \ 16273946f0dSDavid Hildenbrand } else if (saturated) { \ 16373946f0dSDavid Hildenbrand env->cc_op = 1; \ 16473946f0dSDavid Hildenbrand } else { \ 16573946f0dSDavid Hildenbrand env->cc_op = 0; \ 16673946f0dSDavid Hildenbrand } \ 16773946f0dSDavid Hildenbrand } 16873946f0dSDavid Hildenbrand DEF_VPKLS(64, 32) 16973946f0dSDavid Hildenbrand DEF_VPKLS(32, 16) 17073946f0dSDavid Hildenbrand DEF_VPKLS(16, 8) 1717aaf844dSDavid Hildenbrand 1727aaf844dSDavid Hildenbrand void HELPER(gvec_vperm)(void *v1, const void *v2, const void *v3, 1737aaf844dSDavid Hildenbrand const void *v4, uint32_t desc) 1747aaf844dSDavid Hildenbrand { 1757aaf844dSDavid Hildenbrand S390Vector tmp; 1767aaf844dSDavid Hildenbrand int i; 1777aaf844dSDavid Hildenbrand 1787aaf844dSDavid Hildenbrand for (i = 0; i < 16; i++) { 1797aaf844dSDavid Hildenbrand const uint8_t selector = s390_vec_read_element8(v4, i) & 0x1f; 1807aaf844dSDavid Hildenbrand uint8_t byte; 1817aaf844dSDavid Hildenbrand 1827aaf844dSDavid Hildenbrand if (selector < 16) { 1837aaf844dSDavid Hildenbrand byte = s390_vec_read_element8(v2, selector); 1847aaf844dSDavid Hildenbrand } else { 1857aaf844dSDavid Hildenbrand byte = s390_vec_read_element8(v3, selector - 16); 1867aaf844dSDavid Hildenbrand } 1877aaf844dSDavid Hildenbrand s390_vec_write_element8(&tmp, i, byte); 1887aaf844dSDavid Hildenbrand } 1897aaf844dSDavid Hildenbrand *(S390Vector *)v1 = tmp; 1907aaf844dSDavid Hildenbrand } 1910e0a5b49SDavid Hildenbrand 1920e0a5b49SDavid Hildenbrand void HELPER(vstl)(CPUS390XState *env, const void *v1, uint64_t addr, 1930e0a5b49SDavid Hildenbrand uint64_t bytes) 1940e0a5b49SDavid Hildenbrand { 1950e0a5b49SDavid Hildenbrand /* Probe write access before actually modifying memory */ 1960e0a5b49SDavid Hildenbrand probe_write_access(env, addr, bytes, GETPC()); 1970e0a5b49SDavid Hildenbrand 1980e0a5b49SDavid Hildenbrand if (likely(bytes >= 16)) { 1990e0a5b49SDavid Hildenbrand cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 0), GETPC()); 2000e0a5b49SDavid Hildenbrand addr = wrap_address(env, addr + 8); 2010e0a5b49SDavid Hildenbrand cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 1), GETPC()); 2020e0a5b49SDavid Hildenbrand } else { 2030e0a5b49SDavid Hildenbrand S390Vector tmp = {}; 2040e0a5b49SDavid Hildenbrand int i; 2050e0a5b49SDavid Hildenbrand 2060e0a5b49SDavid Hildenbrand for (i = 0; i < bytes; i++) { 2070e0a5b49SDavid Hildenbrand uint8_t byte = s390_vec_read_element8(v1, i); 2080e0a5b49SDavid Hildenbrand 2090e0a5b49SDavid Hildenbrand cpu_stb_data_ra(env, addr, byte, GETPC()); 2100e0a5b49SDavid Hildenbrand addr = wrap_address(env, addr + 1); 2110e0a5b49SDavid Hildenbrand } 2120e0a5b49SDavid Hildenbrand *(S390Vector *)v1 = tmp; 2130e0a5b49SDavid Hildenbrand } 2140e0a5b49SDavid Hildenbrand } 215