Serenity Operating System
1/*
2 * Copyright (c) 2022, Leon Albrecht <leon.a@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include "SoftVPU.h"
8#include "SoftCPU.h"
9#include <AK/SIMDMath.h>
10
11namespace UserspaceEmulator {
12
13void SoftVPU::PREFETCHTNTA(X86::Instruction const&) { TODO(); }
14void SoftVPU::PREFETCHT0(X86::Instruction const&) { TODO(); }
15void SoftVPU::PREFETCHT1(X86::Instruction const&) { TODO(); }
16void SoftVPU::PREFETCHT2(X86::Instruction const&) { TODO(); }
17
18void SoftVPU::LDMXCSR(X86::Instruction const& insn)
19{
20 // FIXME: Shadows
21 m_mxcsr.mxcsr = insn.modrm().read32(m_cpu, insn).value();
22
23 // #GP - General Protection Fault
24 VERIFY((m_mxcsr.mxcsr & 0xFFFF'0000) == 0);
25
26 // Just let the host's SSE (or if not available x87) handle the rounding for us
27 // We do not want to accidentally raise an FP-Exception on the host, so we
28 // mask all exceptions
29#ifdef __SSE__
30 AK::MXCSR temp = m_mxcsr;
31 temp.invalid_operation_mask = 1;
32 temp.denormal_operation_mask = 1;
33 temp.divide_by_zero_mask = 1;
34 temp.overflow_mask = 1;
35 temp.underflow_mask = 1;
36 temp.precision_mask = 1;
37 AK::set_mxcsr(temp);
38#else
39 // FIXME: This will mess with x87-land, because it uses the same trick, and
40 // Does not know of us doing this
41 AK::X87ControlWord cw { 0x037F };
42 cw.rounding_control = m_mxcsr.rounding_control;
43 AK::set_cw_x87(cw);
44#endif
45}
46void SoftVPU::STMXCSR(X86::Instruction const& insn)
47{
48 // FIXME: Shadows
49 insn.modrm().write32(m_cpu, insn, ValueWithShadow<u32>::create_initialized(m_mxcsr.mxcsr));
50}
51
52void SoftVPU::MOVUPS_xmm1_xmm2m128(X86::Instruction const& insn)
53{
54 u8 xmm1 = insn.modrm().reg();
55 if (insn.modrm().is_register()) {
56 m_xmm[xmm1] = m_xmm[insn.modrm().rm()];
57 } else {
58 // FIXME: Shadows
59 m_xmm[xmm1].ps = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
60 }
61}
62void SoftVPU::MOVSS_xmm1_xmm2m32(X86::Instruction const& insn)
63{
64 u8 xmm1 = insn.modrm().reg();
65 if (insn.modrm().is_register()) {
66 m_xmm[xmm1].ps[0] = m_xmm[insn.modrm().rm()].ps[0];
67 } else {
68 // FIXME: Shadows
69 m_xmm[xmm1].ps[0] = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
70 }
71}
72void SoftVPU::MOVUPS_xmm1m128_xmm2(X86::Instruction const& insn)
73{
74 u8 xmm2 = insn.modrm().reg();
75 if (insn.modrm().is_register()) {
76 m_xmm[insn.modrm().rm()] = m_xmm[xmm2];
77 } else {
78 // FIXME: Shadows
79 u128 temp = bit_cast<u128>(m_xmm[xmm2]);
80 insn.modrm().write128(m_cpu, insn, ValueWithShadow<u128>::create_initialized(temp));
81 }
82}
83void SoftVPU::MOVSS_xmm1m32_xmm2(X86::Instruction const& insn)
84{
85 u8 xmm2 = insn.modrm().reg();
86 if (insn.modrm().is_register()) {
87 m_xmm[insn.modrm().rm()].ps[0] = m_xmm[xmm2].ps[0];
88 } else {
89 // FIXME: Shadows
90 u32 temp = bit_cast<u32>(m_xmm[xmm2].ps[0]);
91 insn.modrm().write32(m_cpu, insn, ValueWithShadow<u32>::create_initialized(temp));
92 }
93}
94void SoftVPU::MOVLPS_xmm1_xmm2m64(X86::Instruction const& insn)
95{
96 u8 xmm1 = insn.modrm().reg();
97 if (insn.modrm().is_register()) {
98 // Note: MOVHLPS
99 m_xmm[xmm1].puqw[0] = m_xmm[insn.modrm().rm()].puqw[1];
100 } else {
101 // FIXME: Shadows
102 // Note: Technically we are transferring two packed floats not a quad word
103 m_xmm[xmm1].puqw[0] = insn.modrm().read64(m_cpu, insn).value();
104 }
105}
106void SoftVPU::MOVLPS_m64_xmm2(X86::Instruction const& insn)
107{
108 u8 xmm2 = insn.modrm().reg();
109 // FIXME: This might not hold true for SSE2 or later
110 VERIFY(!insn.modrm().is_register());
111 // Note: Technically we are transferring two packed floats not a quad word
112 insn.modrm().write64(m_cpu, insn, ValueWithShadow<u64>::create_initialized(m_xmm[xmm2].puqw[0]));
113}
114
115void SoftVPU::UNPCKLPS_xmm1_xmm2m128(X86::Instruction const& insn)
116{
117 f32x4& xmm1 = m_xmm[insn.modrm().reg()].ps;
118 f32x4 xmm2m128;
119
120 if (insn.modrm().is_register()) {
121 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
122 } else {
123 // FIXME: Shadows
124 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
125 }
126 f32x4 dest;
127 if (insn.modrm().is_register()) {
128 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
129 } else {
130 // FIXME: Shadows
131 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
132 }
133
134 dest[0] = xmm1[0];
135 dest[1] = xmm2m128[0];
136 dest[2] = xmm1[1];
137 dest[3] = xmm2m128[1];
138
139 m_xmm[insn.modrm().reg()].ps = dest;
140}
141void SoftVPU::UNPCKHPS_xmm1_xmm2m128(X86::Instruction const& insn)
142{
143 f32x4 xmm1 = m_xmm[insn.modrm().reg()].ps;
144 f32x4 xmm2m128;
145
146 if (insn.modrm().is_register()) {
147 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
148 } else {
149 // FIXME: Shadows
150 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
151 }
152 f32x4 dest;
153 dest[0] = xmm1[2];
154 dest[1] = xmm2m128[2];
155 dest[2] = xmm1[3];
156 dest[3] = xmm2m128[3];
157
158 m_xmm[insn.modrm().reg()].ps = dest;
159}
160
161void SoftVPU::MOVHPS_xmm1_xmm2m64(X86::Instruction const& insn)
162{
163 u8 xmm1 = insn.modrm().reg();
164 if (insn.modrm().is_register()) {
165 // Note: MOVLHPS
166 m_xmm[xmm1].puqw[1] = m_xmm[insn.modrm().rm()].puqw[0];
167 } else {
168 // FIXME: Shadows
169 // Note: Technically we are transferring two packed floats not a quad word
170 m_xmm[xmm1].puqw[1] = insn.modrm().read64(m_cpu, insn).value();
171 }
172}
173void SoftVPU::MOVHPS_m64_xmm2(X86::Instruction const& insn)
174{
175 u8 xmm1 = insn.modrm().reg();
176 VERIFY(!insn.modrm().is_register());
177 // Note: Technically we are transferring two packed floats not a quad word
178 insn.modrm().write64(m_cpu, insn, ValueWithShadow<u64>::create_initialized(m_xmm[xmm1].puqw[1]));
179}
180void SoftVPU::MOVAPS_xmm1_xmm2m128(X86::Instruction const& insn)
181{
182 u8 xmm1 = insn.modrm().reg();
183 if (insn.modrm().is_register()) {
184 m_xmm[xmm1] = m_xmm[insn.modrm().rm()];
185 } else {
186 // FIXME: Alignment-check 16
187 auto temp = insn.modrm().read128(m_cpu, insn);
188 m_xmm[xmm1].ps = bit_cast<f32x4>(temp.value());
189 }
190}
191void SoftVPU::MOVAPS_xmm1m128_xmm2(X86::Instruction const& insn)
192{
193 u8 xmm2 = insn.modrm().reg();
194 if (insn.modrm().is_register()) {
195 m_xmm[insn.modrm().rm()] = m_xmm[xmm2];
196 } else {
197 // FIXME: Alignment-check 16
198 u128 temp = bit_cast<u128>(m_xmm[xmm2]);
199 insn.modrm().write128(m_cpu, insn, ValueWithShadow<u128>::create_initialized(temp));
200 }
201}
202
203void SoftVPU::CVTPI2PS_xmm1_mm2m64(X86::Instruction const& insn)
204{
205 // FIXME: Raise Precision
206 // FIXME: Honor Rounding control
207 u8 xmm1 = insn.modrm().reg();
208 if (insn.modrm().is_register()) {
209 i32x2 mm = m_cpu.mmx_get(insn.modrm().rm()).v32;
210 m_xmm[xmm1].ps[0] = mm[0];
211 m_xmm[xmm1].ps[1] = mm[1];
212 } else {
213 // FIXME: Shadows
214 i32x2 m64 = bit_cast<i32x2>(insn.modrm().read64(m_cpu, insn).value());
215 m_xmm[xmm1].ps[0] = m64[0];
216 m_xmm[xmm1].ps[1] = m64[1];
217 }
218}
219void SoftVPU::CVTSI2SS_xmm1_rm32(X86::Instruction const& insn)
220{
221 // FIXME: Raise Precision
222 // FIXME: Shadows
223 // FIXME: Honor Rounding Control
224 m_xmm[insn.modrm().reg()].ps[0] = (i32)insn.modrm().read32(m_cpu, insn).value();
225}
226
227void SoftVPU::MOVNTPS_xmm1m128_xmm2(X86::Instruction const&) { TODO(); }
228
229void SoftVPU::CVTTPS2PI_mm1_xmm2m64(X86::Instruction const&) { TODO(); }
230void SoftVPU::CVTTSS2SI_r32_xmm2m32(X86::Instruction const& insn)
231{
232 // FIXME: Raise Invalid, Precision
233 float value;
234 if (insn.modrm().is_register())
235 value = m_xmm[insn.modrm().rm()].ps[0];
236 else
237 value = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
238
239 m_cpu.gpr32(insn.reg32()) = ValueWithShadow<u32>::create_initialized((u32)(i32)truncf(value));
240}
241void SoftVPU::CVTPS2PI_xmm1_mm2m64(X86::Instruction const&) { TODO(); }
242void SoftVPU::CVTSS2SI_r32_xmm2m32(X86::Instruction const& insn)
243{
244 // FIXME: Raise Invalid, Precision
245 insn.modrm().write32(m_cpu, insn,
246 ValueWithShadow<u32>::create_initialized(static_cast<i32>(m_xmm[insn.modrm().reg()].ps[0])));
247}
248
249void SoftVPU::UCOMISS_xmm1_xmm2m32(X86::Instruction const& insn)
250{
251 float xmm1 = m_xmm[insn.modrm().reg()].ps[0];
252 float xmm2m32;
253 if (insn.modrm().is_register())
254 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0];
255 else
256 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
257 // FIXME: Raise Invalid on SNaN
258 if (isnan(xmm1) || isnan(xmm2m32)) {
259 m_cpu.set_zf(true);
260 m_cpu.set_pf(true);
261 m_cpu.set_cf(true);
262 } else {
263 m_cpu.set_zf(xmm1 == xmm2m32);
264 m_cpu.set_pf(false);
265 m_cpu.set_cf(xmm1 < xmm2m32);
266 }
267 m_cpu.set_of(false);
268 m_cpu.set_af(false);
269 m_cpu.set_sf(false);
270}
271void SoftVPU::COMISS_xmm1_xmm2m32(X86::Instruction const& insn)
272{
273 // FIXME: Raise on QNaN
274 UCOMISS_xmm1_xmm2m32(insn);
275}
276
277void SoftVPU::MOVMSKPS_reg_xmm(X86::Instruction const& insn)
278{
279 VERIFY(insn.modrm().is_register());
280 u8 mask = 0;
281 f32x4 xmm = m_xmm[insn.modrm().rm()].ps;
282 mask |= signbit(xmm[0]) << 0;
283 mask |= signbit(xmm[1]) << 1;
284 mask |= signbit(xmm[2]) << 2;
285 mask |= signbit(xmm[3]) << 3;
286
287 m_cpu.gpr32(insn.reg32()) = ValueWithShadow<u32>::create_initialized(mask);
288}
289
290void SoftVPU::SQRTPS_xmm1_xmm2m128(X86::Instruction const& insn)
291{
292 // FIXME: Raise Invalid, Precision, Denormal
293 f32x4 xmm2m128;
294
295 if (insn.modrm().is_register()) {
296 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
297 } else {
298 // FIXME: Shadows
299 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
300 }
301
302 m_xmm[insn.modrm().reg()].ps = sqrt(xmm2m128);
303}
304void SoftVPU::SQRTSS_xmm1_xmm2m32(X86::Instruction const& insn)
305{
306 // FIXME: Raise Invalid, Precision, Denormal
307 float xmm2m32;
308
309 if (insn.modrm().is_register()) {
310 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0];
311 } else {
312 // FIXME: Shadows
313 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
314 }
315
316 m_xmm[insn.modrm().reg()].ps[0] = AK::sqrt(xmm2m32);
317}
318void SoftVPU::RSQRTPS_xmm1_xmm2m128(X86::Instruction const& insn)
319{
320 f32x4 xmm2m128;
321 if (insn.modrm().is_register()) {
322 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
323 } else {
324 // FIXME: Shadows
325 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
326 }
327
328 m_xmm[insn.modrm().reg()].ps = rsqrt(xmm2m128);
329}
330void SoftVPU::RSQRTSS_xmm1_xmm2m32(X86::Instruction const& insn)
331{
332 float xmm2m32;
333 if (insn.modrm().is_register()) {
334 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0];
335 } else {
336 // FIXME: Shadows
337 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
338 }
339
340 m_xmm[insn.modrm().reg()].ps[0] = AK::rsqrt(xmm2m32);
341}
342
343void SoftVPU::RCPPS_xmm1_xmm2m128(X86::Instruction const& insn)
344{
345 f32x4 xmm2m128;
346 if (insn.modrm().is_register()) {
347 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
348 } else {
349 // FIXME: Shadows
350 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
351 }
352
353 m_xmm[insn.modrm().reg()].ps = 1.f / xmm2m128;
354}
355void SoftVPU::RCPSS_xmm1_xmm2m32(X86::Instruction const& insn)
356{
357 float xmm2m32;
358 if (insn.modrm().is_register()) {
359 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0];
360 } else {
361 // FIXME: Shadows
362 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
363 }
364
365 m_xmm[insn.modrm().reg()].ps[0] = 1.f / xmm2m32;
366}
367
368void SoftVPU::ANDPS_xmm1_xmm2m128(X86::Instruction const& insn)
369{
370 u32x4 xmm2m128;
371 if (insn.modrm().is_register()) {
372 xmm2m128 = m_xmm[insn.modrm().rm()].pudw;
373 } else {
374 // FIXME: Shadows
375 xmm2m128 = bit_cast<u32x4>(insn.modrm().read128(m_cpu, insn).value());
376 }
377
378 m_xmm[insn.modrm().reg()].pudw &= xmm2m128;
379}
380void SoftVPU::ANDNPS_xmm1_xmm2m128(X86::Instruction const& insn)
381{
382 u32x4 xmm2m128;
383 if (insn.modrm().is_register()) {
384 xmm2m128 = m_xmm[insn.modrm().rm()].pudw;
385 } else {
386 // FIXME: Shadows
387 xmm2m128 = bit_cast<u32x4>(insn.modrm().read128(m_cpu, insn).value());
388 }
389
390 u32x4& xmm1 = m_xmm[insn.modrm().reg()].pudw;
391 xmm1 = ~xmm1 & xmm2m128;
392}
393void SoftVPU::ORPS_xmm1_xmm2m128(X86::Instruction const& insn)
394{
395 u32x4 xmm2m128;
396 if (insn.modrm().is_register()) {
397 xmm2m128 = m_xmm[insn.modrm().rm()].pudw;
398 } else {
399 // FIXME: Shadows
400 xmm2m128 = bit_cast<u32x4>(insn.modrm().read128(m_cpu, insn).value());
401 }
402
403 m_xmm[insn.modrm().reg()].pudw |= xmm2m128;
404}
405void SoftVPU::XORPS_xmm1_xmm2m128(X86::Instruction const& insn)
406{
407 u32x4 xmm2m128;
408 if (insn.modrm().is_register()) {
409 xmm2m128 = m_xmm[insn.modrm().rm()].pudw;
410 } else {
411 // FIXME: Shadows
412 xmm2m128 = bit_cast<u32x4>(insn.modrm().read128(m_cpu, insn).value());
413 }
414
415 m_xmm[insn.modrm().reg()].pudw ^= xmm2m128;
416}
417
418void SoftVPU::ADDPS_xmm1_xmm2m128(X86::Instruction const& insn)
419{
420 // Raise Overflow, Underflow, Invalid, Precision, Denormal
421 f32x4 xmm2m128;
422 if (insn.modrm().is_register()) {
423 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
424 } else {
425 // FIXME: Shadows
426 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
427 }
428
429 m_xmm[insn.modrm().reg()].ps += xmm2m128;
430}
431void SoftVPU::ADDSS_xmm1_xmm2m32(X86::Instruction const& insn)
432{
433 // Raise Overflow, Underflow, Invalid, Precision, Denormal
434 float xmm2m32;
435 if (insn.modrm().is_register()) {
436 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0];
437 } else {
438 // FIXME: Shadows
439 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
440 }
441
442 m_xmm[insn.modrm().reg()].ps[0] += xmm2m32;
443}
444
445void SoftVPU::MULPS_xmm1_xmm2m128(X86::Instruction const& insn)
446{
447 // Raise Overflow, Underflow, Invalid, Precision, Denormal
448 f32x4 xmm2m128;
449 if (insn.modrm().is_register()) {
450 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
451 } else {
452 // FIXME: Shadows
453 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
454 }
455
456 m_xmm[insn.modrm().reg()].ps *= xmm2m128;
457}
458void SoftVPU::MULSS_xmm1_xmm2m32(X86::Instruction const& insn)
459{
460 // Raise Overflow, Underflow, Invalid, Precision, Denormal
461 float xmm1 = m_xmm[insn.modrm().reg()].ps[0];
462 float xmm2m32;
463
464 if (insn.modrm().is_register()) {
465 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0];
466 } else {
467 // FIXME: Shadows
468 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
469 }
470 xmm1 *= xmm2m32;
471
472 m_xmm[insn.modrm().reg()].ps[0] *= xmm1;
473}
474
475void SoftVPU::SUBPS_xmm1_xmm2m128(X86::Instruction const& insn)
476{
477 // Raise Overflow, Underflow, Invalid, Precision, Denormal
478 f32x4 xmm2m128;
479
480 if (insn.modrm().is_register()) {
481 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
482 } else {
483 // FIXME: Shadows
484 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
485 }
486
487 m_xmm[insn.modrm().reg()].ps -= xmm2m128;
488}
489void SoftVPU::SUBSS_xmm1_xmm2m32(X86::Instruction const& insn)
490{
491 // Raise Overflow, Underflow, Invalid, Precision, Denormal
492 float xmm2m32;
493
494 if (insn.modrm().is_register()) {
495 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0];
496 } else {
497 // FIXME: Shadows
498 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
499 }
500
501 m_xmm[insn.modrm().reg()].ps[0] -= xmm2m32;
502}
503
504void SoftVPU::MINPS_xmm1_xmm2m128(X86::Instruction const& insn)
505{
506 // FIXME: Raise Invalid (including QNaN Source Operand), Denormal
507 f32x4 xmm1 = m_xmm[insn.modrm().reg()].ps;
508 f32x4 xmm2m128;
509
510 if (insn.modrm().is_register()) {
511 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
512 } else {
513 // FIXME: Shadows
514 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
515 }
516
517 for (auto i = 0; i < 4; ++i) {
518 // When only one is NaN or both are 0.0s (of either sign), or
519 // FIXME: xmm2m32 is SNaN
520 // xmm2m32 is returned unchanged
521 if (isnan(xmm1[i]) || isnan(xmm2m128[i]) || xmm1[i] == xmm2m128[i])
522 xmm1[i] = xmm2m128[i];
523 else
524 xmm1[i] = min(xmm1[i], xmm2m128[i]);
525 }
526
527 m_xmm[insn.modrm().reg()].ps = xmm1;
528}
529void SoftVPU::MINSS_xmm1_xmm2m32(X86::Instruction const& insn)
530{
531 // FIXME: Raise Invalid (Including QNaN Source Operand), Denormal
532 float xmm1 = m_xmm[insn.modrm().reg()].ps[0];
533 float xmm2m32;
534
535 if (insn.modrm().is_register()) {
536 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0];
537 } else {
538 // FIXME: Shadows
539 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
540 }
541 // When only one is NaN or both are 0.0s (of either sign), or
542 // FIXME: xmm2m32 is SNaN
543 // xmm2m32 is returned unchanged
544 if (isnan(xmm1) || isnan(xmm2m32) || xmm1 == xmm2m32)
545 xmm1 = xmm2m32;
546 else
547 xmm1 = min(xmm1, xmm2m32);
548
549 m_xmm[insn.modrm().reg()].ps[0] = xmm1;
550}
551
552void SoftVPU::DIVPS_xmm1_xmm2m128(X86::Instruction const& insn)
553{
554 // Raise Overflow, Underflow, Invalid, Divide-by-Zero, Precision, Denormal
555 f32x4 xmm2m128;
556 if (insn.modrm().is_register()) {
557 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
558 } else {
559 // FIXME: Shadows
560 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
561 }
562
563 m_xmm[insn.modrm().reg()].ps /= xmm2m128;
564}
565void SoftVPU::DIVSS_xmm1_xmm2m32(X86::Instruction const& insn)
566{
567 // Raise Overflow, Underflow, Invalid, Divide-by-Zero, Precision, Denormal
568 float xmm2m32;
569 if (insn.modrm().is_register()) {
570 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0];
571 } else {
572 // FIXME: Shadows
573 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
574 }
575
576 m_xmm[insn.modrm().reg()].ps[0] /= xmm2m32;
577}
578
579void SoftVPU::MAXPS_xmm1_xmm2m128(X86::Instruction const& insn)
580{
581 // FIXME: Raise Invalid (including QNaN Source Operand), Denormal
582 f32x4 xmm1 = m_xmm[insn.modrm().reg()].ps;
583 f32x4 xmm2m128;
584
585 if (insn.modrm().is_register()) {
586 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
587 } else {
588 // FIXME: Shadows
589 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
590 }
591
592 for (auto i = 0; i < 4; ++i) {
593 // When only one is NaN or both are 0.0s (of either sign), or
594 // FIXME: xmm2m32 is SNaN
595 // xmm2m32 is returned unchanged
596 if (isnan(xmm1[i]) || isnan(xmm2m128[i]) || xmm1[i] == xmm2m128[i])
597 xmm1[i] = xmm2m128[i];
598 else
599 xmm1[i] = max(xmm1[i], xmm2m128[i]);
600 }
601
602 m_xmm[insn.modrm().reg()].ps = xmm1;
603}
604void SoftVPU::MAXSS_xmm1_xmm2m32(X86::Instruction const& insn)
605{
606 // FIXME: Raise Invalid (Including QNaN Source Operand), Denormal
607 float xmm1 = m_xmm[insn.modrm().reg()].ps[0];
608 float xmm2m32;
609
610 if (insn.modrm().is_register()) {
611 xmm2m32 = m_xmm[insn.modrm().rm()].ps[0];
612 } else {
613 // FIXME: Shadows
614 xmm2m32 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
615 }
616 // When only one is NaN or both are 0.0s (of either sign), or
617 // FIXME: xmm2m32 is SNaN
618 // xmm2m32 is returned unchanged
619 if (isnan(xmm1) || isnan(xmm2m32) || xmm1 == xmm2m32)
620 xmm1 = xmm2m32;
621 else
622 xmm1 = max(xmm1, xmm2m32);
623
624 m_xmm[insn.modrm().reg()].ps[0] = xmm1;
625}
626
627void SoftVPU::PSHUFW_mm1_mm2m64_imm8(X86::Instruction const& insn)
628{
629 MMX src;
630 if (insn.modrm().is_register()) {
631 src = m_cpu.mmx_get(insn.modrm().rm());
632 } else {
633 // FIXME: Shadows
634 src = bit_cast<MMX>(insn.modrm().read64(m_cpu, insn).value());
635 }
636
637 u8 order = insn.imm8();
638 MMX dest;
639
640 dest.v16u[0] = src.v16u[(order >> 0) & 0b11];
641 dest.v16u[1] = src.v16u[(order >> 2) & 0b11];
642 dest.v16u[2] = src.v16u[(order >> 4) & 0b11];
643 dest.v16u[3] = src.v16u[(order >> 6) & 0b11];
644
645 m_cpu.mmx_set(insn.modrm().reg(), dest);
646}
647
648void SoftVPU::CMPPS_xmm1_xmm2m128_imm8(X86::Instruction const& insn)
649{
650 // FIXME: Raise Denormal, Invalid Operation (QNaN dependent on imm8)
651 XMM& xmm1 = m_xmm[insn.modrm().reg()];
652 f32x4 xmm2m128;
653
654 if (insn.modrm().is_register()) {
655 xmm2m128 = m_xmm[insn.modrm().rm()].ps;
656 } else {
657 // FIXME: Shadows
658 xmm2m128 = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
659 }
660 using enum ComparePredicate;
661 switch ((ComparePredicate)insn.imm8()) {
662 case EQ:
663 xmm1.ps = xmm1.ps == xmm2m128;
664 break;
665 case LT:
666 xmm1.ps = xmm1.ps < xmm2m128;
667 break;
668 case LE:
669 xmm1.ps = xmm1.ps <= xmm2m128;
670 break;
671 case UNORD:
672 for (auto i = 0; i < 4; ++i)
673 xmm1.pudw[i] = 0xFFFF'FFFF * (isnan(xmm1.ps[i]) || isnan(xmm2m128[i]));
674 break;
675 case NEQ:
676 xmm1.ps = xmm1.ps != xmm2m128;
677 break;
678 case NLT:
679 xmm1.ps = xmm1.ps >= xmm2m128;
680 break;
681 case NLE:
682 xmm1.ps = xmm1.ps > xmm2m128;
683 break;
684 case ORD:
685 for (auto i = 0; i < 4; ++i)
686 xmm1.pudw[i] = 0xFFFF'FFFF * (!isnan(xmm1.ps[i]) && !isnan(xmm2m128[i]));
687 break;
688 }
689}
690void SoftVPU::CMPSS_xmm1_xmm2m32_imm8(X86::Instruction const& insn)
691{
692 // FIXME: Raise Denormal, Invalid Operation (QNaN dependent on imm8)
693 float xmm1 = m_xmm[insn.modrm().reg()].ps[0];
694 float xmm2m128;
695 bool res;
696
697 if (insn.modrm().is_register()) {
698 xmm2m128 = m_xmm[insn.modrm().rm()].ps[0];
699 } else {
700 // FIXME: Shadows
701 xmm2m128 = bit_cast<float>(insn.modrm().read32(m_cpu, insn).value());
702 }
703 using enum ComparePredicate;
704 switch ((ComparePredicate)insn.imm8()) {
705 case EQ:
706 res = xmm1 == xmm2m128;
707 break;
708 case LT:
709 res = xmm1 < xmm2m128;
710 break;
711 case LE:
712 res = xmm1 <= xmm2m128;
713 break;
714 case UNORD:
715 res = isnan(xmm1) || isnan(xmm2m128);
716 break;
717 case NEQ:
718 res = xmm1 != xmm2m128;
719 break;
720 case NLT:
721 res = xmm1 >= xmm2m128;
722 break;
723 case NLE:
724 res = xmm1 > xmm2m128;
725 break;
726 case ORD:
727 res = !isnan(xmm1) && !isnan(xmm2m128);
728 break;
729 }
730
731 m_xmm[insn.modrm().reg()].pudw[0] = 0xFFFF'FFFF * res;
732}
733
734void SoftVPU::PINSRW_mm1_r32m16_imm8(X86::Instruction const&) { TODO(); }
735void SoftVPU::PINSRW_xmm1_r32m16_imm8(X86::Instruction const&) { TODO(); }
736void SoftVPU::PEXTRW_reg_mm1_imm8(X86::Instruction const&) { TODO(); }
737void SoftVPU::PEXTRW_reg_xmm1_imm8(X86::Instruction const&) { TODO(); }
738
739void SoftVPU::SHUFPS_xmm1_xmm2m128_imm8(X86::Instruction const& insn)
740{
741 f32x4 src;
742 if (insn.modrm().is_register()) {
743 src = m_xmm[insn.modrm().rm()].ps;
744 } else {
745 // FIXME: Shadows
746 src = bit_cast<f32x4>(insn.modrm().read128(m_cpu, insn).value());
747 }
748
749 u8 order = insn.imm8();
750 f32x4 dest;
751 dest[0] = src[(order >> 0) & 0b11];
752 dest[1] = src[(order >> 2) & 0b11];
753 dest[2] = src[(order >> 4) & 0b11];
754 dest[3] = src[(order >> 6) & 0b11];
755
756 m_xmm[insn.modrm().reg()].ps = dest;
757}
758
759void SoftVPU::PMOVMSKB_reg_mm1(X86::Instruction const&) { TODO(); }
760void SoftVPU::PMOVMSKB_reg_xmm1(X86::Instruction const& insn)
761{
762 VERIFY(insn.modrm().is_register());
763 XMM src = m_xmm[insn.modrm().rm()];
764
765 u32 dest = 0;
766 for (int i = 0; i < 16; ++i)
767 dest |= (src.pub[i] >> 7) << i;
768
769 m_cpu.gpr32(insn.reg32()) = ValueWithShadow<u32>::create_initialized(dest);
770}
771
772void SoftVPU::PMINUB_mm1_mm2m64(X86::Instruction const&) { TODO(); }
773void SoftVPU::PMINUB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); }
774
775void SoftVPU::PMAXUB_mm1_mm2m64(X86::Instruction const&) { TODO(); }
776void SoftVPU::PMAXUB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); }
777
778void SoftVPU::PAVGB_mm1_mm2m64(X86::Instruction const&) { TODO(); }
779void SoftVPU::PAVGB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); }
780
781void SoftVPU::PAVGW_mm1_mm2m64(X86::Instruction const&) { TODO(); }
782void SoftVPU::PAVGW_xmm1_xmm2m128(X86::Instruction const&) { TODO(); }
783
784void SoftVPU::PMULHUW_mm1_mm2m64(X86::Instruction const&) { TODO(); }
785void SoftVPU::PMULHUW_xmm1_xmm2m64(X86::Instruction const&) { TODO(); }
786
787void SoftVPU::MOVNTQ_m64_mm1(X86::Instruction const&) { TODO(); }
788
789void SoftVPU::PMINSB_mm1_mm2m64(X86::Instruction const&) { TODO(); }
790void SoftVPU::PMINSB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); }
791
792void SoftVPU::PMAXSB_mm1_mm2m64(X86::Instruction const&) { TODO(); }
793void SoftVPU::PMAXSB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); }
794
795void SoftVPU::PSADBB_mm1_mm2m64(X86::Instruction const&) { TODO(); }
796void SoftVPU::PSADBB_xmm1_xmm2m128(X86::Instruction const&) { TODO(); }
797
798void SoftVPU::MASKMOVQ_mm1_mm2m64(X86::Instruction const&) { TODO(); }
799}