Fixed compilation error
[bochs-mirror.git] / fpu / fpu.cc
blob65cdebf29ed0fce111d5e9dc74057238dd3f7f3b
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: fpu.cc,v 1.48 2008/09/18 19:10:23 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (c) 2003 Stanislav Shwartsman
6 // Written by Stanislav Shwartsman [sshwarts at sourceforge net]
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 /////////////////////////////////////////////////////////////////////////
25 #define NEED_CPU_REG_SHORTCUTS 1
26 #include "bochs.h"
27 #include "cpu/cpu.h"
28 #define LOG_THIS BX_CPU_THIS_PTR
30 #include "iodev/iodev.h"
32 #define UPDATE_LAST_OPCODE 1
33 #define CHECK_PENDING_EXCEPTIONS 1
35 #if BX_SUPPORT_FPU
36 void BX_CPU_C::prepareFPU(bxInstruction_c *i,
37 bx_bool check_pending_exceptions, bx_bool update_last_instruction)
39 if (BX_CPU_THIS_PTR cr0.get_EM() || BX_CPU_THIS_PTR cr0.get_TS())
40 exception(BX_NM_EXCEPTION, 0, 0);
42 if (check_pending_exceptions)
43 BX_CPU_THIS_PTR FPU_check_pending_exceptions();
45 if (update_last_instruction)
47 BX_CPU_THIS_PTR the_i387.foo = (((Bit32u)(i->b1()) << 8) | i->modrm()) & 0x7ff;
48 BX_CPU_THIS_PTR the_i387.fcs = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
49 BX_CPU_THIS_PTR the_i387.fip = BX_CPU_THIS_PTR prev_rip;
51 if (! i->modC0()) {
52 RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
54 BX_CPU_THIS_PTR the_i387.fds = BX_CPU_THIS_PTR sregs[i->seg()].selector.value;
55 BX_CPU_THIS_PTR the_i387.fdp = RMAddr(i);
60 void BX_CPU_C::FPU_check_pending_exceptions(void)
62 if(BX_CPU_THIS_PTR the_i387.get_partial_status() & FPU_SW_Summary)
64 // NE=1 selects the native or internal mode, which generates #MF,
65 // which is an extension introduced with 80486.
66 // NE=0 selects the original (backward compatible) FPU error
67 // handling, which generates an IRQ 13 via the PIC chip.
68 #if BX_CPU_LEVEL >= 4
69 if (BX_CPU_THIS_PTR cr0.get_NE() != 0) {
70 exception(BX_MF_EXCEPTION, 0, 0);
72 else
73 #endif
75 // MSDOS compatibility external interrupt (IRQ13)
76 BX_INFO (("math_abort: MSDOS compatibility FPU exception"));
77 DEV_pic_raise_irq(13);
82 bx_address BX_CPU_C::fpu_save_environment(bxInstruction_c *i)
84 unsigned offset;
86 /* read all registers in stack order and update x87 tag word */
87 for(int n=0;n<8;n++) {
88 // update tag only if it is not empty
89 if (! IS_TAG_EMPTY(n)) {
90 int tag = FPU_tagof(BX_READ_FPU_REG(n));
91 BX_CPU_THIS_PTR the_i387.FPU_settagi(tag, n);
95 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
97 if (protected_mode()) /* Protected Mode */
99 if (i->os32L() || i->os64L())
101 Bit32u tmp;
103 tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_control_word();
104 write_virtual_dword(i->seg(), eaddr, tmp);
105 tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_status_word();
106 write_virtual_dword(i->seg(), eaddr + 0x04, tmp);
107 tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_tag_word();
108 write_virtual_dword(i->seg(), eaddr + 0x08, tmp);
109 tmp = (Bit32u)(BX_CPU_THIS_PTR the_i387.fip);
110 write_virtual_dword(i->seg(), eaddr + 0x0c, tmp);
111 tmp = (BX_CPU_THIS_PTR the_i387.fcs & 0xffff) |
112 ((Bit32u)(BX_CPU_THIS_PTR the_i387.foo)) << 16;
113 write_virtual_dword(i->seg(), eaddr + 0x10, tmp);
114 tmp = (Bit32u)(BX_CPU_THIS_PTR the_i387.fdp);
115 write_virtual_dword(i->seg(), eaddr + 0x14, tmp);
116 tmp = 0xffff0000 | (BX_CPU_THIS_PTR the_i387.fds);
117 write_virtual_dword(i->seg(), eaddr + 0x18, tmp);
119 offset = 0x1c;
121 else /* Protected Mode - 16 bit */
123 Bit16u tmp;
125 tmp = BX_CPU_THIS_PTR the_i387.get_control_word();
126 write_virtual_word(i->seg(), eaddr, tmp);
127 tmp = BX_CPU_THIS_PTR the_i387.get_status_word();
128 write_virtual_word(i->seg(), eaddr + 0x02, tmp);
129 tmp = BX_CPU_THIS_PTR the_i387.get_tag_word();
130 write_virtual_word(i->seg(), eaddr + 0x04, tmp);
131 tmp = (Bit16u)(BX_CPU_THIS_PTR the_i387.fip) & 0xffff;
132 write_virtual_word(i->seg(), eaddr + 0x06, tmp);
133 tmp = (BX_CPU_THIS_PTR the_i387.fcs);
134 write_virtual_word(i->seg(), eaddr + 0x08, tmp);
135 tmp = (Bit16u)(BX_CPU_THIS_PTR the_i387.fdp) & 0xffff;
136 write_virtual_word(i->seg(), eaddr + 0x0a, tmp);
137 tmp = (BX_CPU_THIS_PTR the_i387.fds);
138 write_virtual_word(i->seg(), eaddr + 0x0c, tmp);
140 offset = 0x0e;
143 else /* Real or V86 Mode */
145 Bit32u fp_ip = ((Bit32u)(BX_CPU_THIS_PTR the_i387.fcs) << 4) +
146 (Bit32u)(BX_CPU_THIS_PTR the_i387.fip);
147 Bit32u fp_dp = ((Bit32u)(BX_CPU_THIS_PTR the_i387.fds) << 4) +
148 (Bit32u)(BX_CPU_THIS_PTR the_i387.fdp);
150 if (i->os32L())
152 Bit32u tmp;
154 tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_control_word();
155 write_virtual_dword(i->seg(), eaddr, tmp);
156 tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_status_word();
157 write_virtual_dword(i->seg(), eaddr + 0x04, tmp);
158 tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_tag_word();
159 write_virtual_dword(i->seg(), eaddr + 0x08, tmp);
160 tmp = 0xffff0000 | (fp_ip & 0xffff);
161 write_virtual_dword(i->seg(), eaddr + 0x0c, tmp);
162 tmp = ((fp_ip & 0xffff0000) >> 4) | BX_CPU_THIS_PTR the_i387.foo;
163 write_virtual_dword(i->seg(), eaddr + 0x10, tmp);
164 tmp = 0xffff0000 | (fp_dp & 0xffff);
165 write_virtual_dword(i->seg(), eaddr + 0x14, tmp);
166 tmp = (fp_dp & 0xffff0000) >> 4;
167 write_virtual_dword(i->seg(), eaddr + 0x18, tmp);
169 offset = 0x1c;
171 else /* Real or V86 Mode - 16 bit */
173 Bit16u tmp;
175 tmp = BX_CPU_THIS_PTR the_i387.get_control_word();
176 write_virtual_word(i->seg(), eaddr, tmp);
177 tmp = BX_CPU_THIS_PTR the_i387.get_status_word();
178 write_virtual_word(i->seg(), eaddr + 0x02, tmp);
179 tmp = BX_CPU_THIS_PTR the_i387.get_tag_word();
180 write_virtual_word(i->seg(), eaddr + 0x04, tmp);
181 tmp = fp_ip & 0xffff;
182 write_virtual_word(i->seg(), eaddr + 0x06, tmp);
183 tmp = (Bit16u)((fp_ip & 0xf0000) >> 4) | BX_CPU_THIS_PTR the_i387.foo;
184 write_virtual_word(i->seg(), eaddr + 0x08, tmp);
185 tmp = fp_dp & 0xffff;
186 write_virtual_word(i->seg(), eaddr + 0x0a, tmp);
187 tmp = (Bit16u)((fp_dp & 0xf0000) >> 4);
188 write_virtual_word(i->seg(), eaddr + 0x0c, tmp);
190 offset = 0x0e;
194 return (eaddr + offset);
197 bx_address BX_CPU_C::fpu_load_environment(bxInstruction_c *i)
199 unsigned offset;
201 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
203 if (protected_mode()) /* Protected Mode */
205 if (i->os32L() || i->os64L())
207 Bit32u tmp;
209 tmp = read_virtual_dword(i->seg(), eaddr);
210 BX_CPU_THIS_PTR the_i387.cwd = tmp & 0xffff;
211 tmp = read_virtual_dword(i->seg(), eaddr + 0x04);
212 BX_CPU_THIS_PTR the_i387.swd = tmp & 0xffff;
213 BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x07;
214 tmp = read_virtual_dword(i->seg(), eaddr + 0x08);
215 BX_CPU_THIS_PTR the_i387.twd = tmp & 0xffff;
216 tmp = read_virtual_dword(i->seg(), eaddr + 0x0c);
217 BX_CPU_THIS_PTR the_i387.fip = tmp;
218 tmp = read_virtual_dword(i->seg(), eaddr + 0x10);
219 BX_CPU_THIS_PTR the_i387.fcs = tmp & 0xffff;
220 BX_CPU_THIS_PTR the_i387.foo = (tmp >> 16) & 0x07ff;
221 tmp = read_virtual_dword(i->seg(), eaddr + 0x14);
222 BX_CPU_THIS_PTR the_i387.fdp = tmp;
223 tmp = read_virtual_dword(i->seg(), eaddr + 0x18);
224 BX_CPU_THIS_PTR the_i387.fds = tmp & 0xffff;
225 offset = 0x1c;
227 else /* Protected Mode - 16 bit */
229 Bit16u tmp;
231 tmp = read_virtual_word(i->seg(), eaddr);
232 BX_CPU_THIS_PTR the_i387.cwd = tmp;
233 tmp = read_virtual_word(i->seg(), eaddr + 0x2);
234 BX_CPU_THIS_PTR the_i387.swd = tmp;
235 BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x07;
236 tmp = read_virtual_word(i->seg(), eaddr + 0x04);
237 BX_CPU_THIS_PTR the_i387.twd = tmp;
238 tmp = read_virtual_word(i->seg(), eaddr + 0x06);
239 BX_CPU_THIS_PTR the_i387.fip = tmp & 0xffff;
240 tmp = read_virtual_word(i->seg(), eaddr + 0x08);
241 BX_CPU_THIS_PTR the_i387.fcs = tmp;
242 tmp = read_virtual_word(i->seg(), eaddr + 0x0a);
243 BX_CPU_THIS_PTR the_i387.fdp = tmp & 0xffff;
244 tmp = read_virtual_word(i->seg(), eaddr + 0x0c);
245 BX_CPU_THIS_PTR the_i387.fds = tmp;
246 /* opcode is defined to be zero */
247 BX_CPU_THIS_PTR the_i387.foo = 0;
248 offset = 0x0e;
251 else /* Real or V86 Mode */
253 Bit32u fp_ip = 0, fp_dp = 0;
255 if (i->os32L())
257 Bit32u tmp;
259 tmp = read_virtual_dword(i->seg(), eaddr);
260 BX_CPU_THIS_PTR the_i387.cwd = tmp & 0xffff;
261 tmp = read_virtual_dword(i->seg(), eaddr + 0x04);
262 BX_CPU_THIS_PTR the_i387.swd = tmp & 0xffff;
263 BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x07;
264 tmp = read_virtual_dword(i->seg(), eaddr + 0x08);
265 BX_CPU_THIS_PTR the_i387.twd = tmp & 0xffff;
266 tmp = read_virtual_dword(i->seg(), eaddr + 0x0c);
267 fp_ip = tmp & 0xffff;
268 tmp = read_virtual_dword(i->seg(), eaddr + 0x10);
269 fp_ip = fp_ip | ((tmp & 0x0ffff000) << 4);
270 BX_CPU_THIS_PTR the_i387.fip = fp_ip;
271 BX_CPU_THIS_PTR the_i387.foo = tmp & 0x07ff;
272 BX_CPU_THIS_PTR the_i387.fcs = 0;
273 tmp = read_virtual_dword(i->seg(), eaddr + 0x14);
274 fp_dp = tmp & 0xffff;
275 tmp = read_virtual_dword(i->seg(), eaddr + 0x18);
276 fp_dp = fp_dp | ((tmp & 0x0ffff000) << 4);
277 BX_CPU_THIS_PTR the_i387.fdp = fp_dp;
278 BX_CPU_THIS_PTR the_i387.fds = 0;
279 offset = 0x1c;
281 else /* Real or V86 Mode - 16 bit */
283 Bit16u tmp;
285 tmp = read_virtual_word(i->seg(), eaddr);
286 BX_CPU_THIS_PTR the_i387.cwd = tmp;
287 tmp = read_virtual_word(i->seg(), eaddr + 0x2);
288 BX_CPU_THIS_PTR the_i387.swd = tmp;
289 BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x07;
290 tmp = read_virtual_word(i->seg(), eaddr + 0x04);
291 BX_CPU_THIS_PTR the_i387.twd = tmp;
292 tmp = read_virtual_word(i->seg(), eaddr + 0x06);
293 fp_ip = tmp & 0xffff;
294 tmp = read_virtual_word(i->seg(), eaddr + 0x08);
295 fp_ip = fp_ip | ((tmp & 0xf000) << 4);
296 BX_CPU_THIS_PTR the_i387.fip = fp_ip;
297 BX_CPU_THIS_PTR the_i387.foo = tmp & 0x07ff;
298 BX_CPU_THIS_PTR the_i387.fcs = 0;
299 tmp = read_virtual_word(i->seg(), eaddr + 0x0a);
300 fp_dp = tmp & 0xffff;
301 tmp = read_virtual_word(i->seg(), eaddr + 0x0c);
302 fp_dp = fp_dp | ((tmp & 0xf000) << 4);
303 BX_CPU_THIS_PTR the_i387.fdp = fp_dp;
304 BX_CPU_THIS_PTR the_i387.fds = 0;
305 offset = 0x0e;
309 /* always set bit 6 as '1 */
310 BX_CPU_THIS_PTR the_i387.cwd =
311 (BX_CPU_THIS_PTR the_i387.cwd & ~FPU_CW_Reserved_Bits) | 0x0040;
313 /* check for unmasked exceptions */
314 if (FPU_PARTIAL_STATUS & ~FPU_CONTROL_WORD & FPU_CW_Exceptions_Mask)
316 /* set the B and ES bits in the status-word */
317 FPU_PARTIAL_STATUS |= FPU_SW_Summary | FPU_SW_Backward;
319 else
321 /* clear the B and ES bits in the status-word */
322 FPU_PARTIAL_STATUS &= ~(FPU_SW_Summary | FPU_SW_Backward);
325 return (eaddr + offset);
328 /* D9 /5 */
329 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDCW(bxInstruction_c *i)
331 #if BX_SUPPORT_FPU
332 BX_CPU_THIS_PTR prepareFPU(i, CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
334 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
336 Bit16u cwd = read_virtual_word(i->seg(), eaddr);
337 FPU_CONTROL_WORD = (cwd & ~FPU_CW_Reserved_Bits) | 0x0040; // bit 6 is reserved as '1
339 /* check for unmasked exceptions */
340 if (FPU_PARTIAL_STATUS & ~FPU_CONTROL_WORD & FPU_CW_Exceptions_Mask)
342 /* set the B and ES bits in the status-word */
343 FPU_PARTIAL_STATUS |= FPU_SW_Summary | FPU_SW_Backward;
345 else
347 /* clear the B and ES bits in the status-word */
348 FPU_PARTIAL_STATUS &= ~(FPU_SW_Summary | FPU_SW_Backward);
350 #else
351 BX_INFO(("FLDCW: required FPU, configure --enable-fpu"));
352 #endif
355 /* D9 /7 */
356 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTCW(bxInstruction_c *i)
358 #if BX_SUPPORT_FPU
359 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
361 Bit16u cwd = BX_CPU_THIS_PTR the_i387.get_control_word();
363 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
365 write_virtual_word(i->seg(), eaddr, cwd);
366 #else
367 BX_INFO(("FNSTCW: required FPU, configure --enable-fpu"));
368 #endif
371 /* DD /7 */
372 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTSW(bxInstruction_c *i)
374 #if BX_SUPPORT_FPU
375 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
377 Bit16u swd = BX_CPU_THIS_PTR the_i387.get_status_word();
379 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
381 write_virtual_word(i->seg(), eaddr, swd);
382 #else
383 BX_INFO(("FNSTSW: required FPU, configure --enable-fpu"));
384 #endif
387 /* DF E0 */
388 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTSW_AX(bxInstruction_c *i)
390 #if BX_SUPPORT_FPU
391 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
392 AX = BX_CPU_THIS_PTR the_i387.get_status_word();
393 #else
394 BX_INFO(("FNSTSW_AX: required FPU, configure --enable-fpu"));
395 #endif
398 /* DD /4 */
399 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FRSTOR(bxInstruction_c *i)
401 #if BX_SUPPORT_FPU
402 BX_CPU_THIS_PTR prepareFPU(i, CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
404 bx_address offset = fpu_load_environment(i);
405 floatx80 tmp;
407 /* read all registers in stack order */
408 for(int n=0;n<8;n++)
410 tmp.fraction = read_virtual_qword(i->seg(), offset + n*10);
411 tmp.exp = read_virtual_word (i->seg(), offset + n*10 + 8);
413 // update tag only if it is not empty
414 BX_WRITE_FPU_REGISTER_AND_TAG(tmp,
415 IS_TAG_EMPTY(n) ? FPU_Tag_Empty : FPU_tagof(tmp), n);
417 #else
418 BX_INFO(("FRSTOR: required FPU, configure --enable-fpu"));
419 #endif
422 /* DD /6 */
423 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSAVE(bxInstruction_c *i)
425 #if BX_SUPPORT_FPU
426 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
428 bx_address offset = fpu_save_environment(i);
430 /* save all registers in stack order. */
431 for(int n=0;n<8;n++)
433 floatx80 stn = BX_READ_FPU_REG(n);
434 write_virtual_qword(i->seg(), offset + n*10, stn.fraction);
435 write_virtual_word (i->seg(), offset + n*10 + 8, stn.exp);
438 BX_CPU_THIS_PTR the_i387.init();
439 #else
440 BX_INFO(("FNSAVE: required FPU, configure --enable-fpu"));
441 #endif
444 /* 9B E2 */
445 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNCLEX(bxInstruction_c *i)
447 #if BX_SUPPORT_FPU
448 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
450 FPU_PARTIAL_STATUS &= ~(FPU_SW_Backward|FPU_SW_Summary|FPU_SW_Stack_Fault|FPU_SW_Precision|
451 FPU_SW_Underflow|FPU_SW_Overflow|FPU_SW_Zero_Div|FPU_SW_Denormal_Op|
452 FPU_SW_Invalid);
454 // do not update last fpu instruction pointer
455 #else
456 BX_INFO(("FNCLEX: required FPU, configure --enable-fpu"));
457 #endif
460 /* DB E3 */
461 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNINIT(bxInstruction_c *i)
463 #if BX_SUPPORT_FPU
464 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
465 BX_CPU_THIS_PTR the_i387.init();
466 #else
467 BX_INFO(("FNINIT: required FPU, configure --enable-fpu"));
468 #endif
471 /* D9 /4 */
472 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDENV(bxInstruction_c *i)
474 #if BX_SUPPORT_FPU
475 BX_CPU_THIS_PTR prepareFPU(i, CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
476 fpu_load_environment(i);
478 /* read all registers in stack order and update x87 tag word */
479 for(int n=0;n<8;n++) {
480 // update tag only if it is not empty
481 if (! IS_TAG_EMPTY(n)) {
482 int tag = FPU_tagof(BX_READ_FPU_REG(n));
483 BX_CPU_THIS_PTR the_i387.FPU_settagi(tag, n);
486 #else
487 BX_INFO(("FLDENV: required FPU, configure --enable-fpu"));
488 #endif
491 /* D9 /6 */
492 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTENV(bxInstruction_c *i)
494 #if BX_SUPPORT_FPU
495 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
496 fpu_save_environment(i);
497 /* mask all floating point exceptions */
498 FPU_CONTROL_WORD |= FPU_CW_Exceptions_Mask;
499 /* clear the B and ES bits in the status word */
500 FPU_PARTIAL_STATUS &= ~(FPU_SW_Backward|FPU_SW_Summary);
501 #else
502 BX_INFO(("FNSTENV: required FPU, configure --enable-fpu"));
503 #endif
506 /* D9 D0 */
507 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNOP(bxInstruction_c *i)
509 #if BX_SUPPORT_FPU
510 BX_CPU_THIS_PTR prepareFPU(i, CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
512 // Perform no FPU operation. This instruction takes up space in the
513 // instruction stream but does not affect the FPU or machine
514 // context, except the EIP register.
515 #else
516 BX_INFO(("FNOP: required FPU, configure --enable-fpu"));
517 #endif
520 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPLEGACY(bxInstruction_c *i)
522 #if BX_SUPPORT_FPU
523 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
525 // FPU performs no specific operation and no internal x87 states
526 // are affected
527 #else
528 BX_INFO(("legacy FPU opcodes: required FPU, configure --enable-fpu"));
529 #endif
532 #endif
534 #if BX_SUPPORT_FPU
536 #include <math.h>
538 void BX_CPU_C::print_state_FPU(void)
540 static double scale_factor = pow(2.0, -63.0);
541 static char* cw_round_control[] = {
542 "NEAREST", "DOWN", "UP", "CHOP"
544 static char* cw_precision_control[] = {
545 "32", "RES", "64", "80"
548 Bit32u reg;
549 reg = BX_CPU_THIS_PTR the_i387.get_status_word();
550 fprintf(stderr, "status word: 0x%04x: ", reg);
551 fprintf(stderr, "%s %s TOS%d %s %s %s %s %s %s %s %s %s %s %s\n",
552 (reg & FPU_SW_Backward) ? "B" : "b",
553 (reg & FPU_SW_C3) ? "C3" : "c3", (FPU_TOS&7),
554 (reg & FPU_SW_C2) ? "C2" : "c2",
555 (reg & FPU_SW_C1) ? "C1" : "c1",
556 (reg & FPU_SW_C0) ? "C0" : "c0",
557 (reg & FPU_SW_Summary) ? "ES" : "es",
558 (reg & FPU_SW_Stack_Fault) ? "SF" : "sf",
559 (reg & FPU_SW_Precision) ? "PE" : "pe",
560 (reg & FPU_SW_Underflow) ? "UE" : "ue",
561 (reg & FPU_SW_Overflow) ? "OE" : "oe",
562 (reg & FPU_SW_Zero_Div) ? "ZE" : "ze",
563 (reg & FPU_SW_Denormal_Op) ? "DE" : "de",
564 (reg & FPU_SW_Invalid) ? "IE" : "ie");
566 reg = BX_CPU_THIS_PTR the_i387.get_control_word();
567 fprintf(stderr, "control word: 0x%04x: ", reg);
568 fprintf(stderr, "%s RC_%s PC_%s %s %s %s %s %s %s\n",
569 (reg & FPU_CW_Inf) ? "INF" : "inf",
570 (cw_round_control[(reg & FPU_CW_RC) >> 10]),
571 (cw_precision_control[(reg & FPU_CW_PC) >> 8]),
572 (reg & FPU_CW_Precision) ? "PM" : "pm",
573 (reg & FPU_CW_Underflow) ? "UM" : "um",
574 (reg & FPU_CW_Overflow) ? "OM" : "om",
575 (reg & FPU_CW_Zero_Div) ? "ZM" : "zm",
576 (reg & FPU_CW_Denormal) ? "DM" : "dm",
577 (reg & FPU_CW_Invalid) ? "IM" : "im");
579 reg = BX_CPU_THIS_PTR the_i387.get_tag_word();
580 fprintf(stderr, "tag word: 0x%04x\n", reg);
581 reg = BX_CPU_THIS_PTR the_i387.foo;
582 fprintf(stderr, "operand: 0x%04x\n", reg);
583 reg = (Bit32u)(BX_CPU_THIS_PTR the_i387.fip) & 0xffffffff;
584 fprintf(stderr, "fip: 0x%08x\n", reg);
585 reg = BX_CPU_THIS_PTR the_i387.fcs;
586 fprintf(stderr, "fcs: 0x%04x\n", reg);
587 reg = (Bit32u)(BX_CPU_THIS_PTR the_i387.fdp) & 0xffffffff;
588 fprintf(stderr, "fdp: 0x%08x\n", reg);
589 reg = BX_CPU_THIS_PTR the_i387.fds;
590 fprintf(stderr, "fds: 0x%04x\n", reg);
592 // print stack too
593 int tos = FPU_TOS & 7;
594 for (int i=0; i<8; i++) {
595 const floatx80 &fp = BX_FPU_REG(i);
596 unsigned tag = BX_CPU_THIS_PTR the_i387.FPU_gettagi((i-tos)&7);
597 if (tag != FPU_Tag_Empty) tag = FPU_tagof(fp);
598 double f = pow(2.0, ((0x7fff & fp.exp) - 0x3fff));
599 if (fp.exp & 0x8000) f = -f;
600 #ifdef _MSC_VER
601 f *= (double)(signed __int64)(fp.fraction>>1) * scale_factor * 2;
602 #else
603 f *= fp.fraction*scale_factor;
604 #endif
605 fprintf(stderr, "%sFP%d ST%d(%c): raw 0x%04x:%08lx%08lx (%.10f)\n",
606 i==tos?"=>":" ", i, (i-tos)&7,
607 "v0se"[tag],
608 fp.exp & 0xffff, GET32H(fp.fraction), GET32L(fp.fraction),
612 #endif