[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 NULL, // TODO: OPCODE 0xA0 NOT IMPLEMENTED
202 NULL, // TODO: OPCODE 0xA1 NOT IMPLEMENTED
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 NULL, // TODO: OPCODE 0xA8 NOT IMPLEMENTED
210 NULL, // TODO: OPCODE 0xA9 NOT IMPLEMENTED
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(Fast486ExtOpcodeConditionalJmp)
302 {
303 BOOLEAN Jump = FALSE;
304 LONG Offset = 0;
305 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
306
307 if (State->PrefixFlags & FAST486_PREFIX_OPSIZE)
308 {
309 /* The OPSIZE prefix toggles the size */
310 Size = !Size;
311 }
312
313 if (State->PrefixFlags & FAST486_PREFIX_LOCK)
314 {
315 /* Invalid prefix */
316 Fast486Exception(State, FAST486_EXCEPTION_UD);
317 return FALSE;
318 }
319
320 /* Make sure this is the right instruction */
321 ASSERT((Opcode & 0xF0) == 0x80);
322
323 /* Fetch the offset */
324 if (Size)
325 {
326 if (!Fast486FetchDword(State, (PULONG)&Offset))
327 {
328 /* Exception occurred */
329 return FALSE;
330 }
331 }
332 else
333 {
334 SHORT Value;
335
336 if (!Fast486FetchWord(State, (PUSHORT)&Value))
337 {
338 /* Exception occurred */
339 return FALSE;
340 }
341
342 /* Sign-extend */
343 Offset = (LONG)Value;
344 }
345
346 switch ((Opcode & 0x0F) >> 1)
347 {
348 /* JO / JNO */
349 case 0:
350 {
351 Jump = State->Flags.Of;
352 break;
353 }
354
355 /* JC / JNC */
356 case 1:
357 {
358 Jump = State->Flags.Cf;
359 break;
360 }
361
362 /* JZ / JNZ */
363 case 2:
364 {
365 Jump = State->Flags.Zf;
366 break;
367 }
368
369 /* JBE / JNBE */
370 case 3:
371 {
372 Jump = State->Flags.Cf || State->Flags.Zf;
373 break;
374 }
375
376 /* JS / JNS */
377 case 4:
378 {
379 Jump = State->Flags.Sf;
380 break;
381 }
382
383 /* JP / JNP */
384 case 5:
385 {
386 Jump = State->Flags.Pf;
387 break;
388 }
389
390 /* JL / JNL */
391 case 6:
392 {
393 Jump = State->Flags.Sf != State->Flags.Of;
394 break;
395 }
396
397 /* JLE / JNLE */
398 case 7:
399 {
400 Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
401 break;
402 }
403 }
404
405 if (Opcode & 1)
406 {
407 /* Invert the result */
408 Jump = !Jump;
409 }
410
411 if (Jump)
412 {
413 /* Move the instruction pointer */
414 State->InstPtr.Long += Offset;
415 }
416
417 /* Return success */
418 return TRUE;
419 }
420
421 FAST486_OPCODE_HANDLER(Fast486ExtOpcodeConditionalSet)
422 {
423 BOOLEAN Value = FALSE;
424 BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
425 FAST486_MOD_REG_RM ModRegRm;
426
427 if (State->PrefixFlags & FAST486_PREFIX_ADSIZE)
428 {
429 /* The OPSIZE prefix toggles the size */
430 AddressSize = !AddressSize;
431 }
432
433 /* Get the operands */
434 if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
435 {
436 /* Exception occurred */
437 return FALSE;
438 }
439
440 /* Make sure this is the right instruction */
441 ASSERT((Opcode & 0xF0) == 0x90);
442
443 switch ((Opcode & 0x0F) >> 1)
444 {
445 /* SETO / SETNO */
446 case 0:
447 {
448 Value = State->Flags.Of;
449 break;
450 }
451
452 /* SETC / SETNC */
453 case 1:
454 {
455 Value = State->Flags.Cf;
456 break;
457 }
458
459 /* SETZ / SETNZ */
460 case 2:
461 {
462 Value = State->Flags.Zf;
463 break;
464 }
465
466 /* SETBE / SETNBE */
467 case 3:
468 {
469 Value = State->Flags.Cf || State->Flags.Zf;
470 break;
471 }
472
473 /* SETS / SETNS */
474 case 4:
475 {
476 Value = State->Flags.Sf;
477 break;
478 }
479
480 /* SETP / SETNP */
481 case 5:
482 {
483 Value = State->Flags.Pf;
484 break;
485 }
486
487 /* SETL / SETNL */
488 case 6:
489 {
490 Value = State->Flags.Sf != State->Flags.Of;
491 break;
492 }
493
494 /* SETLE / SETNLE */
495 case 7:
496 {
497 Value = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf;
498 break;
499 }
500 }
501
502 if (Opcode & 1)
503 {
504 /* Invert the result */
505 Value = !Value;
506 }
507
508 /* Write back the result */
509 return Fast486WriteModrmByteOperands(State, &ModRegRm, FALSE, Value);
510 }
511
512 FAST486_OPCODE_HANDLER(Fast486OpcodeExtended)
513 {
514 UCHAR SecondOpcode;
515
516 /* Fetch the second operation code */
517 if (!Fast486FetchByte(State, &SecondOpcode))
518 {
519 /* Exception occurred */
520 return FALSE;
521 }
522
523 if (Fast486ExtendedHandlers[SecondOpcode] != NULL)
524 {
525 /* Call the extended opcode handler */
526 return Fast486ExtendedHandlers[SecondOpcode](State, SecondOpcode);
527 }
528 else
529 {
530 /* This is not a valid opcode */
531 Fast486Exception(State, FAST486_EXCEPTION_UD);
532 return FALSE;
533 }
534 }