1 /*
2  *  Copyright (C) 2002-2010  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 	CASE_0F_D(0x00)												/* GRP 6 Exxx */
20 		{
21 			if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
22 			GetRM;Bitu which=(rm>>3)&7;
23 			switch (which) {
24 			case 0x00:	/* SLDT */
25 			case 0x01:	/* STR */
26 				{
27 					Bitu saveval;
28 					if (!which) saveval=CPU_SLDT();
29 					else saveval=CPU_STR();
30 					if (rm >= 0xc0) {GetEArw;*earw=(Bit16u)saveval;}
31 					else {GetEAa;SaveMw(eaa,saveval);}
32 				}
33 				break;
34 			case 0x02:case 0x03:case 0x04:case 0x05:
35 				{
36 					/* Just use 16-bit loads since were only using selectors */
37 					Bitu loadval;
38 					if (rm >= 0xc0 ) {GetEArw;loadval=*earw;}
39 					else {GetEAa;loadval=LoadMw(eaa);}
40 					switch (which) {
41 					case 0x02:
42 						if (cpu.cpl) EXCEPTION(EXCEPTION_GP);
43 						if (CPU_LLDT(loadval)) RUNEXCEPTION();
44 						break;
45 					case 0x03:
46 						if (cpu.cpl) EXCEPTION(EXCEPTION_GP);
47 						if (CPU_LTR(loadval)) RUNEXCEPTION();
48 						break;
49 					case 0x04:
50 						CPU_VERR(loadval);
51 						break;
52 					case 0x05:
53 						CPU_VERW(loadval);
54 						break;
55 					}
56 				}
57 				break;
58 			default:
59 				LOG(LOG_CPU,LOG_ERROR)("GRP6:Illegal call %2X",which);
60 				goto illegal_opcode;
61 			}
62 		}
63 		break;
64 	CASE_0F_D(0x01)												/* Group 7 Ed */
65 		{
66 			GetRM;Bitu which=(rm>>3)&7;
67 			if (rm < 0xc0)	{ //First ones all use EA
68 				GetEAa;Bitu limit;
69 				switch (which) {
70 				case 0x00:										/* SGDT */
71 					SaveMw(eaa,(Bit16u)CPU_SGDT_limit());
72 					SaveMd(eaa+2,(Bit32u)CPU_SGDT_base());
73 					break;
74 				case 0x01:										/* SIDT */
75 					SaveMw(eaa,(Bit16u)CPU_SIDT_limit());
76 					SaveMd(eaa+2,(Bit32u)CPU_SIDT_base());
77 					break;
78 				case 0x02:										/* LGDT */
79 					if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
80 					CPU_LGDT(LoadMw(eaa),LoadMd(eaa+2));
81 					break;
82 				case 0x03:										/* LIDT */
83 					if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
84 					CPU_LIDT(LoadMw(eaa),LoadMd(eaa+2));
85 					break;
86 				case 0x04:										/* SMSW */
87 					SaveMw(eaa,(Bit16u)CPU_SMSW());
88 					break;
89 				case 0x06:										/* LMSW */
90 					limit=LoadMw(eaa);
91 					if (CPU_LMSW((Bit16u)limit)) RUNEXCEPTION();
92 					break;
93 				case 0x07:										/* INVLPG */
94 					if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
95 					PAGING_ClearTLB();
96 					break;
97 				}
98 			} else {
99 				GetEArd;
100 				switch (which) {
101 				case 0x02:										/* LGDT */
102 					if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
103 					goto illegal_opcode;
104 				case 0x03:										/* LIDT */
105 					if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
106 					goto illegal_opcode;
107 				case 0x04:										/* SMSW */
108 					*eard=(Bit32u)CPU_SMSW();
109 					break;
110 				case 0x06:										/* LMSW */
111 					if (CPU_LMSW(*eard)) RUNEXCEPTION();
112 					break;
113 				default:
114 					LOG(LOG_CPU,LOG_ERROR)("Illegal group 7 RM subfunction %d",which);
115 					goto illegal_opcode;
116 					break;
117 				}
118 
119 			}
120 		}
121 		break;
122 	CASE_0F_D(0x02)												/* LAR Gd,Ed */
123 		{
124 			if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
125 			GetRMrd;Bitu ar=*rmrd;
126 			if (rm >= 0xc0) {
127 				GetEArw;CPU_LAR(*earw,ar);
128 			} else {
129 				GetEAa;CPU_LAR(LoadMw(eaa),ar);
130 			}
131 			*rmrd=(Bit32u)ar;
132 		}
133 		break;
134 	CASE_0F_D(0x03)												/* LSL Gd,Ew */
135 		{
136 			if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
137 			GetRMrd;Bitu limit=*rmrd;
138 			/* Just load 16-bit values for selectors */
139 			if (rm >= 0xc0) {
140 				GetEArw;CPU_LSL(*earw,limit);
141 			} else {
142 				GetEAa;CPU_LSL(LoadMw(eaa),limit);
143 			}
144 			*rmrd=(Bit32u)limit;
145 		}
146 		break;
147 	CASE_0F_D(0x80)												/* JO */
148 		JumpCond32_d(TFLG_O);break;
149 	CASE_0F_D(0x81)												/* JNO */
150 		JumpCond32_d(TFLG_NO);break;
151 	CASE_0F_D(0x82)												/* JB */
152 		JumpCond32_d(TFLG_B);break;
153 	CASE_0F_D(0x83)												/* JNB */
154 		JumpCond32_d(TFLG_NB);break;
155 	CASE_0F_D(0x84)												/* JZ */
156 		JumpCond32_d(TFLG_Z);break;
157 	CASE_0F_D(0x85)												/* JNZ */
158 		JumpCond32_d(TFLG_NZ);break;
159 	CASE_0F_D(0x86)												/* JBE */
160 		JumpCond32_d(TFLG_BE);break;
161 	CASE_0F_D(0x87)												/* JNBE */
162 		JumpCond32_d(TFLG_NBE);break;
163 	CASE_0F_D(0x88)												/* JS */
164 		JumpCond32_d(TFLG_S);break;
165 	CASE_0F_D(0x89)												/* JNS */
166 		JumpCond32_d(TFLG_NS);break;
167 	CASE_0F_D(0x8a)												/* JP */
168 		JumpCond32_d(TFLG_P);break;
169 	CASE_0F_D(0x8b)												/* JNP */
170 		JumpCond32_d(TFLG_NP);break;
171 	CASE_0F_D(0x8c)												/* JL */
172 		JumpCond32_d(TFLG_L);break;
173 	CASE_0F_D(0x8d)												/* JNL */
174 		JumpCond32_d(TFLG_NL);break;
175 	CASE_0F_D(0x8e)												/* JLE */
176 		JumpCond32_d(TFLG_LE);break;
177 	CASE_0F_D(0x8f)												/* JNLE */
178 		JumpCond32_d(TFLG_NLE);break;
179 
180 	CASE_0F_D(0xa0)												/* PUSH FS */
181 		Push_32(SegValue(fs));break;
182 	CASE_0F_D(0xa1)												/* POP FS */
183 		if (CPU_PopSeg(fs,true)) RUNEXCEPTION();
184 		break;
185 	CASE_0F_D(0xa3)												/* BT Ed,Gd */
186 		{
187 			FillFlags();GetRMrd;
188 			Bit32u mask=1 << (*rmrd & 31);
189 			if (rm >= 0xc0 ) {
190 				GetEArd;
191 				SETFLAGBIT(CF,(*eard & mask));
192 			} else {
193 				GetEAa;eaa+=(((Bit32s)*rmrd)>>5)*4;
194 				Bit32u old=LoadMd(eaa);
195 				SETFLAGBIT(CF,(old & mask));
196 			}
197 			break;
198 		}
199 	CASE_0F_D(0xa4)												/* SHLD Ed,Gd,Ib */
200 		RMEdGdOp3(DSHLD,Fetchb());
201 		break;
202 	CASE_0F_D(0xa5)												/* SHLD Ed,Gd,CL */
203 		RMEdGdOp3(DSHLD,reg_cl);
204 		break;
205 	CASE_0F_D(0xa8)												/* PUSH GS */
206 		Push_32(SegValue(gs));break;
207 	CASE_0F_D(0xa9)												/* POP GS */
208 		if (CPU_PopSeg(gs,true)) RUNEXCEPTION();
209 		break;
210 	CASE_0F_D(0xab)												/* BTS Ed,Gd */
211 		{
212 			FillFlags();GetRMrd;
213 			Bit32u mask=1 << (*rmrd & 31);
214 			if (rm >= 0xc0 ) {
215 				GetEArd;
216 				SETFLAGBIT(CF,(*eard & mask));
217 				*eard|=mask;
218 			} else {
219 				GetEAa;eaa+=(((Bit32s)*rmrd)>>5)*4;
220 				Bit32u old=LoadMd(eaa);
221 				SETFLAGBIT(CF,(old & mask));
222 				SaveMd(eaa,old | mask);
223 			}
224 			break;
225 		}
226 
227 	CASE_0F_D(0xac)												/* SHRD Ed,Gd,Ib */
228 		RMEdGdOp3(DSHRD,Fetchb());
229 		break;
230 	CASE_0F_D(0xad)												/* SHRD Ed,Gd,CL */
231 		RMEdGdOp3(DSHRD,reg_cl);
232 		break;
233 	CASE_0F_D(0xaf)												/* IMUL Gd,Ed */
234 		{
235 			RMGdEdOp3(DIMULD,*rmrd);
236 			break;
237 		}
238 	CASE_0F_D(0xb1)												/* CMPXCHG Ed,Gd */
239 		{
240 			if (CPU_ArchitectureType<CPU_ARCHTYPE_486NEWSLOW) goto illegal_opcode;
241 			FillFlags();
242 			GetRMrd;
243 			if (rm >= 0xc0) {
244 				GetEArd;
245 				if (*eard==reg_eax) {
246 					*eard=*rmrd;
247 					SETFLAGBIT(ZF,1);
248 				} else {
249 					reg_eax=*eard;
250 					SETFLAGBIT(ZF,0);
251 				}
252 			} else {
253 				GetEAa;
254 				Bit32u val=LoadMd(eaa);
255 				if (val==reg_eax) {
256 					SaveMd(eaa,*rmrd);
257 					SETFLAGBIT(ZF,1);
258 				} else {
259 					SaveMd(eaa,val);	// cmpxchg always issues a write
260 					reg_eax=val;
261 					SETFLAGBIT(ZF,0);
262 				}
263 			}
264 			break;
265 		}
266 	CASE_0F_D(0xb2)												/* LSS Ed */
267 		{
268 			GetRMrd;
269 			if (rm >= 0xc0) goto illegal_opcode;
270 			GetEAa;
271 			if (CPU_SetSegGeneral(ss,LoadMw(eaa+4))) RUNEXCEPTION();
272 			*rmrd=LoadMd(eaa);
273 			break;
274 		}
275 	CASE_0F_D(0xb3)												/* BTR Ed,Gd */
276 		{
277 			FillFlags();GetRMrd;
278 			Bit32u mask=1 << (*rmrd & 31);
279 			if (rm >= 0xc0 ) {
280 				GetEArd;
281 				SETFLAGBIT(CF,(*eard & mask));
282 				*eard&= ~mask;
283 			} else {
284 				GetEAa;eaa+=(((Bit32s)*rmrd)>>5)*4;
285 				Bit32u old=LoadMd(eaa);
286 				SETFLAGBIT(CF,(old & mask));
287 				SaveMd(eaa,old & ~mask);
288 			}
289 			break;
290 		}
291 	CASE_0F_D(0xb4)												/* LFS Ed */
292 		{
293 			GetRMrd;
294 			if (rm >= 0xc0) goto illegal_opcode;
295 			GetEAa;
296 			if (CPU_SetSegGeneral(fs,LoadMw(eaa+4))) RUNEXCEPTION();
297 			*rmrd=LoadMd(eaa);
298 			break;
299 		}
300 	CASE_0F_D(0xb5)												/* LGS Ed */
301 		{
302 			GetRMrd;
303 			if (rm >= 0xc0) goto illegal_opcode;
304 			GetEAa;
305 			if (CPU_SetSegGeneral(gs,LoadMw(eaa+4))) RUNEXCEPTION();
306 			*rmrd=LoadMd(eaa);
307 			break;
308 		}
309 	CASE_0F_D(0xb6)												/* MOVZX Gd,Eb */
310 		{
311 			GetRMrd;
312 			if (rm >= 0xc0 ) {GetEArb;*rmrd=*earb;}
313 			else {GetEAa;*rmrd=LoadMb(eaa);}
314 			break;
315 		}
316 	CASE_0F_D(0xb7)												/* MOVXZ Gd,Ew */
317 		{
318 			GetRMrd;
319 			if (rm >= 0xc0 ) {GetEArw;*rmrd=*earw;}
320 			else {GetEAa;*rmrd=LoadMw(eaa);}
321 			break;
322 		}
323 	CASE_0F_D(0xba)												/* GRP8 Ed,Ib */
324 		{
325 			FillFlags();GetRM;
326 			if (rm >= 0xc0 ) {
327 				GetEArd;
328 				Bit32u mask=1 << (Fetchb() & 31);
329 				SETFLAGBIT(CF,(*eard & mask));
330 				switch (rm & 0x38) {
331 				case 0x20:											/* BT */
332 					break;
333 				case 0x28:											/* BTS */
334 					*eard|=mask;
335 					break;
336 				case 0x30:											/* BTR */
337 					*eard&=~mask;
338 					break;
339 				case 0x38:											/* BTC */
340 					if (GETFLAG(CF)) *eard&=~mask;
341 					else *eard|=mask;
342 					break;
343 				default:
344 					E_Exit("CPU:66:0F:BA:Illegal subfunction %X",rm & 0x38);
345 				}
346 			} else {
347 				GetEAa;Bit32u old=LoadMd(eaa);
348 				Bit32u mask=1 << (Fetchb() & 31);
349 				SETFLAGBIT(CF,(old & mask));
350 				switch (rm & 0x38) {
351 				case 0x20:											/* BT */
352 					break;
353 				case 0x28:											/* BTS */
354 					SaveMd(eaa,old|mask);
355 					break;
356 				case 0x30:											/* BTR */
357 					SaveMd(eaa,old & ~mask);
358 					break;
359 				case 0x38:											/* BTC */
360 					if (GETFLAG(CF)) old&=~mask;
361 					else old|=mask;
362 					SaveMd(eaa,old);
363 					break;
364 				default:
365 					E_Exit("CPU:66:0F:BA:Illegal subfunction %X",rm & 0x38);
366 				}
367 			}
368 			break;
369 		}
370 	CASE_0F_D(0xbb)												/* BTC Ed,Gd */
371 		{
372 			FillFlags();GetRMrd;
373 			Bit32u mask=1 << (*rmrd & 31);
374 			if (rm >= 0xc0 ) {
375 				GetEArd;
376 				SETFLAGBIT(CF,(*eard & mask));
377 				*eard^=mask;
378 			} else {
379 				GetEAa;eaa+=(((Bit32s)*rmrd)>>5)*4;
380 				Bit32u old=LoadMd(eaa);
381 				SETFLAGBIT(CF,(old & mask));
382 				SaveMd(eaa,old ^ mask);
383 			}
384 			break;
385 		}
386 	CASE_0F_D(0xbc)												/* BSF Gd,Ed */
387 		{
388 			GetRMrd;
389 			Bit32u result,value;
390 			if (rm >= 0xc0) { GetEArd; value=*eard; }
391 			else			{ GetEAa; value=LoadMd(eaa); }
392 			if (value==0) {
393 				SETFLAGBIT(ZF,true);
394 			} else {
395 				result = 0;
396 				while ((value & 0x01)==0) { result++; value>>=1; }
397 				SETFLAGBIT(ZF,false);
398 				*rmrd = result;
399 			}
400 			lflags.type=t_UNKNOWN;
401 			break;
402 		}
403 	CASE_0F_D(0xbd)												/*  BSR Gd,Ed */
404 		{
405 			GetRMrd;
406 			Bit32u result,value;
407 			if (rm >= 0xc0) { GetEArd; value=*eard; }
408 			else			{ GetEAa; value=LoadMd(eaa); }
409 			if (value==0) {
410 				SETFLAGBIT(ZF,true);
411 			} else {
412 				result = 31;	// Operandsize-1
413 				while ((value & 0x80000000)==0) { result--; value<<=1; }
414 				SETFLAGBIT(ZF,false);
415 				*rmrd = result;
416 			}
417 			lflags.type=t_UNKNOWN;
418 			break;
419 		}
420 	CASE_0F_D(0xbe)												/* MOVSX Gd,Eb */
421 		{
422 			GetRMrd;
423 			if (rm >= 0xc0 ) {GetEArb;*rmrd=*(Bit8s *)earb;}
424 			else {GetEAa;*rmrd=LoadMbs(eaa);}
425 			break;
426 		}
427 	CASE_0F_D(0xbf)												/* MOVSX Gd,Ew */
428 		{
429 			GetRMrd;
430 			if (rm >= 0xc0 ) {GetEArw;*rmrd=*(Bit16s *)earw;}
431 			else {GetEAa;*rmrd=LoadMws(eaa);}
432 			break;
433 		}
434 	CASE_0F_D(0xc1)												/* XADD Gd,Ed */
435 		{
436 			if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
437 			GetRMrd;Bit32u oldrmrd=*rmrd;
438 			if (rm >= 0xc0 ) {GetEArd;*rmrd=*eard;*eard+=oldrmrd;}
439 			else {GetEAa;*rmrd=LoadMd(eaa);SaveMd(eaa,LoadMd(eaa)+oldrmrd);}
440 			break;
441 		}
442 	CASE_0F_D(0xc8)												/* BSWAP EAX */
443 		if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
444 		BSWAPD(reg_eax);break;
445 	CASE_0F_D(0xc9)												/* BSWAP ECX */
446 		if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
447 		BSWAPD(reg_ecx);break;
448 	CASE_0F_D(0xca)												/* BSWAP EDX */
449 		if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
450 		BSWAPD(reg_edx);break;
451 	CASE_0F_D(0xcb)												/* BSWAP EBX */
452 		if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
453 		BSWAPD(reg_ebx);break;
454 	CASE_0F_D(0xcc)												/* BSWAP ESP */
455 		if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
456 		BSWAPD(reg_esp);break;
457 	CASE_0F_D(0xcd)												/* BSWAP EBP */
458 		if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
459 		BSWAPD(reg_ebp);break;
460 	CASE_0F_D(0xce)												/* BSWAP ESI */
461 		if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
462 		BSWAPD(reg_esi);break;
463 	CASE_0F_D(0xcf)												/* BSWAP EDI */
464 		if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
465 		BSWAPD(reg_edi);break;
466