1 /* 2 * QEMU TCG support -- s390x vector support instructions 3 * 4 * Copyright (C) 2019 Red Hat Inc 5 * 6 * Authors: 7 * David Hildenbrand <david@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 */ 12 #include "qemu/osdep.h" 13 #include "cpu.h" 14 #include "s390x-internal.h" 15 #include "vec.h" 16 #include "tcg/tcg.h" 17 #include "tcg/tcg-gvec-desc.h" 18 #include "exec/helper-proto.h" 19 #include "exec/cpu_ldst.h" 20 #include "exec/exec-all.h" 21 22 void HELPER(gvec_vbperm)(void *v1, const void *v2, const void *v3, 23 uint32_t desc) 24 { 25 S390Vector tmp = {}; 26 uint16_t result = 0; 27 int i; 28 29 for (i = 0; i < 16; i++) { 30 const uint8_t bit_nr = s390_vec_read_element8(v3, i); 31 uint16_t bit; 32 33 if (bit_nr >= 128) { 34 continue; 35 } 36 bit = (s390_vec_read_element8(v2, bit_nr / 8) 37 >> (7 - (bit_nr % 8))) & 1; 38 result |= (bit << (15 - i)); 39 } 40 s390_vec_write_element16(&tmp, 3, result); 41 *(S390Vector *)v1 = tmp; 42 } 43 44 void HELPER(vll)(CPUS390XState *env, void *v1, uint64_t addr, uint64_t bytes) 45 { 46 if (likely(bytes >= 16)) { 47 uint64_t t0, t1; 48 49 t0 = cpu_ldq_data_ra(env, addr, GETPC()); 50 addr = wrap_address(env, addr + 8); 51 t1 = cpu_ldq_data_ra(env, addr, GETPC()); 52 s390_vec_write_element64(v1, 0, t0); 53 s390_vec_write_element64(v1, 1, t1); 54 } else { 55 S390Vector tmp = {}; 56 int i; 57 58 for (i = 0; i < bytes; i++) { 59 uint8_t byte = cpu_ldub_data_ra(env, addr, GETPC()); 60 61 s390_vec_write_element8(&tmp, i, byte); 62 addr = wrap_address(env, addr + 1); 63 } 64 *(S390Vector *)v1 = tmp; 65 } 66 } 67 68 #define DEF_VPK_HFN(BITS, TBITS) \ 69 typedef uint##TBITS##_t (*vpk##BITS##_fn)(uint##BITS##_t, int *); \ 70 static int vpk##BITS##_hfn(S390Vector *v1, const S390Vector *v2, \ 71 const S390Vector *v3, vpk##BITS##_fn fn) \ 72 { \ 73 int i, saturated = 0; \ 74 S390Vector tmp; \ 75 \ 76 for (i = 0; i < (128 / TBITS); i++) { \ 77 uint##BITS##_t src; \ 78 \ 79 if (i < (128 / BITS)) { \ 80 src = s390_vec_read_element##BITS(v2, i); \ 81 } else { \ 82 src = s390_vec_read_element##BITS(v3, i - (128 / BITS)); \ 83 } \ 84 s390_vec_write_element##TBITS(&tmp, i, fn(src, &saturated)); \ 85 } \ 86 *v1 = tmp; \ 87 return saturated; \ 88 } 89 DEF_VPK_HFN(64, 32) 90 DEF_VPK_HFN(32, 16) 91 DEF_VPK_HFN(16, 8) 92 93 #define DEF_VPK(BITS, TBITS) \ 94 static uint##TBITS##_t vpk##BITS##e(uint##BITS##_t src, int *saturated) \ 95 { \ 96 return src; \ 97 } \ 98 void HELPER(gvec_vpk##BITS)(void *v1, const void *v2, const void *v3, \ 99 uint32_t desc) \ 100 { \ 101 vpk##BITS##_hfn(v1, v2, v3, vpk##BITS##e); \ 102 } 103 DEF_VPK(64, 32) 104 DEF_VPK(32, 16) 105 DEF_VPK(16, 8) 106 107 #define DEF_VPKS(BITS, TBITS) \ 108 static uint##TBITS##_t vpks##BITS##e(uint##BITS##_t src, int *saturated) \ 109 { \ 110 if ((int##BITS##_t)src > INT##TBITS##_MAX) { \ 111 (*saturated)++; \ 112 return INT##TBITS##_MAX; \ 113 } else if ((int##BITS##_t)src < INT##TBITS##_MIN) { \ 114 (*saturated)++; \ 115 return INT##TBITS##_MIN; \ 116 } \ 117 return src; \ 118 } \ 119 void HELPER(gvec_vpks##BITS)(void *v1, const void *v2, const void *v3, \ 120 uint32_t desc) \ 121 { \ 122 vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e); \ 123 } \ 124 void HELPER(gvec_vpks_cc##BITS)(void *v1, const void *v2, const void *v3, \ 125 CPUS390XState *env, uint32_t desc) \ 126 { \ 127 int saturated = vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e); \ 128 \ 129 if (saturated == (128 / TBITS)) { \ 130 env->cc_op = 3; \ 131 } else if (saturated) { \ 132 env->cc_op = 1; \ 133 } else { \ 134 env->cc_op = 0; \ 135 } \ 136 } 137 DEF_VPKS(64, 32) 138 DEF_VPKS(32, 16) 139 DEF_VPKS(16, 8) 140 141 #define DEF_VPKLS(BITS, TBITS) \ 142 static uint##TBITS##_t vpkls##BITS##e(uint##BITS##_t src, int *saturated) \ 143 { \ 144 if (src > UINT##TBITS##_MAX) { \ 145 (*saturated)++; \ 146 return UINT##TBITS##_MAX; \ 147 } \ 148 return src; \ 149 } \ 150 void HELPER(gvec_vpkls##BITS)(void *v1, const void *v2, const void *v3, \ 151 uint32_t desc) \ 152 { \ 153 vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e); \ 154 } \ 155 void HELPER(gvec_vpkls_cc##BITS)(void *v1, const void *v2, const void *v3, \ 156 CPUS390XState *env, uint32_t desc) \ 157 { \ 158 int saturated = vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e); \ 159 \ 160 if (saturated == (128 / TBITS)) { \ 161 env->cc_op = 3; \ 162 } else if (saturated) { \ 163 env->cc_op = 1; \ 164 } else { \ 165 env->cc_op = 0; \ 166 } \ 167 } 168 DEF_VPKLS(64, 32) 169 DEF_VPKLS(32, 16) 170 DEF_VPKLS(16, 8) 171 172 void HELPER(gvec_vperm)(void *v1, const void *v2, const void *v3, 173 const void *v4, uint32_t desc) 174 { 175 S390Vector tmp; 176 int i; 177 178 for (i = 0; i < 16; i++) { 179 const uint8_t selector = s390_vec_read_element8(v4, i) & 0x1f; 180 uint8_t byte; 181 182 if (selector < 16) { 183 byte = s390_vec_read_element8(v2, selector); 184 } else { 185 byte = s390_vec_read_element8(v3, selector - 16); 186 } 187 s390_vec_write_element8(&tmp, i, byte); 188 } 189 *(S390Vector *)v1 = tmp; 190 } 191 192 void HELPER(vstl)(CPUS390XState *env, const void *v1, uint64_t addr, 193 uint64_t bytes) 194 { 195 /* Probe write access before actually modifying memory */ 196 probe_write_access(env, addr, bytes, GETPC()); 197 198 if (likely(bytes >= 16)) { 199 cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 0), GETPC()); 200 addr = wrap_address(env, addr + 8); 201 cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 1), GETPC()); 202 } else { 203 S390Vector tmp = {}; 204 int i; 205 206 for (i = 0; i < bytes; i++) { 207 uint8_t byte = s390_vec_read_element8(v1, i); 208 209 cpu_stb_data_ra(env, addr, byte, GETPC()); 210 addr = wrap_address(env, addr + 1); 211 } 212 *(S390Vector *)v1 = tmp; 213 } 214 } 215