1 /*
2  *  Copyright (C) 2002-2013  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 /* State Management */
20 	CASE_0F_D(0x77)												/* EMMS */
21 	{
22 		setFPU(TAG_Empty);
23 		break;
24 	}
25 
26 
27 /* Data Movement */
28 	CASE_0F_D(0x6e)												/* MOVD Pq,Ed */
29 	{
30 		GetRM;
31 		MMX_reg* rmrq=lookupRMregMM[rm];
32 		if (rm>=0xc0) {
33 			GetEArd;
34 			rmrq->ud.d0=*(Bit32u*)eard;
35 			rmrq->ud.d1=0;
36 		} else {
37 			GetEAa;
38 			rmrq->ud.d0=LoadMd(eaa);
39 			rmrq->ud.d1=0;
40 		}
41 		break;
42 	}
43 	CASE_0F_D(0x7e)												/* MOVD Ed,Pq */
44 	{
45 		GetRM;
46 		MMX_reg* rmrq=lookupRMregMM[rm];
47 		if (rm>=0xc0) {
48 			GetEArd;
49 			*(Bit32u*)eard=rmrq->ud.d0;
50 		} else {
51 			GetEAa;
52 			SaveMd(eaa,rmrq->ud.d0);
53 		}
54 		break;
55 	}
56 
57 	CASE_0F_D(0x6f)												/* MOVQ Pq,Qq */
58 	{
59 		GetRM;
60 		MMX_reg* dest=lookupRMregMM[rm];
61 		if (rm>=0xc0) {
62 			MMX_reg* src=&reg_mmx[rm&7];
63 			dest->q = src->q;
64 		} else {
65 			GetEAa;
66 			dest->q=LoadMq(eaa);
67 		}
68 		break;
69 	}
70 	CASE_0F_D(0x7f)												/* MOVQ Qq,Pq */
71 	{
72 		GetRM;
73 		MMX_reg* dest=lookupRMregMM[rm];
74 		if (rm>=0xc0) {
75 			MMX_reg* src=&reg_mmx[rm&7];
76 			dest->q = src->q;
77 		} else {
78 			GetEAa;
79 			SaveMq(eaa,dest->q);
80 		}
81 		break;
82 	}
83 
84 /* Boolean Logic */
85 	CASE_0F_D(0xef)												/* PXOR Pq,Qq */
86 	{
87 		GetRM;
88 		MMX_reg* dest=lookupRMregMM[rm];
89 		if (rm>=0xc0) {
90 			MMX_reg* src=&reg_mmx[rm&7];
91 			dest->q ^= src->q;
92 		} else {
93 			GetEAa;
94 			dest->q ^= LoadMq(eaa);
95 		}
96 		break;
97 	}
98 
99 	CASE_0F_D(0xeb)												/* POR Pq,Qq */
100 	{
101 		GetRM;
102 		MMX_reg* dest=lookupRMregMM[rm];
103 		if (rm>=0xc0) {
104 			MMX_reg* src=&reg_mmx[rm&7];
105 			dest->q |= src->q;
106 		} else {
107 			GetEAa;
108 			dest->q |= LoadMq(eaa);
109 		}
110 		break;
111 	}
112 	CASE_0F_D(0xdb)												/* PAND Pq,Qq */
113 	{
114 		GetRM;
115 		MMX_reg* dest=lookupRMregMM[rm];
116 		if (rm>=0xc0) {
117 			MMX_reg* src=&reg_mmx[rm&7];
118 			dest->q &= src->q;
119 		} else {
120 			GetEAa;
121 			dest->q &= LoadMq(eaa);
122 		}
123 		break;
124 	}
125 	CASE_0F_D(0xdf)												/* PANDN Pq,Qq */
126 	{
127 		GetRM;
128 		MMX_reg* dest=lookupRMregMM[rm];
129 		if (rm>=0xc0) {
130 			MMX_reg* src=&reg_mmx[rm&7];
131 			dest->q = ~dest->q & src->q;
132 		} else {
133 			GetEAa;
134 			dest->q = ~dest->q & LoadMq(eaa);
135 		}
136 		break;
137 	}
138 
139 /* Shift */
140 	CASE_0F_D(0xf1)												/* PSLLW Pq,Qq */
141 	{
142 		GetRM;
143 		MMX_reg* dest=lookupRMregMM[rm];
144 		MMX_reg src;
145 		if (rm>=0xc0) {
146 			src.q=reg_mmx[rm&7].q;
147 		} else {
148 			GetEAa;
149 			src.q=LoadMq(eaa);
150 		}
151 		if (src.q > 15) dest->q = 0;
152 		else {
153 			dest->uw.w0 <<= src.ub.b0;
154 			dest->uw.w1 <<= src.ub.b0;
155 			dest->uw.w2 <<= src.ub.b0;
156 			dest->uw.w3 <<= src.ub.b0;
157 		}
158 		break;
159 	}
160 	CASE_0F_D(0xd1)												/* PSRLW Pq,Qq */
161 	{
162 		GetRM;
163 		MMX_reg* dest=lookupRMregMM[rm];
164 		MMX_reg src;
165 		if (rm>=0xc0) {
166 			src.q=reg_mmx[rm&7].q;
167 		} else {
168 			GetEAa;
169 			src.q=LoadMq(eaa);
170 		}
171 		if (src.q > 15) dest->q = 0;
172 		else {
173 			dest->uw.w0 >>= src.ub.b0;
174 			dest->uw.w1 >>= src.ub.b0;
175 			dest->uw.w2 >>= src.ub.b0;
176 			dest->uw.w3 >>= src.ub.b0;
177 		}
178 		break;
179 	}
180 	CASE_0F_D(0xe1)												/* PSRAW Pq,Qq */
181 	{
182 		GetRM;
183 		MMX_reg* dest=lookupRMregMM[rm];
184 		MMX_reg src;
185 		MMX_reg tmp;
186 		tmp.q = dest->q;
187 		if (rm>=0xc0) {
188 			src.q=reg_mmx[rm&7].q;
189 		} else {
190 			GetEAa;
191 			src.q=LoadMq(eaa);
192 		}
193 		if (!src.q) break;
194 		if (src.q > 15) {
195 			dest->uw.w0 = (tmp.uw.w0&0x8000)?0xffff:0;
196 			dest->uw.w1 = (tmp.uw.w1&0x8000)?0xffff:0;
197 			dest->uw.w2 = (tmp.uw.w2&0x8000)?0xffff:0;
198 			dest->uw.w3 = (tmp.uw.w3&0x8000)?0xffff:0;
199 		} else {
200 			dest->uw.w0 >>= src.ub.b0;
201 			dest->uw.w1 >>= src.ub.b0;
202 			dest->uw.w2 >>= src.ub.b0;
203 			dest->uw.w3 >>= src.ub.b0;
204 			if (tmp.uw.w0&0x8000) dest->uw.w0 |= (0xffff << (16 - src.ub.b0));
205 			if (tmp.uw.w1&0x8000) dest->uw.w1 |= (0xffff << (16 - src.ub.b0));
206 			if (tmp.uw.w2&0x8000) dest->uw.w2 |= (0xffff << (16 - src.ub.b0));
207 			if (tmp.uw.w3&0x8000) dest->uw.w3 |= (0xffff << (16 - src.ub.b0));
208 		}
209 		break;
210 	}
211 	CASE_0F_D(0x71)												/* PSLLW/PSRLW/PSRAW Pq,Ib */
212 	{
213 		GetRM;
214 		Bit8u op=(rm>>3)&7;
215 		Bit8u shift=Fetchb();
216 		MMX_reg* dest=&reg_mmx[rm&7];
217 		switch (op) {
218 			case 0x06: 	/*PSLLW*/
219 				if (shift > 15) dest->q = 0;
220 				else {
221 					dest->uw.w0 <<= shift;
222 					dest->uw.w1 <<= shift;
223 					dest->uw.w2 <<= shift;
224 					dest->uw.w3 <<= shift;
225 				}
226 				break;
227 			case 0x02:  /*PSRLW*/
228 				if (shift > 15) dest->q = 0;
229 				else {
230 					dest->uw.w0 >>= shift;
231 					dest->uw.w1 >>= shift;
232 					dest->uw.w2 >>= shift;
233 					dest->uw.w3 >>= shift;
234 				}
235 				break;
236 			case 0x04:  /*PSRAW*/
237 				MMX_reg tmp;
238 				if (!shift) break;
239 				tmp.q = dest->q;
240 				if (shift > 15) {
241 					dest->uw.w0 = (tmp.uw.w0&0x8000)?0xffff:0;
242 					dest->uw.w1 = (tmp.uw.w1&0x8000)?0xffff:0;
243 					dest->uw.w2 = (tmp.uw.w2&0x8000)?0xffff:0;
244 					dest->uw.w3 = (tmp.uw.w3&0x8000)?0xffff:0;
245 				} else {
246 					dest->uw.w0 >>= shift;
247 					dest->uw.w1 >>= shift;
248 					dest->uw.w2 >>= shift;
249 					dest->uw.w3 >>= shift;
250 					if (tmp.uw.w0&0x8000) dest->uw.w0 |= (0xffff << (16 - shift));
251 					if (tmp.uw.w1&0x8000) dest->uw.w1 |= (0xffff << (16 - shift));
252 					if (tmp.uw.w2&0x8000) dest->uw.w2 |= (0xffff << (16 - shift));
253 					if (tmp.uw.w3&0x8000) dest->uw.w3 |= (0xffff << (16 - shift));
254 				}
255 				break;
256 		}
257 		break;
258 	}
259 	CASE_0F_D(0xf2)												/* PSLLD Pq,Qq */
260 	{
261 		GetRM;
262 		MMX_reg* dest=lookupRMregMM[rm];
263 		MMX_reg src;
264 		if (rm>=0xc0) {
265 			src.q=reg_mmx[rm&7].q;
266 		} else {
267 			GetEAa;
268 			src.q=LoadMq(eaa);
269 		}
270 		if (src.q > 31) dest->q = 0;
271 		else {
272 			dest->ud.d0 <<= src.ub.b0;
273 			dest->ud.d1 <<= src.ub.b0;
274 		}
275 		break;
276 	}
277 	CASE_0F_D(0xd2)												/* PSRLD Pq,Qq */
278 	{
279 		GetRM;
280 		MMX_reg* dest=lookupRMregMM[rm];
281 		MMX_reg src;
282 		if (rm>=0xc0) {
283 			src.q=reg_mmx[rm&7].q;
284 		} else {
285 			GetEAa;
286 			src.q=LoadMq(eaa);
287 		}
288 		if (src.q > 31) dest->q = 0;
289 		else {
290 			dest->ud.d0 >>= src.ub.b0;
291 			dest->ud.d1 >>= src.ub.b0;
292 		}
293 		break;
294 	}
295 	CASE_0F_D(0xe2)												/* PSRAD Pq,Qq */
296 	{
297 		GetRM;
298 		MMX_reg* dest=lookupRMregMM[rm];
299 		MMX_reg src;
300 		MMX_reg tmp;
301 		tmp.q = dest->q;
302 		if (rm>=0xc0) {
303 			src.q=reg_mmx[rm&7].q;
304 		} else {
305 			GetEAa;
306 			src.q=LoadMq(eaa);
307 		}
308 		if (!src.q) break;
309 		if (src.q > 31) {
310 			dest->ud.d0 = (tmp.ud.d0&0x80000000)?0xffffffff:0;
311 			dest->ud.d1 = (tmp.ud.d1&0x80000000)?0xffffffff:0;
312 		} else {
313 			dest->ud.d0 >>= src.ub.b0;
314 			dest->ud.d1 >>= src.ub.b0;
315 			if (tmp.ud.d0&0x80000000) dest->ud.d0 |= (0xffffffff << (32 - src.ub.b0));
316 			if (tmp.ud.d1&0x80000000) dest->ud.d1 |= (0xffffffff << (32 - src.ub.b0));
317 		}
318 		break;
319 	}
320 	CASE_0F_D(0x72)												/* PSLLD/PSRLD/PSRAD Pq,Ib */
321 	{
322 		GetRM;
323 		Bit8u op=(rm>>3)&7;
324 		Bit8u shift=Fetchb();
325 		MMX_reg* dest=&reg_mmx[rm&7];
326 		switch (op) {
327 			case 0x06: 	/*PSLLD*/
328 				if (shift > 31) dest->q = 0;
329 				else {
330 					dest->ud.d0 <<= shift;
331 					dest->ud.d1 <<= shift;
332 				}
333 				break;
334 			case 0x02:  /*PSRLD*/
335 				if (shift > 31) dest->q = 0;
336 				else {
337 					dest->ud.d0 >>= shift;
338 					dest->ud.d1 >>= shift;
339 				}
340 				break;
341 			case 0x04:  /*PSRAD*/
342 				MMX_reg tmp;
343 				if (!shift) break;
344 				tmp.q = dest->q;
345 				if (shift > 31) {
346 					dest->ud.d0 = (tmp.ud.d0&0x80000000)?0xffffffff:0;
347 					dest->ud.d1 = (tmp.ud.d1&0x80000000)?0xffffffff:0;
348 				} else {
349 					dest->ud.d0 >>= shift;
350 					dest->ud.d1 >>= shift;
351 					if (tmp.ud.d0&0x80000000) dest->ud.d0 |= (0xffffffff << (32 - shift));
352 					if (tmp.ud.d1&0x80000000) dest->ud.d1 |= (0xffffffff << (32 - shift));
353 				}
354 				break;
355 		}
356 		break;
357 	}
358 
359 	CASE_0F_D(0xf3)												/* PSLLQ Pq,Qq */
360 	{
361 		GetRM;
362 		MMX_reg* dest=lookupRMregMM[rm];
363 		MMX_reg src;
364 		if (rm>=0xc0) {
365 			src.q=reg_mmx[rm&7].q;
366 		} else {
367 			GetEAa;
368 			src.q=LoadMq(eaa);
369 		}
370 		if (src.q > 63) dest->q = 0;
371 		else dest->q <<= src.ub.b0;
372 		break;
373 	}
374 	CASE_0F_D(0xd3)												/* PSRLQ Pq,Qq */
375 	{
376 		GetRM;
377 		MMX_reg* dest=lookupRMregMM[rm];
378 		MMX_reg src;
379 		if (rm>=0xc0) {
380 			src.q=reg_mmx[rm&7].q;
381 		} else {
382 			GetEAa;
383 			src.q=LoadMq(eaa);
384 		}
385 		if (src.q > 63) dest->q = 0;
386 		else dest->q >>= src.ub.b0;
387 		break;
388 	}
389 	CASE_0F_D(0x73)												/* PSLLQ/PSRLQ Pq,Ib */
390 	{
391 		GetRM;
392 		Bit8u shift=Fetchb();
393 		MMX_reg* dest=&reg_mmx[rm&7];
394 		if (shift > 63) dest->q = 0;
395 		else {
396 			Bit8u op=rm&0x20;
397 			if (op) {
398 				dest->q <<= shift;
399 			} else {
400 				dest->q >>= shift;
401 			}
402 		}
403 		break;
404 	}
405 
406 /* Math */
407 	CASE_0F_D(0xFC)												/* PADDB Pq,Qq */
408 	{
409 		GetRM;
410 		MMX_reg* dest=lookupRMregMM[rm];
411 		MMX_reg src;
412 		if (rm>=0xc0) {
413 			src.q=reg_mmx[rm&7].q;
414 		} else {
415 			GetEAa;
416 			src.q = LoadMq(eaa);
417 		}
418 		dest->ub.b0 += src.ub.b0;
419 		dest->ub.b1 += src.ub.b1;
420 		dest->ub.b2 += src.ub.b2;
421 		dest->ub.b3 += src.ub.b3;
422 		dest->ub.b4 += src.ub.b4;
423 		dest->ub.b5 += src.ub.b5;
424 		dest->ub.b6 += src.ub.b6;
425 		dest->ub.b7 += src.ub.b7;
426 		break;
427 	}
428 	CASE_0F_D(0xFD)												/* PADDW Pq,Qq */
429 	{
430 		GetRM;
431 		MMX_reg* dest=lookupRMregMM[rm];
432 		MMX_reg src;
433 		if (rm>=0xc0) {
434 			src.q=reg_mmx[rm&7].q;
435 		} else {
436 			GetEAa;
437 			src.q = LoadMq(eaa);
438 		}
439 		dest->uw.w0 += src.uw.w0;
440 		dest->uw.w1 += src.uw.w1;
441 		dest->uw.w2 += src.uw.w2;
442 		dest->uw.w3 += src.uw.w3;
443 		break;
444 	}
445 	CASE_0F_D(0xFE)												/* PADDD Pq,Qq */
446 	{
447 		GetRM;
448 		MMX_reg* dest=lookupRMregMM[rm];
449 		MMX_reg src;
450 		if (rm>=0xc0) {
451 			src.q=reg_mmx[rm&7].q;
452 		} else {
453 			GetEAa;
454 			src.q = LoadMq(eaa);
455 		}
456 		dest->ud.d0 += src.ud.d0;
457 		dest->ud.d1 += src.ud.d1;
458 		break;
459 	}
460 	CASE_0F_D(0xEC)												/* PADDSB Pq,Qq */
461 	{
462 		GetRM;
463 		MMX_reg* dest=lookupRMregMM[rm];
464 		MMX_reg src;
465 		if (rm>=0xc0) {
466 			src.q = reg_mmx[rm&7].q;
467 		} else {
468 			GetEAa;
469 			src.q = LoadMq(eaa);
470 		}
471 		dest->sb.b0 = SaturateWordSToByteS((Bit16s)dest->sb.b0+(Bit16s)src.sb.b0);
472 		dest->sb.b1 = SaturateWordSToByteS((Bit16s)dest->sb.b1+(Bit16s)src.sb.b1);
473 		dest->sb.b2 = SaturateWordSToByteS((Bit16s)dest->sb.b2+(Bit16s)src.sb.b2);
474 		dest->sb.b3 = SaturateWordSToByteS((Bit16s)dest->sb.b3+(Bit16s)src.sb.b3);
475 		dest->sb.b4 = SaturateWordSToByteS((Bit16s)dest->sb.b4+(Bit16s)src.sb.b4);
476 		dest->sb.b5 = SaturateWordSToByteS((Bit16s)dest->sb.b5+(Bit16s)src.sb.b5);
477 		dest->sb.b6 = SaturateWordSToByteS((Bit16s)dest->sb.b6+(Bit16s)src.sb.b6);
478 		dest->sb.b7 = SaturateWordSToByteS((Bit16s)dest->sb.b7+(Bit16s)src.sb.b7);
479 		break;
480 	}
481 	CASE_0F_D(0xED)												/* PADDSW Pq,Qq */
482 	{
483 		GetRM;
484 		MMX_reg* dest=lookupRMregMM[rm];
485 		MMX_reg src;
486 		if (rm>=0xc0) {
487 			src.q = reg_mmx[rm&7].q;
488 		} else {
489 			GetEAa;
490 			src.q = LoadMq(eaa);
491 		}
492 		dest->sw.w0 = SaturateDwordSToWordS((Bit32s)dest->sw.w0+(Bit32s)src.sw.w0);
493 		dest->sw.w1 = SaturateDwordSToWordS((Bit32s)dest->sw.w1+(Bit32s)src.sw.w1);
494 		dest->sw.w2 = SaturateDwordSToWordS((Bit32s)dest->sw.w2+(Bit32s)src.sw.w2);
495 		dest->sw.w3 = SaturateDwordSToWordS((Bit32s)dest->sw.w3+(Bit32s)src.sw.w3);
496 		break;
497 	}
498 	CASE_0F_D(0xDC)												/* PADDUSB Pq,Qq */
499 	{
500 		GetRM;
501 		MMX_reg* dest=lookupRMregMM[rm];
502 		MMX_reg src;
503 		if (rm>=0xc0) {
504 			src.q = reg_mmx[rm&7].q;
505 		} else {
506 			GetEAa;
507 			src.q = LoadMq(eaa);
508 		}
509 		dest->ub.b0 = SaturateWordSToByteU((Bit16s)dest->ub.b0+(Bit16s)src.ub.b0);
510 		dest->ub.b1 = SaturateWordSToByteU((Bit16s)dest->ub.b1+(Bit16s)src.ub.b1);
511 		dest->ub.b2 = SaturateWordSToByteU((Bit16s)dest->ub.b2+(Bit16s)src.ub.b2);
512 		dest->ub.b3 = SaturateWordSToByteU((Bit16s)dest->ub.b3+(Bit16s)src.ub.b3);
513 		dest->ub.b4 = SaturateWordSToByteU((Bit16s)dest->ub.b4+(Bit16s)src.ub.b4);
514 		dest->ub.b5 = SaturateWordSToByteU((Bit16s)dest->ub.b5+(Bit16s)src.ub.b5);
515 		dest->ub.b6 = SaturateWordSToByteU((Bit16s)dest->ub.b6+(Bit16s)src.ub.b6);
516 		dest->ub.b7 = SaturateWordSToByteU((Bit16s)dest->ub.b7+(Bit16s)src.ub.b7);
517 		break;
518 	}
519 	CASE_0F_D(0xDD)												/* PADDUSW Pq,Qq */
520 	{
521 		GetRM;
522 		MMX_reg* dest=lookupRMregMM[rm];
523 		MMX_reg src;
524 		if (rm>=0xc0) {
525 			src.q = reg_mmx[rm&7].q;
526 		} else {
527 			GetEAa;
528 			src.q = LoadMq(eaa);
529 		}
530 		dest->uw.w0 = SaturateDwordSToWordU((Bit32s)dest->uw.w0+(Bit32s)src.uw.w0);
531 		dest->uw.w1 = SaturateDwordSToWordU((Bit32s)dest->uw.w1+(Bit32s)src.uw.w1);
532 		dest->uw.w2 = SaturateDwordSToWordU((Bit32s)dest->uw.w2+(Bit32s)src.uw.w2);
533 		dest->uw.w3 = SaturateDwordSToWordU((Bit32s)dest->uw.w3+(Bit32s)src.uw.w3);
534 		break;
535 	}
536 	CASE_0F_D(0xF8)												/* PSUBB Pq,Qq */
537 	{
538 		GetRM;
539 		MMX_reg* dest=lookupRMregMM[rm];
540 		MMX_reg src;
541 		if (rm>=0xc0) {
542 			src.q=reg_mmx[rm&7].q;
543 		} else {
544 			GetEAa;
545 			src.q = LoadMq(eaa);
546 		}
547 		dest->ub.b0 -= src.ub.b0;
548 		dest->ub.b1 -= src.ub.b1;
549 		dest->ub.b2 -= src.ub.b2;
550 		dest->ub.b3 -= src.ub.b3;
551 		dest->ub.b4 -= src.ub.b4;
552 		dest->ub.b5 -= src.ub.b5;
553 		dest->ub.b6 -= src.ub.b6;
554 		dest->ub.b7 -= src.ub.b7;
555 		break;
556 	}
557 	CASE_0F_D(0xF9)												/* PSUBW Pq,Qq */
558 	{
559 		GetRM;
560 		MMX_reg* dest=lookupRMregMM[rm];
561 		MMX_reg src;
562 		if (rm>=0xc0) {
563 			src.q=reg_mmx[rm&7].q;
564 		} else {
565 			GetEAa;
566 			src.q = LoadMq(eaa);
567 		}
568 		dest->uw.w0 -= src.uw.w0;
569 		dest->uw.w1 -= src.uw.w1;
570 		dest->uw.w2 -= src.uw.w2;
571 		dest->uw.w3 -= src.uw.w3;
572 		break;
573 	}
574 	CASE_0F_D(0xFA)												/* PSUBD Pq,Qq */
575 	{
576 		GetRM;
577 		MMX_reg* dest=lookupRMregMM[rm];
578 		MMX_reg src;
579 		if (rm>=0xc0) {
580 			src.q=reg_mmx[rm&7].q;
581 		} else {
582 			GetEAa;
583 			src.q = LoadMq(eaa);
584 		}
585 		dest->ud.d0 -= src.ud.d0;
586 		dest->ud.d1 -= src.ud.d1;
587 		break;
588 	}
589 	CASE_0F_D(0xE8)												/* PSUBSB Pq,Qq */
590 	{
591 		GetRM;
592 		MMX_reg* dest=lookupRMregMM[rm];
593 		MMX_reg src;
594 		if (rm>=0xc0) {
595 			src.q = reg_mmx[rm&7].q;
596 		} else {
597 			GetEAa;
598 			src.q = LoadMq(eaa);
599 		}
600 		dest->sb.b0 = SaturateWordSToByteS((Bit16s)dest->sb.b0-(Bit16s)src.sb.b0);
601 		dest->sb.b1 = SaturateWordSToByteS((Bit16s)dest->sb.b1-(Bit16s)src.sb.b1);
602 		dest->sb.b2 = SaturateWordSToByteS((Bit16s)dest->sb.b2-(Bit16s)src.sb.b2);
603 		dest->sb.b3 = SaturateWordSToByteS((Bit16s)dest->sb.b3-(Bit16s)src.sb.b3);
604 		dest->sb.b4 = SaturateWordSToByteS((Bit16s)dest->sb.b4-(Bit16s)src.sb.b4);
605 		dest->sb.b5 = SaturateWordSToByteS((Bit16s)dest->sb.b5-(Bit16s)src.sb.b5);
606 		dest->sb.b6 = SaturateWordSToByteS((Bit16s)dest->sb.b6-(Bit16s)src.sb.b6);
607 		dest->sb.b7 = SaturateWordSToByteS((Bit16s)dest->sb.b7-(Bit16s)src.sb.b7);
608 		break;
609 	}
610 	CASE_0F_D(0xE9)												/* PSUBSW Pq,Qq */
611 	{
612 		GetRM;
613 		MMX_reg* dest=lookupRMregMM[rm];
614 		MMX_reg src;
615 		if (rm>=0xc0) {
616 			src.q = reg_mmx[rm&7].q;
617 		} else {
618 			GetEAa;
619 			src.q = LoadMq(eaa);
620 		}
621 		dest->sw.w0 = SaturateDwordSToWordS((Bit32s)dest->sw.w0-(Bit32s)src.sw.w0);
622 		dest->sw.w1 = SaturateDwordSToWordS((Bit32s)dest->sw.w1-(Bit32s)src.sw.w1);
623 		dest->sw.w2 = SaturateDwordSToWordS((Bit32s)dest->sw.w2-(Bit32s)src.sw.w2);
624 		dest->sw.w3 = SaturateDwordSToWordS((Bit32s)dest->sw.w3-(Bit32s)src.sw.w3);
625 		break;
626 	}
627 	CASE_0F_D(0xD8)												/* PSUBUSB Pq,Qq */
628 	{
629 		GetRM;
630 		MMX_reg* dest=lookupRMregMM[rm];
631 		MMX_reg src;
632 		MMX_reg result;
633 		if (rm>=0xc0) {
634 			src.q = reg_mmx[rm&7].q;
635 		} else {
636 			GetEAa;
637 			src.q = LoadMq(eaa);
638 		}
639 		result.q = 0;
640 		if (dest->ub.b0>src.ub.b0) result.ub.b0 = dest->ub.b0 - src.ub.b0;
641 		if (dest->ub.b1>src.ub.b1) result.ub.b1 = dest->ub.b1 - src.ub.b1;
642 		if (dest->ub.b2>src.ub.b2) result.ub.b2 = dest->ub.b2 - src.ub.b2;
643 		if (dest->ub.b3>src.ub.b3) result.ub.b3 = dest->ub.b3 - src.ub.b3;
644 		if (dest->ub.b4>src.ub.b4) result.ub.b4 = dest->ub.b4 - src.ub.b4;
645 		if (dest->ub.b5>src.ub.b5) result.ub.b5 = dest->ub.b5 - src.ub.b5;
646 		if (dest->ub.b6>src.ub.b6) result.ub.b6 = dest->ub.b6 - src.ub.b6;
647 		if (dest->ub.b7>src.ub.b7) result.ub.b7 = dest->ub.b7 - src.ub.b7;
648 		dest->q = result.q;
649 		break;
650 	}
651 
652 	CASE_0F_D(0xD9)												/* PSUBUSW Pq,Qq */
653 	{
654 		GetRM;
655 		MMX_reg* dest=lookupRMregMM[rm];
656 		MMX_reg src;
657 		MMX_reg result;
658 		if (rm>=0xc0) {
659 			src.q = reg_mmx[rm&7].q;
660 		} else {
661 			GetEAa;
662 			src.q = LoadMq(eaa);
663 		}
664 		result.q = 0;
665 		if (dest->uw.w0>src.uw.w0) result.uw.w0 = dest->uw.w0 - src.uw.w0;
666 		if (dest->uw.w1>src.uw.w1) result.uw.w1 = dest->uw.w1 - src.uw.w1;
667 		if (dest->uw.w2>src.uw.w2) result.uw.w2 = dest->uw.w2 - src.uw.w2;
668 		if (dest->uw.w3>src.uw.w3) result.uw.w3 = dest->uw.w3 - src.uw.w3;
669 		dest->q = result.q;
670 		break;
671 	}
672 	CASE_0F_D(0xE5)												/* PMULHW Pq,Qq */
673 	{
674 		GetRM;
675 		MMX_reg* dest=lookupRMregMM[rm];
676 		MMX_reg src;
677 		if (rm>=0xc0) {
678 			src.q = reg_mmx[rm&7].q;
679 		} else {
680 			GetEAa;
681 			src.q = LoadMq(eaa);
682 		}
683 		Bit32s product0 = (Bit32s)dest->sw.w0 * (Bit32s)src.sw.w0;
684 		Bit32s product1 = (Bit32s)dest->sw.w1 * (Bit32s)src.sw.w1;
685 		Bit32s product2 = (Bit32s)dest->sw.w2 * (Bit32s)src.sw.w2;
686 		Bit32s product3 = (Bit32s)dest->sw.w3 * (Bit32s)src.sw.w3;
687 		dest->uw.w0 = (Bit16u)(product0 >> 16);
688 		dest->uw.w1 = (Bit16u)(product1 >> 16);
689 		dest->uw.w2 = (Bit16u)(product2 >> 16);
690 		dest->uw.w3 = (Bit16u)(product3 >> 16);
691 		break;
692 	}
693 	CASE_0F_D(0xD5)												/* PMULLW Pq,Qq */
694 	{
695 		GetRM;
696 		MMX_reg* dest=lookupRMregMM[rm];
697 		MMX_reg src;
698 		if (rm>=0xc0) {
699 			src.q = reg_mmx[rm&7].q;
700 		} else {
701 			GetEAa;
702 			src.q = LoadMq(eaa);
703 		}
704 		Bit32u product0 = (Bit32u)dest->uw.w0 * (Bit32u)src.uw.w0;
705 		Bit32u product1 = (Bit32u)dest->uw.w1 * (Bit32u)src.uw.w1;
706 		Bit32u product2 = (Bit32u)dest->uw.w2 * (Bit32u)src.uw.w2;
707 		Bit32u product3 = (Bit32u)dest->uw.w3 * (Bit32u)src.uw.w3;
708 		dest->uw.w0 = (product0 & 0xffff);
709 		dest->uw.w1 = (product1 & 0xffff);
710 		dest->uw.w2 = (product2 & 0xffff);
711 		dest->uw.w3 = (product3 & 0xffff);
712 		break;
713 	}
714 	CASE_0F_D(0xF5)												/* PMADDWD Pq,Qq */
715 	{
716 		GetRM;
717 		MMX_reg* dest=lookupRMregMM[rm];
718 		MMX_reg src;
719 		if (rm>=0xc0) {
720 			src.q = reg_mmx[rm&7].q;
721 		} else {
722 			GetEAa;
723 			src.q = LoadMq(eaa);
724 		}
725 		if (dest->ud.d0 == 0x80008000 && src.ud.d0 == 0x80008000)
726 			dest->ud.d0 = 0x80000000;
727 		else {
728 			Bit32s product0 = (Bit32s)dest->sw.w0 * (Bit32s)src.sw.w0;
729 			Bit32s product1 = (Bit32s)dest->sw.w1 * (Bit32s)src.sw.w1;
730 			dest->ud.d0 = product0 + product1;
731 		}
732 		if (dest->ud.d1 == 0x80008000 && src.ud.d1 == 0x80008000)
733 			dest->ud.d1 = 0x80000000;
734 		else {
735 			Bit32s product2 = (Bit32s)dest->sw.w2 * (Bit32s)src.sw.w2;
736 			Bit32s product3 = (Bit32s)dest->sw.w3 * (Bit32s)src.sw.w3;
737 			dest->sd.d1 = product2 + product3;
738 		}
739 		break;
740 	}
741 
742 /* Comparison */
743 	CASE_0F_D(0x74)												/* PCMPEQB Pq,Qq */
744 	{
745 		GetRM;
746 		MMX_reg* dest=lookupRMregMM[rm];
747 		MMX_reg src;
748 		if (rm>=0xc0) {
749 			src.q=reg_mmx[rm&7].q;
750 		} else {
751 			GetEAa;
752 			src.q = LoadMq(eaa);
753 		}
754 		dest->ub.b0 = dest->ub.b0==src.ub.b0?0xff:0;
755 		dest->ub.b1 = dest->ub.b1==src.ub.b1?0xff:0;
756 		dest->ub.b2 = dest->ub.b2==src.ub.b2?0xff:0;
757 		dest->ub.b3 = dest->ub.b3==src.ub.b3?0xff:0;
758 		dest->ub.b4 = dest->ub.b4==src.ub.b4?0xff:0;
759 		dest->ub.b5 = dest->ub.b5==src.ub.b5?0xff:0;
760 		dest->ub.b6 = dest->ub.b6==src.ub.b6?0xff:0;
761 		dest->ub.b7 = dest->ub.b7==src.ub.b7?0xff:0;
762 		break;
763 	}
764 	CASE_0F_D(0x75)												/* PCMPEQW Pq,Qq */
765 	{
766 		GetRM;
767 		MMX_reg* dest=lookupRMregMM[rm];
768 		MMX_reg src;
769 		if (rm>=0xc0) {
770 			src.q=reg_mmx[rm&7].q;
771 		} else {
772 			GetEAa;
773 			src.q = LoadMq(eaa);
774 		}
775 		dest->uw.w0 = dest->uw.w0==src.uw.w0?0xffff:0;
776 		dest->uw.w1 = dest->uw.w1==src.uw.w1?0xffff:0;
777 		dest->uw.w2 = dest->uw.w2==src.uw.w2?0xffff:0;
778 		dest->uw.w3 = dest->uw.w3==src.uw.w3?0xffff:0;
779 		break;
780 	}
781 	CASE_0F_D(0x76)												/* PCMPEQD Pq,Qq */
782 	{
783 		GetRM;
784 		MMX_reg* dest=lookupRMregMM[rm];
785 		MMX_reg src;
786 		if (rm>=0xc0) {
787 			src.q=reg_mmx[rm&7].q;
788 		} else {
789 			GetEAa;
790 			src.q = LoadMq(eaa);
791 		}
792 		dest->ud.d0 = dest->ud.d0==src.ud.d0?0xffffffff:0;
793 		dest->ud.d1 = dest->ud.d1==src.ud.d1?0xffffffff:0;
794 		break;
795 	}
796 	CASE_0F_D(0x64)												/* PCMPGTB Pq,Qq */
797 	{
798 		GetRM;
799 		MMX_reg* dest=lookupRMregMM[rm];
800 		MMX_reg src;
801 		if (rm>=0xc0) {
802 			src.q=reg_mmx[rm&7].q;
803 		} else {
804 			GetEAa;
805 			src.q = LoadMq(eaa);
806 		}
807 		dest->ub.b0 = dest->sb.b0>src.sb.b0?0xff:0;
808 		dest->ub.b1 = dest->sb.b1>src.sb.b1?0xff:0;
809 		dest->ub.b2 = dest->sb.b2>src.sb.b2?0xff:0;
810 		dest->ub.b3 = dest->sb.b3>src.sb.b3?0xff:0;
811 		dest->ub.b4 = dest->sb.b4>src.sb.b4?0xff:0;
812 		dest->ub.b5 = dest->sb.b5>src.sb.b5?0xff:0;
813 		dest->ub.b6 = dest->sb.b6>src.sb.b6?0xff:0;
814 		dest->ub.b7 = dest->sb.b7>src.sb.b7?0xff:0;
815 		break;
816 	}
817 	CASE_0F_D(0x65)												/* PCMPGTW Pq,Qq */
818 	{
819 		GetRM;
820 		MMX_reg* dest=lookupRMregMM[rm];
821 		MMX_reg src;
822 		if (rm>=0xc0) {
823 			src.q=reg_mmx[rm&7].q;
824 		} else {
825 			GetEAa;
826 			src.q = LoadMq(eaa);
827 		}
828 		dest->uw.w0 = dest->sw.w0>src.sw.w0?0xffff:0;
829 		dest->uw.w1 = dest->sw.w1>src.sw.w1?0xffff:0;
830 		dest->uw.w2 = dest->sw.w2>src.sw.w2?0xffff:0;
831 		dest->uw.w3 = dest->sw.w3>src.sw.w3?0xffff:0;
832 		break;
833 	}
834 	CASE_0F_D(0x66)												/* PCMPGTD Pq,Qq */
835 	{
836 		GetRM;
837 		MMX_reg* dest=lookupRMregMM[rm];
838 		MMX_reg src;
839 		if (rm>=0xc0) {
840 			src.q=reg_mmx[rm&7].q;
841 		} else {
842 			GetEAa;
843 			src.q = LoadMq(eaa);
844 		}
845 		dest->ud.d0 = dest->sd.d0>src.sd.d0?0xffffffff:0;
846 		dest->ud.d1 = dest->sd.d1>src.sd.d1?0xffffffff:0;
847 		break;
848 	}
849 
850 /* Data Packing */
851 	CASE_0F_D(0x63)												/* PACKSSWB Pq,Qq */
852 	{
853 		GetRM;
854 		MMX_reg* dest=lookupRMregMM[rm];
855 		MMX_reg src;
856 		if (rm>=0xc0) {
857 			src.q=reg_mmx[rm&7].q;
858 		} else {
859 			GetEAa;
860 			src.q = LoadMq(eaa);
861 		}
862 		dest->sb.b0 = SaturateWordSToByteS(dest->sw.w0);
863 		dest->sb.b1 = SaturateWordSToByteS(dest->sw.w1);
864 		dest->sb.b2 = SaturateWordSToByteS(dest->sw.w2);
865 		dest->sb.b3 = SaturateWordSToByteS(dest->sw.w3);
866 		dest->sb.b4 = SaturateWordSToByteS(src.sw.w0);
867 		dest->sb.b5 = SaturateWordSToByteS(src.sw.w1);
868 		dest->sb.b6 = SaturateWordSToByteS(src.sw.w2);
869 		dest->sb.b7 = SaturateWordSToByteS(src.sw.w3);
870 		break;
871 	}
872 	CASE_0F_D(0x6B)												/* PACKSSDW Pq,Qq */
873 	{
874 		GetRM;
875 		MMX_reg* dest=lookupRMregMM[rm];
876 		MMX_reg src;
877 		if (rm>=0xc0) {
878 			src.q=reg_mmx[rm&7].q;
879 		} else {
880 			GetEAa;
881 			src.q = LoadMq(eaa);
882 		}
883 		dest->sw.w0 = SaturateDwordSToWordS(dest->sd.d0);
884 		dest->sw.w1 = SaturateDwordSToWordS(dest->sd.d1);
885 		dest->sw.w2 = SaturateDwordSToWordS(src.sd.d0);
886 		dest->sw.w3 = SaturateDwordSToWordS(src.sd.d1);
887 		break;
888 	}
889 	CASE_0F_D(0x67)												/* PACKUSWB Pq,Qq */
890 	{
891 		GetRM;
892 		MMX_reg* dest=lookupRMregMM[rm];
893 		MMX_reg src;
894 		if (rm>=0xc0) {
895 			src.q=reg_mmx[rm&7].q;
896 		} else {
897 			GetEAa;
898 			src.q = LoadMq(eaa);
899 		}
900 		dest->ub.b0 = SaturateWordSToByteU(dest->sw.w0);
901 		dest->ub.b1 = SaturateWordSToByteU(dest->sw.w1);
902 		dest->ub.b2 = SaturateWordSToByteU(dest->sw.w2);
903 		dest->ub.b3 = SaturateWordSToByteU(dest->sw.w3);
904 		dest->ub.b4 = SaturateWordSToByteU(src.sw.w0);
905 		dest->ub.b5 = SaturateWordSToByteU(src.sw.w1);
906 		dest->ub.b6 = SaturateWordSToByteU(src.sw.w2);
907 		dest->ub.b7 = SaturateWordSToByteU(src.sw.w3);
908 		break;
909 	}
910 	CASE_0F_D(0x68)												/* PUNPCKHBW Pq,Qq */
911 	{
912 		GetRM;
913 		MMX_reg* dest=lookupRMregMM[rm];
914 		MMX_reg src;
915 		if (rm>=0xc0) {
916 			src.q=reg_mmx[rm&7].q;
917 		} else {
918 			GetEAa;
919 			src.q = LoadMq(eaa);
920 		}
921 		dest->ub.b0 = dest->ub.b4;
922 		dest->ub.b1 = src.ub.b4;
923 		dest->ub.b2 = dest->ub.b5;
924 		dest->ub.b3 = src.ub.b5;
925 		dest->ub.b4 = dest->ub.b6;
926 		dest->ub.b5 = src.ub.b6;
927 		dest->ub.b6 = dest->ub.b7;
928 		dest->ub.b7 = src.ub.b7;
929 		break;
930 	}
931 	CASE_0F_D(0x69)												/* PUNPCKHWD Pq,Qq */
932 	{
933 		GetRM;
934 		MMX_reg* dest=lookupRMregMM[rm];
935 		MMX_reg src;
936 		if (rm>=0xc0) {
937 			src.q=reg_mmx[rm&7].q;
938 		} else {
939 			GetEAa;
940 			src.q = LoadMq(eaa);
941 		}
942 		dest->uw.w0 = dest->uw.w2;
943 		dest->uw.w1 = src.uw.w2;
944 		dest->uw.w2 = dest->uw.w3;
945 		dest->uw.w3 = src.uw.w3;
946 		break;
947 	}
948 	CASE_0F_D(0x6A)												/* PUNPCKHDQ Pq,Qq */
949 	{
950 		GetRM;
951 		MMX_reg* dest=lookupRMregMM[rm];
952 		MMX_reg src;
953 		if (rm>=0xc0) {
954 			src.q=reg_mmx[rm&7].q;
955 		} else {
956 			GetEAa;
957 			src.q = LoadMq(eaa);
958 		}
959 		dest->ud.d0 = dest->ud.d1;
960 		dest->ud.d1 = src.ud.d1;
961 		break;
962 	}
963 	CASE_0F_D(0x60)												/* PUNPCKLBW Pq,Qq */
964 	{
965 		GetRM;
966 		MMX_reg* dest=lookupRMregMM[rm];
967 		MMX_reg src;
968 		if (rm>=0xc0) {
969 			src.q=reg_mmx[rm&7].q;
970 		} else {
971 			GetEAa;
972 			src.q = LoadMq(eaa);
973 		}
974 		dest->ub.b7 = src.ub.b3;
975 		dest->ub.b6 = dest->ub.b3;
976 		dest->ub.b5 = src.ub.b2;
977 		dest->ub.b4 = dest->ub.b2;
978 		dest->ub.b3 = src.ub.b1;
979 		dest->ub.b2 = dest->ub.b1;
980 		dest->ub.b1 = src.ub.b0;
981 		dest->ub.b0 = dest->ub.b0;
982 		break;
983 	}
984 	CASE_0F_D(0x61)												/* PUNPCKLWD Pq,Qq */
985 	{
986 		GetRM;
987 		MMX_reg* dest=lookupRMregMM[rm];
988 		MMX_reg src;
989 		if (rm>=0xc0) {
990 			src.q=reg_mmx[rm&7].q;
991 		} else {
992 			GetEAa;
993 			src.q = LoadMq(eaa);
994 		}
995 		dest->uw.w3 = src.uw.w1;
996 		dest->uw.w2 = dest->uw.w1;
997 		dest->uw.w1 = src.uw.w0;
998 		dest->uw.w0 = dest->uw.w0;
999 		break;
1000 	}
1001 	CASE_0F_D(0x62)												/* PUNPCKLDQ Pq,Qq */
1002 	{
1003 		GetRM;
1004 		MMX_reg* dest=lookupRMregMM[rm];
1005 		MMX_reg src;
1006 		if (rm>=0xc0) {
1007 			src.q=reg_mmx[rm&7].q;
1008 		} else {
1009 			GetEAa;
1010 			src.q = LoadMq(eaa);
1011 		}
1012 		dest->ud.d1 = src.ud.d0;
1013 		break;
1014 	}
1015