[FAST486]
[reactos.git] / lib / fast486 / extraops.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * extraops.c
4 *
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 // #define WIN32_NO_STATUS
25 // #define _INC_WINDOWS
26 #include <windef.h>
27
28 // #define NDEBUG
29 #include <debug.h>
30
31 #include <fast486.h>
32 #include "opcodes.h"
33 #include "common.h"
34 #include "extraops.h"
35
36 /* PUBLIC VARIABLES ***********************************************************/
37
38 FAST486_OPCODE_HANDLER_PROC
39 Fast486ExtendedHandlers[FAST486_NUM_OPCODE_HANDLERS] =
40 {
41 NULL, // TODO: OPCODE 0x00 NOT IMPLEMENTED
42 NULL, // TODO: OPCODE 0x01 NOT IMPLEMENTED
43 NULL, // TODO: OPCODE 0x02 NOT IMPLEMENTED
44 NULL, // TODO: OPCODE 0x03 NOT IMPLEMENTED
45 NULL, // TODO: OPCODE 0x04 NOT IMPLEMENTED
46 NULL, // TODO: OPCODE 0x05 NOT IMPLEMENTED
47 NULL, // TODO: OPCODE 0x06 NOT IMPLEMENTED
48 NULL, // TODO: OPCODE 0x07 NOT IMPLEMENTED
49 NULL, // TODO: OPCODE 0x08 NOT IMPLEMENTED
50 NULL, // TODO: OPCODE 0x09 NOT IMPLEMENTED
51 NULL, // Invalid
52 NULL, // Reserved (UD1)
53 NULL, // Invalid
54 NULL, // Invalid
55 NULL, // Invalid
56 NULL, // Invalid
57 NULL, // TODO: OPCODE 0x10 NOT IMPLEMENTED
58 NULL, // TODO: OPCODE 0x11 NOT IMPLEMENTED
59 NULL, // TODO: OPCODE 0x12 NOT IMPLEMENTED
60 NULL, // TODO: OPCODE 0x13 NOT IMPLEMENTED
61 NULL, // Invalid
62 NULL, // Invalid
63 NULL, // Invalid
64 NULL, // Invalid
65 NULL, // Invalid
66 NULL, // Invalid
67 NULL, // Invalid
68 NULL, // Invalid
69 NULL, // Invalid
70 NULL, // Invalid
71 NULL, // Invalid
72 NULL, // Invalid
73 NULL, // TODO: OPCODE 0x20 NOT IMPLEMENTED
74 NULL, // TODO: OPCODE 0x21 NOT IMPLEMENTED
75 NULL, // TODO: OPCODE 0x22 NOT IMPLEMENTED
76 NULL, // TODO: OPCODE 0x23 NOT IMPLEMENTED
77 NULL, // TODO: OPCODE 0x24 NOT IMPLEMENTED
78 NULL, // Invalid
79 NULL, // TODO: OPCODE 0x26 NOT IMPLEMENTED
80 NULL, // Invalid
81 NULL, // Invalid
82 NULL, // Invalid
83 NULL, // Invalid
84 NULL, // Invalid
85 NULL, // Invalid
86 NULL, // Invalid
87 NULL, // Invalid
88 NULL, // Invalid
89 NULL, // Invalid
90 NULL, // Invalid
91 NULL, // Invalid
92 NULL, // Invalid
93 NULL, // Invalid
94 NULL, // Invalid
95 NULL, // Invalid
96 NULL, // Invalid
97 NULL, // Invalid
98 NULL, // Invalid
99 NULL, // Invalid
100 NULL, // Invalid
101 NULL, // Invalid
102 NULL, // Invalid
103 NULL, // Invalid
104 NULL, // Invalid
105 NULL, // Invalid
106 NULL, // Invalid
107 NULL, // Invalid
108 NULL, // Invalid
109 NULL, // Invalid
110 NULL, // Invalid
111 NULL, // Invalid
112 NULL, // Invalid
113 NULL, // Invalid
114 NULL, // Invalid
115 NULL, // Invalid
116 NULL, // Invalid
117 NULL, // Invalid
118 NULL, // Invalid
119 NULL, // Invalid
120 NULL, // Invalid
121 NULL, // Invalid
122 NULL, // Invalid
123 NULL, // Invalid
124 NULL, // Invalid
125 NULL, // Invalid
126 NULL, // Invalid
127 NULL, // Invalid
128 NULL, // Invalid
129 NULL, // Invalid
130 NULL, // Invalid
131 NULL, // Invalid
132 NULL, // Invalid
133 NULL, // Invalid
134 NULL, // Invalid
135 NULL, // Invalid
136 NULL, // Invalid
137 NULL, // Invalid
138 NULL, // Invalid
139 NULL, // Invalid
140 NULL, // Invalid
141 NULL, // Invalid
142 NULL, // Invalid
143 NULL, // Invalid
144 NULL, // Invalid
145 NULL, // Invalid
146 NULL, // Invalid
147 NULL, // Invalid
148 NULL, // Invalid
149 NULL, // Invalid
150 NULL, // Invalid
151 NULL, // Invalid
152 NULL, // Invalid
153 NULL, // Invalid
154 NULL, // Invalid
155 NULL, // Invalid
156 NULL, // Invalid
157 NULL, // Invalid
158 NULL, // Invalid
159 NULL, // Invalid
160 NULL, // Invalid
161 NULL, // Invalid
162 NULL, // Invalid
163 NULL, // Invalid
164 NULL, // Invalid
165 NULL, // Invalid
166 NULL, // Invalid
167 NULL, // Invalid
168 NULL, // Invalid
169 Fast486ExtOpcodeConditionalJmp,
170 Fast486ExtOpcodeConditionalJmp,
171 Fast486ExtOpcodeConditionalJmp,
172 Fast486ExtOpcodeConditionalJmp,
173 Fast486ExtOpcodeConditionalJmp,
174 Fast486ExtOpcodeConditionalJmp,
175 Fast486ExtOpcodeConditionalJmp,
176 Fast486ExtOpcodeConditionalJmp,
177 Fast486ExtOpcodeConditionalJmp,
178 Fast486ExtOpcodeConditionalJmp,
179 Fast486ExtOpcodeConditionalJmp,
180 Fast486ExtOpcodeConditionalJmp,
181 Fast486ExtOpcodeConditionalJmp,
182 Fast486ExtOpcodeConditionalJmp,
183 Fast486ExtOpcodeConditionalJmp,
184 Fast486ExtOpcodeConditionalJmp,
185 Fast486ExtOpcodeConditionalSet,
186 Fast486ExtOpcodeConditionalSet,
187 Fast486ExtOpcodeConditionalSet,
188 Fast486ExtOpcodeConditionalSet,
189 Fast486ExtOpcodeConditionalSet,
190 Fast486ExtOpcodeConditionalSet,
191 Fast486ExtOpcodeConditionalSet,
192 Fast486ExtOpcodeConditionalSet,
193 Fast486ExtOpcodeConditionalSet,
194 Fast486ExtOpcodeConditionalSet,
195 Fast486ExtOpcodeConditionalSet,
196 Fast486ExtOpcodeConditionalSet,
197 Fast486ExtOpcodeConditionalSet,
198 Fast486ExtOpcodeConditionalSet,
199 Fast486ExtOpcodeConditionalSet,
200 Fast486ExtOpcodeConditionalSet,
201 Fast486ExtOpcodePushFs,
202 Fast486ExtOpcodePopFs,
203 NULL, // Invalid
204 NULL, // TODO: OPCODE 0xA3 NOT IMPLEMENTED
205 NULL, // TODO: OPCODE 0xA4 NOT IMPLEMENTED
206 NULL, // TODO: OPCODE 0xA5 NOT IMPLEMENTED
207 NULL, // Invalid
208 NULL, // Invalid
209 Fast486ExtOpcodePushGs,
210 Fast486ExtOpcodePopGs,
211 NULL, // TODO: OPCODE 0xAA NOT IMPLEMENTED
212 NULL, // TODO: OPCODE 0xAB NOT IMPLEMENTED
213 NULL, // TODO: OPCODE 0xAC NOT IMPLEMENTED
214 NULL, // TODO: OPCODE 0xAD NOT IMPLEMENTED
215 NULL, // TODO: OPCODE 0xAE NOT IMPLEMENTED
216 NULL, // TODO: OPCODE 0xAF NOT IMPLEMENTED
217 NULL, // TODO: OPCODE 0xB0 NOT IMPLEMENTED
218 NULL, // TODO: OPCODE 0xB1 NOT IMPLEMENTED
219 NULL, // TODO: OPCODE 0xB2 NOT IMPLEMENTED
220 NULL, // TODO: OPCODE 0xB3 NOT IMPLEMENTED
221 NULL, // TODO: OPCODE 0xB4 NOT IMPLEMENTED
222 NULL, // TODO: OPCODE 0xB5 NOT IMPLEMENTED
223 NULL, // TODO: OPCODE 0xB6 NOT IMPLEMENTED
224 NULL, // TODO: OPCODE 0xB7 NOT IMPLEMENTED
225 NULL, // TODO: OPCODE 0xB8 NOT IMPLEMENTED
226 NULL, // TODO: OPCODE 0xB9 NOT IMPLEMENTED
227 NULL, // TODO: OPCODE 0xBA NOT IMPLEMENTED
228 NULL, // TODO: OPCODE 0xBB NOT IMPLEMENTED
229 NULL, // TODO: OPCODE 0xBC NOT IMPLEMENTED
230 NULL, // TODO: OPCODE 0xBD NOT IMPLEMENTED
231 NULL, // TODO: OPCODE 0xBE NOT IMPLEMENTED
232 NULL, // TODO: OPCODE 0xBF NOT IMPLEMENTED
233 NULL, // TODO: OPCODE 0xC0 NOT IMPLEMENTED
234 NULL, // TODO: OPCODE 0xC1 NOT IMPLEMENTED
235 NULL, // Invalid
236 NULL, // Invalid
237 NULL, // Invalid
238 NULL, // Invalid
239 NULL, // Invalid
240 NULL, // Invalid
241 NULL, // TODO: OPCODE 0xC8 NOT IMPLEMENTED
242 NULL, // TODO: OPCODE 0xC9 NOT IMPLEMENTED
243 NULL, // TODO: OPCODE 0xCA NOT IMPLEMENTED
244 NULL, // TODO: OPCODE 0xCB NOT IMPLEMENTED
245 NULL, // TODO: OPCODE 0xCC NOT IMPLEMENTED
246 NULL, // TODO: OPCODE 0xCD NOT IMPLEMENTED
247 NULL, // TODO: OPCODE 0xCE NOT IMPLEMENTED
248 NULL, // TODO: OPCODE 0xCF NOT IMPLEMENTED
249 NULL, // Invalid
250 NULL, // Invalid
251 NULL, // Invalid
252 NULL, // Invalid
253 NULL, // Invalid
254 NULL, // Invalid
255 NULL, // Invalid
256 NULL, // Invalid
257 NULL, // Invalid
258 NULL, // Invalid
259 NULL, // Invalid
260 NULL, // Invalid
261 NULL, // Invalid
262 NULL, // Invalid
263 NULL, // Invalid
264 NULL, // Invalid
265 NULL, // Invalid
266 NULL, // Invalid
267 NULL, // Invalid
268 NULL, // Invalid
269 NULL, // Invalid
270 NULL, // Invalid
271 NULL, // Invalid
272 NULL, // Invalid
273 NULL, // Invalid
274 NULL, // Invalid
275 NULL, // Invalid
276 NULL, // Invalid
277 NULL, // Invalid
278 NULL, // Invalid
279 NULL, // Invalid
280 NULL, // Invalid
281 NULL, // Invalid
282 NULL, // Invalid
283 NULL, // Invalid
284 NULL, // Invalid
285 NULL, // Invalid
286 NULL, // Invalid
287 NULL, // Invalid
288 NULL, // Invalid
289 NULL, // Invalid
290 NULL, // Invalid
291 NULL, // Invalid
292 NULL, // Invalid
293 NULL, // Invalid
294 NULL, // Invalid
295 NULL, // Invalid
296 NULL, // Invalid
297 };
298
299 /* PUBLIC FUNCTIONS ***********************************************************/
300
301 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushFs)
302 {
303 /* Call the internal API */
304 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector);
305 }
306
307 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopFs)
308 {
309 ULONG NewSelector;
310
311 if (!Fast486StackPop(State, &NewSelector))
312 {
313 /* Exception occurred */
314 return FALSE;
315 }
316
317 /* Call the internal API */
318 return Fast486LoadSegment(State, FAST486_REG_FS, LOWORD(NewSelector));
319 }
320
321 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePushGs)
322 {
323 /* Call the internal API */
324 return Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector);
325 }
326
327 FAST486_OPCODE_HANDLER(Fast486ExtOpcodePopGs)
328 {
329 ULONG NewSelector;
330
331 if (!Fast486StackPop(State, &NewSelector))
332 {
333 /* Exception occurred */
334 return FALSE;
335 }
336
337 /* Call the internal API */
338 return Fast486LoadSegment(State, FAST486_REG_GS, LOWORD(NewSelector));
339 }
340
341 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalJmp)
342 {
343 BOOLEAN Jump = FALSE;
344 LONG Offset = 0;
345 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
346
347 if (State->PrefixFlags & FAST486_PREFIX_OPSIZE)
348 {
349 /* The OPSIZE prefix toggles the size */
350 Size = !Size;
351 }
352
353 if (State->PrefixFlags & FAST486_PREFIX_LOCK)
354 {
355 /* Invalid prefix */
356 Fast486Exception(State, FAST486_EXCEPTION_UD);
357 return FALSE;
358 }
359
360 /* Make sure this is the right instruction */
361 ASSERT((Opcode & 0xF0) == 0x80);
362
363 /* Fetch the offset */
364 if (Size)
365 {
366 if (!Fast486FetchDword(State, (PULONG)&Offset))
367 {
368 /* Exception occurred */
369 return FALSE;
370 }
371 }
372 else
373 {
374 SHORT Value;
375
376 if (!Fast486FetchWord(State, (PUSHORT)&Value))
377 {
378 /* Exception occurred */
379 return FALSE;
380 }
381
382 /* Sign-extend */
383 Offset = (LONG)Value;
384 }
385
386 switch ((Opcode & 0x0F) >> 1)
387 {
388 /* JO / JNO */
389 case 0:
390 {
391 Jump = State->Flags.Of;
392 break;
393 }
394
395 /* JC / JNC */
396 case 1:
397 {
398 Jump = State->Flags.Cf;
399 break;
400 }
401
402 /* JZ / JNZ */
403 case 2:
404 {
405 Jump = State->Flags.Zf;
406 break;
407 }
408
409 /* JBE / JNBE */
410 case 3:
411 {
412 Jump = State->Flags.Cf || State->Flags.Zf;
413 break;
414 }
415
416 /* JS / JNS */
417 case 4:
418 {
419 Jump = State->Flags.Sf;
420 break;
421 }
422
423 /* JP / JNP */
424 case 5:
425 {
426 Jump = State->Flags.Pf;
427 break;
428 }
429
430 /* JL / JNL */
431 case 6:
432 {
433 Jump = State->Flags.Sf != State->Flags.Of;
434 break;
435 }
436
437 /* JLE / JNLE */
438 case 7:
439 {
440 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
441 break;
442 }
443 }
444
445 if (Opcode & 1)
446 {
447 /* Invert the result */
448 Jump = !Jump;
449 }
450
451 if (Jump)
452 {
453 /* Move the instruction pointer */
454 State->InstPtr.Long += Offset;
455 }
456
457 /* Return success */
458 return TRUE;
459 }
460
461 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
462 {
463 BOOLEAN Value = FALSE;
464 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
465 FAST486_MOD_REG_RM ModRegRm;
466
467 if (State->PrefixFlags & FAST486_PREFIX_ADSIZE)
468 {
469 /* The OPSIZE prefix toggles the size */
470 AddressSize = !AddressSize;
471 }
472
473 /* Get the operands */
474 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
475 {
476 /* Exception occurred */
477 return FALSE;
478 }
479
480 /* Make sure this is the right instruction */
481 ASSERT((Opcode & 0xF0) == 0x90);
482
483 switch ((Opcode & 0x0F) >> 1)
484 {
485 /* SETO / SETNO */
486 case 0:
487 {
488 Value = State->Flags.Of;
489 break;
490 }
491
492 /* SETC / SETNC */
493 case 1:
494 {
495 Value = State->Flags.Cf;
496 break;
497 }
498
499 /* SETZ / SETNZ */
500 case 2:
501 {
502 Value = State->Flags.Zf;
503 break;
504 }
505
506 /* SETBE / SETNBE */
507 case 3:
508 {
509 Value = State->Flags.Cf || State->Flags.Zf;
510 break;
511 }
512
513 /* SETS / SETNS */
514 case 4:
515 {
516 Value = State->Flags.Sf;
517 break;
518 }
519
520 /* SETP / SETNP */
521 case 5:
522 {
523 Value = State->Flags.Pf;
524 break;
525 }
526
527 /* SETL / SETNL */
528 case 6:
529 {
530 Value = State->Flags.Sf != State->Flags.Of;
531 break;
532 }
533
534 /* SETLE / SETNLE */
535 case 7:
536 {
537 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
538 break;
539 }
540 }
541
542 if (Opcode & 1)
543 {
544 /* Invert the result */
545 Value = !Value;
546 }
547
548 /* Write back the result */
549 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
550 }
551
552 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
553 {
554 UCHAR SecondOpcode;
555
556 /* Fetch the second operation code */
557 if (!Fast486FetchByte(State, &SecondOpcode))
558 {
559 /* Exception occurred */
560 return FALSE;
561 }
562
563 if (Fast486ExtendedHandlers[SecondOpcode] != NULL)
564 {
565 /* Call the extended opcode handler */
566 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
567 }
568 else
569 {
570 /* This is not a valid opcode */
571 Fast486Exception(State, FAST486_EXCEPTION_UD);
572 return FALSE;
573 }
574 }