master
c 223 lines 10.2 KB
Raw
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-common.h"
20 #include "accel/tcg/cpu-mmu-index.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 const int mmu_idx = cpu_mmu_index(env_cpu(env), false);
47 const uintptr_t ra = GETPC();
48 MemOpIdx oi;
49
50 if (likely(bytes >= 16)) {
51 uint64_t t0, t1;
52
53 oi = make_memop_idx(MO_BE | MO_64 | MO_UNALN, mmu_idx);
54 t0 = cpu_ldq_mmu(env, addr, oi, ra);
55 addr = wrap_address(env, addr + 8);
56 t1 = cpu_ldq_mmu(env, addr, oi, ra);
57 s390_vec_write_element64(v1, 0, t0);
58 s390_vec_write_element64(v1, 1, t1);
59 } else {
60 S390Vector tmp = {};
61
62 oi = make_memop_idx(MO_8, mmu_idx);
63 for (int i = 0; i < bytes; i++) {
64 uint8_t byte = cpu_ldb_mmu(env, addr, oi, ra);
65
66
67 s390_vec_write_element8(&tmp, i, byte);
68 addr = wrap_address(env, addr + 1);
69 }
70 *(S390Vector *)v1 = tmp;
71 }
72 }
73
74 #define DEF_VPK_HFN(BITS, TBITS) \
75 typedef uint##TBITS##_t (*vpk##BITS##_fn)(uint##BITS##_t, int *); \
76 static int vpk##BITS##_hfn(S390Vector *v1, const S390Vector *v2, \
77 const S390Vector *v3, vpk##BITS##_fn fn) \
78 { \
79 int i, saturated = 0; \
80 S390Vector tmp; \
81 \
82 for (i = 0; i < (128 / TBITS); i++) { \
83 uint##BITS##_t src; \
84 \
85 if (i < (128 / BITS)) { \
86 src = s390_vec_read_element##BITS(v2, i); \
87 } else { \
88 src = s390_vec_read_element##BITS(v3, i - (128 / BITS)); \
89 } \
90 s390_vec_write_element##TBITS(&tmp, i, fn(src, &saturated)); \
91 } \
92 *v1 = tmp; \
93 return saturated; \
94 }
95 DEF_VPK_HFN(64, 32)
96 DEF_VPK_HFN(32, 16)
97 DEF_VPK_HFN(16, 8)
98
99 #define DEF_VPK(BITS, TBITS) \
100 static uint##TBITS##_t vpk##BITS##e(uint##BITS##_t src, int *saturated) \
101 { \
102 return src; \
103 } \
104 void HELPER(gvec_vpk##BITS)(void *v1, const void *v2, const void *v3, \
105 uint32_t desc) \
106 { \
107 vpk##BITS##_hfn(v1, v2, v3, vpk##BITS##e); \
108 }
109 DEF_VPK(64, 32)
110 DEF_VPK(32, 16)
111 DEF_VPK(16, 8)
112
113 #define DEF_VPKS(BITS, TBITS) \
114 static uint##TBITS##_t vpks##BITS##e(uint##BITS##_t src, int *saturated) \
115 { \
116 if ((int##BITS##_t)src > INT##TBITS##_MAX) { \
117 (*saturated)++; \
118 return INT##TBITS##_MAX; \
119 } else if ((int##BITS##_t)src < INT##TBITS##_MIN) { \
120 (*saturated)++; \
121 return INT##TBITS##_MIN; \
122 } \
123 return src; \
124 } \
125 void HELPER(gvec_vpks##BITS)(void *v1, const void *v2, const void *v3, \
126 uint32_t desc) \
127 { \
128 vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e); \
129 } \
130 void HELPER(gvec_vpks_cc##BITS)(void *v1, const void *v2, const void *v3, \
131 CPUS390XState *env, uint32_t desc) \
132 { \
133 int saturated = vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e); \
134 \
135 if (saturated == (128 / TBITS)) { \
136 env->cc_op = 3; \
137 } else if (saturated) { \
138 env->cc_op = 1; \
139 } else { \
140 env->cc_op = 0; \
141 } \
142 }
143 DEF_VPKS(64, 32)
144 DEF_VPKS(32, 16)
145 DEF_VPKS(16, 8)
146
147 #define DEF_VPKLS(BITS, TBITS) \
148 static uint##TBITS##_t vpkls##BITS##e(uint##BITS##_t src, int *saturated) \
149 { \
150 if (src > UINT##TBITS##_MAX) { \
151 (*saturated)++; \
152 return UINT##TBITS##_MAX; \
153 } \
154 return src; \
155 } \
156 void HELPER(gvec_vpkls##BITS)(void *v1, const void *v2, const void *v3, \
157 uint32_t desc) \
158 { \
159 vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e); \
160 } \
161 void HELPER(gvec_vpkls_cc##BITS)(void *v1, const void *v2, const void *v3, \
162 CPUS390XState *env, uint32_t desc) \
163 { \
164 int saturated = vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e); \
165 \
166 if (saturated == (128 / TBITS)) { \
167 env->cc_op = 3; \
168 } else if (saturated) { \
169 env->cc_op = 1; \
170 } else { \
171 env->cc_op = 0; \
172 } \
173 }
174 DEF_VPKLS(64, 32)
175 DEF_VPKLS(32, 16)
176 DEF_VPKLS(16, 8)
177
178 void HELPER(gvec_vperm)(void *v1, const void *v2, const void *v3,
179 const void *v4, uint32_t desc)
180 {
181 S390Vector tmp;
182 int i;
183
184 for (i = 0; i < 16; i++) {
185 const uint8_t selector = s390_vec_read_element8(v4, i) & 0x1f;
186 uint8_t byte;
187
188 if (selector < 16) {
189 byte = s390_vec_read_element8(v2, selector);
190 } else {
191 byte = s390_vec_read_element8(v3, selector - 16);
192 }
193 s390_vec_write_element8(&tmp, i, byte);
194 }
195 *(S390Vector *)v1 = tmp;
196 }
197
198 void HELPER(vstl)(CPUS390XState *env, const void *v1, uint64_t addr,
199 uint64_t bytes)
200 {
201 const int mmu_idx = cpu_mmu_index(env_cpu(env), false);
202 const uintptr_t ra = GETPC();
203 MemOpIdx oi;
204
205 /* Probe write access before actually modifying memory */
206 probe_write_access(env, addr, MIN(bytes, 16), GETPC());
207
208 if (likely(bytes >= 16)) {
209 oi = make_memop_idx(MO_BE | MO_64 | MO_UNALN, mmu_idx);
210 cpu_stq_mmu(env, addr, s390_vec_read_element64(v1, 0), oi, ra);
211 addr = wrap_address(env, addr + 8);
212 cpu_stq_mmu(env, addr, s390_vec_read_element64(v1, 1), oi, ra);
213 } else {
214 oi = make_memop_idx(MO_8, mmu_idx);
215
216 for (int i = 0; i < bytes; i++) {
217 uint8_t byte = s390_vec_read_element8(v1, i);
218
219 cpu_stb_mmu(env, addr, byte, oi, ra);
220 addr = wrap_address(env, addr + 1);
221 }
222 }
223 }