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
HELPER(gvec_vbperm)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
HELPER(vll)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
HELPER(gvec_vperm)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
HELPER(vstl)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