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