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
HELPER(gvec_vbperm)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
HELPER(vll)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
HELPER(gvec_vperm)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
HELPER(vstl)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, MIN(bytes, 16), 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 int i;
204
205 for (i = 0; i < bytes; i++) {
206 uint8_t byte = s390_vec_read_element8(v1, i);
207
208 cpu_stb_data_ra(env, addr, byte, GETPC());
209 addr = wrap_address(env, addr + 1);
210 }
211 }
212 }
213