- removed support for old-style syntax userbutton shortcuts
[bochs-mirror.git] / fpu / fpu.cc
blob2c54633793bcca8fdb141834c99cb5795966a45b
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: fpu.cc,v 1.39 2008/04/30 20:41:15 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 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);
56 } else {
57 BX_CPU_THIS_PTR the_i387.fds = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
58 BX_CPU_THIS_PTR the_i387.fdp = 0;
63 void BX_CPU_C::FPU_check_pending_exceptions(void)
65 if(BX_CPU_THIS_PTR the_i387.get_partial_status() & FPU_SW_Summary)
67 // NE=1 selects the native or internal mode, which generates #MF,
68 // which is an extension introduced with 80486.
69 // NE=0 selects the original (backward compatible) FPU error
70 // handling, which generates an IRQ 13 via the PIC chip.
71 #if BX_CPU_LEVEL >= 4
72 if (BX_CPU_THIS_PTR cr0.get_NE() != 0) {
73 exception(BX_MF_EXCEPTION, 0, 0);
75 else
76 #endif
78 // MSDOS compatibility external interrupt (IRQ13)
79 BX_INFO (("math_abort: MSDOS compatibility FPU exception"));
80 DEV_pic_raise_irq(13);
85 int BX_CPU_C::fpu_save_environment(bxInstruction_c *i)
87 BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
89 if (protected_mode()) /* Protected Mode */
91 if (i->os32L() || i->os64L())
93 Bit32u tmp;
95 tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_control_word();
96 write_virtual_dword(i->seg(), RMAddr(i), tmp);
97 tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_status_word();
98 write_virtual_dword(i->seg(), RMAddr(i) + 0x04, tmp);
99 tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_tag_word();
100 write_virtual_dword(i->seg(), RMAddr(i) + 0x08, tmp);
101 tmp = (Bit32u)(BX_CPU_THIS_PTR the_i387.fip);
102 write_virtual_dword(i->seg(), RMAddr(i) + 0x0c, tmp);
103 tmp = (BX_CPU_THIS_PTR the_i387.fcs & 0xffff) |
104 ((Bit32u)(BX_CPU_THIS_PTR the_i387.foo)) << 16;
105 write_virtual_dword(i->seg(), RMAddr(i) + 0x10, tmp);
106 tmp = (Bit32u)(BX_CPU_THIS_PTR the_i387.fdp);
107 write_virtual_dword(i->seg(), RMAddr(i) + 0x14, tmp);
108 tmp = 0xffff0000 | (BX_CPU_THIS_PTR the_i387.fds);
109 write_virtual_dword(i->seg(), RMAddr(i) + 0x18, tmp);
111 return 0x1c;
113 else /* Protected Mode - 16 bit */
115 Bit16u tmp;
117 tmp = BX_CPU_THIS_PTR the_i387.get_control_word();
118 write_virtual_word(i->seg(), RMAddr(i), tmp);
119 tmp = BX_CPU_THIS_PTR the_i387.get_status_word();
120 write_virtual_word(i->seg(), RMAddr(i) + 0x02, tmp);
121 tmp = BX_CPU_THIS_PTR the_i387.get_tag_word();
122 write_virtual_word(i->seg(), RMAddr(i) + 0x04, tmp);
123 tmp = (Bit16u)(BX_CPU_THIS_PTR the_i387.fip) & 0xffff;
124 write_virtual_word(i->seg(), RMAddr(i) + 0x06, tmp);
125 tmp = (BX_CPU_THIS_PTR the_i387.fcs);
126 write_virtual_word(i->seg(), RMAddr(i) + 0x08, tmp);
127 tmp = (Bit16u)(BX_CPU_THIS_PTR the_i387.fdp) & 0xffff;
128 write_virtual_word(i->seg(), RMAddr(i) + 0x0a, tmp);
129 tmp = (BX_CPU_THIS_PTR the_i387.fds);
130 write_virtual_word(i->seg(), RMAddr(i) + 0x0c, tmp);
132 return 0x0e;
135 else /* Real or V86 Mode */
137 Bit32u fp_ip = ((Bit32u)(BX_CPU_THIS_PTR the_i387.fcs) << 4) +
138 (Bit32u)(BX_CPU_THIS_PTR the_i387.fip);
139 Bit32u fp_dp = ((Bit32u)(BX_CPU_THIS_PTR the_i387.fds) << 4) +
140 (Bit32u)(BX_CPU_THIS_PTR the_i387.fdp);
142 if (i->os32L() || i->os64L())
144 Bit32u tmp;
146 tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_control_word();
147 write_virtual_dword(i->seg(), RMAddr(i), tmp);
148 tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_status_word();
149 write_virtual_dword(i->seg(), RMAddr(i) + 0x04, tmp);
150 tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_tag_word();
151 write_virtual_dword(i->seg(), RMAddr(i) + 0x08, tmp);
152 tmp = 0xffff0000 | (fp_ip & 0xffff);
153 write_virtual_dword(i->seg(), RMAddr(i) + 0x0c, tmp);
154 tmp = ((fp_ip & 0xffff0000) >> 4) | BX_CPU_THIS_PTR the_i387.foo;
155 write_virtual_dword(i->seg(), RMAddr(i) + 0x10, tmp);
156 tmp = 0xffff0000 | (fp_dp & 0xffff);
157 write_virtual_dword(i->seg(), RMAddr(i) + 0x14, tmp);
158 tmp = (fp_dp & 0xffff0000) >> 4;
159 write_virtual_dword(i->seg(), RMAddr(i) + 0x18, tmp);
161 return 0x1c;
163 else /* Real or V86 Mode - 16 bit */
165 Bit16u tmp;
167 tmp = BX_CPU_THIS_PTR the_i387.get_control_word();
168 write_virtual_word(i->seg(), RMAddr(i), tmp);
169 tmp = BX_CPU_THIS_PTR the_i387.get_status_word();
170 write_virtual_word(i->seg(), RMAddr(i) + 0x02, tmp);
171 tmp = BX_CPU_THIS_PTR the_i387.get_tag_word();
172 write_virtual_word(i->seg(), RMAddr(i) + 0x04, tmp);
173 tmp = fp_ip & 0xffff;
174 write_virtual_word(i->seg(), RMAddr(i) + 0x06, tmp);
175 tmp = (Bit16u)((fp_ip & 0xf0000) >> 4) | BX_CPU_THIS_PTR the_i387.foo;
176 write_virtual_word(i->seg(), RMAddr(i) + 0x08, tmp);
177 tmp = fp_dp & 0xffff;
178 write_virtual_word(i->seg(), RMAddr(i) + 0x0a, tmp);
179 tmp = (Bit16u)((fp_dp & 0xf0000) >> 4);
180 write_virtual_word(i->seg(), RMAddr(i) + 0x0c, tmp);
182 return 0x0e;
187 int BX_CPU_C::fpu_load_environment(bxInstruction_c *i)
189 int offset;
191 BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
193 if (protected_mode()) /* Protected Mode */
195 if (i->os32L() || i->os64L())
197 Bit32u tmp;
199 tmp = read_virtual_dword(i->seg(), RMAddr(i));
200 BX_CPU_THIS_PTR the_i387.cwd = tmp & 0xffff;
201 tmp = read_virtual_dword(i->seg(), RMAddr(i) + 0x04);
202 BX_CPU_THIS_PTR the_i387.swd = tmp & 0xffff;
203 BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x07;
204 tmp = read_virtual_dword(i->seg(), RMAddr(i) + 0x08);
205 BX_CPU_THIS_PTR the_i387.twd = tmp & 0xffff;
206 tmp = read_virtual_dword(i->seg(), RMAddr(i) + 0x0c);
207 BX_CPU_THIS_PTR the_i387.fip = tmp;
208 tmp = read_virtual_dword(i->seg(), RMAddr(i) + 0x10);
209 BX_CPU_THIS_PTR the_i387.fcs = tmp & 0xffff;
210 BX_CPU_THIS_PTR the_i387.foo = (tmp >> 16) & 0x07ff;
211 tmp = read_virtual_dword(i->seg(), RMAddr(i) + 0x14);
212 BX_CPU_THIS_PTR the_i387.fdp = tmp;
213 tmp = read_virtual_dword(i->seg(), RMAddr(i) + 0x18);
214 BX_CPU_THIS_PTR the_i387.fds = tmp & 0xffff;
215 offset = 0x1c;
217 else /* Protected Mode - 16 bit */
219 Bit16u tmp;
221 tmp = read_virtual_word(i->seg(), RMAddr(i));
222 BX_CPU_THIS_PTR the_i387.cwd = tmp;
223 tmp = read_virtual_word(i->seg(), RMAddr(i) + 0x2);
224 BX_CPU_THIS_PTR the_i387.swd = tmp;
225 BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x07;
226 tmp = read_virtual_word(i->seg(), RMAddr(i) + 0x04);
227 BX_CPU_THIS_PTR the_i387.twd = tmp;
228 tmp = read_virtual_word(i->seg(), RMAddr(i) + 0x06);
229 BX_CPU_THIS_PTR the_i387.fip = tmp & 0xffff;
230 tmp = read_virtual_word(i->seg(), RMAddr(i) + 0x08);
231 BX_CPU_THIS_PTR the_i387.fcs = tmp;
232 tmp = read_virtual_word(i->seg(), RMAddr(i) + 0x0a);
233 BX_CPU_THIS_PTR the_i387.fdp = tmp & 0xffff;
234 tmp = read_virtual_word(i->seg(), RMAddr(i) + 0x0c);
235 BX_CPU_THIS_PTR the_i387.fds = tmp;
236 /* opcode is defined to be zero */
237 BX_CPU_THIS_PTR the_i387.foo = 0;
238 offset = 0x0e;
241 else /* Real or V86 Mode */
243 Bit32u fp_ip = 0, fp_dp = 0;
245 if (i->os32L() || i->os64L())
247 Bit32u tmp;
249 tmp = read_virtual_dword(i->seg(), RMAddr(i));
250 BX_CPU_THIS_PTR the_i387.cwd = tmp & 0xffff;
251 tmp = read_virtual_dword(i->seg(), RMAddr(i) + 0x04);
252 BX_CPU_THIS_PTR the_i387.swd = tmp & 0xffff;
253 BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x07;
254 tmp = read_virtual_dword(i->seg(), RMAddr(i) + 0x08);
255 BX_CPU_THIS_PTR the_i387.twd = tmp & 0xffff;
256 tmp = read_virtual_dword(i->seg(), RMAddr(i) + 0x0c);
257 fp_ip = tmp & 0xffff;
258 tmp = read_virtual_dword(i->seg(), RMAddr(i) + 0x10);
259 fp_ip = fp_ip | ((tmp & 0x0ffff000) << 4);
260 BX_CPU_THIS_PTR the_i387.fip = fp_ip;
261 BX_CPU_THIS_PTR the_i387.foo = tmp & 0x07ff;
262 BX_CPU_THIS_PTR the_i387.fcs = 0;
263 tmp = read_virtual_dword(i->seg(), RMAddr(i) + 0x14);
264 fp_dp = tmp & 0xffff;
265 tmp = read_virtual_dword(i->seg(), RMAddr(i) + 0x18);
266 fp_dp = fp_dp | ((tmp & 0x0ffff000) << 4);
267 BX_CPU_THIS_PTR the_i387.fdp = fp_dp;
268 BX_CPU_THIS_PTR the_i387.fds = 0;
269 offset = 0x1c;
271 else /* Real or V86 Mode - 16 bit */
273 Bit16u tmp;
275 tmp = read_virtual_word(i->seg(), RMAddr(i));
276 BX_CPU_THIS_PTR the_i387.cwd = tmp;
277 tmp = read_virtual_word(i->seg(), RMAddr(i) + 0x2);
278 BX_CPU_THIS_PTR the_i387.swd = tmp;
279 BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x07;
280 tmp = read_virtual_word(i->seg(), RMAddr(i) + 0x04);
281 BX_CPU_THIS_PTR the_i387.twd = tmp;
282 tmp = read_virtual_word(i->seg(), RMAddr(i) + 0x06);
283 fp_ip = tmp & 0xffff;
284 tmp = read_virtual_word(i->seg(), RMAddr(i) + 0x08);
285 fp_ip = fp_ip | ((tmp & 0xf000) << 4);
286 BX_CPU_THIS_PTR the_i387.fip = fp_ip;
287 BX_CPU_THIS_PTR the_i387.foo = tmp & 0x07ff;
288 BX_CPU_THIS_PTR the_i387.fcs = 0;
289 tmp = read_virtual_word(i->seg(), RMAddr(i) + 0x0a);
290 fp_dp = tmp & 0xffff;
291 tmp = read_virtual_word(i->seg(), RMAddr(i) + 0x0c);
292 fp_dp = fp_dp | ((tmp & 0xf000) << 4);
293 BX_CPU_THIS_PTR the_i387.fdp = fp_dp;
294 BX_CPU_THIS_PTR the_i387.fds = 0;
295 offset = 0x0e;
299 /* always set bit 6 - reserved */
300 BX_CPU_THIS_PTR the_i387.cwd |= 0x0040;
302 /* check for unmasked exceptions */
303 if (FPU_PARTIAL_STATUS & ~FPU_CONTROL_WORD & FPU_CW_Exceptions_Mask)
305 /* set the B and ES bits in the status-word */
306 FPU_PARTIAL_STATUS |= FPU_SW_Summary | FPU_SW_Backward;
308 else
310 /* clear the B and ES bits in the status-word */
311 FPU_PARTIAL_STATUS &= ~(FPU_SW_Summary | FPU_SW_Backward);
314 return offset;
317 /* D9 /5 */
318 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDCW(bxInstruction_c *i)
320 #if BX_SUPPORT_FPU
321 BX_CPU_THIS_PTR prepareFPU(i, CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
323 BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
325 Bit16u cwd = read_virtual_word(i->seg(), RMAddr(i));
326 FPU_CONTROL_WORD = cwd | 0x0040; // bit 6 is reserved - always set
328 /* check for unmasked exceptions */
329 if (FPU_PARTIAL_STATUS & ~FPU_CONTROL_WORD & FPU_CW_Exceptions_Mask)
331 /* set the B and ES bits in the status-word */
332 FPU_PARTIAL_STATUS |= FPU_SW_Summary | FPU_SW_Backward;
334 else
336 /* clear the B and ES bits in the status-word */
337 FPU_PARTIAL_STATUS &= ~(FPU_SW_Summary | FPU_SW_Backward);
339 #else
340 BX_INFO(("FLDCW: required FPU, configure --enable-fpu"));
341 #endif
344 /* D9 /7 */
345 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTCW(bxInstruction_c *i)
347 #if BX_SUPPORT_FPU
348 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
350 Bit16u cwd = BX_CPU_THIS_PTR the_i387.get_control_word();
352 BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
354 write_virtual_word(i->seg(), RMAddr(i), cwd);
355 #else
356 BX_INFO(("FNSTCW: required FPU, configure --enable-fpu"));
357 #endif
360 /* DD /7 */
361 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTSW(bxInstruction_c *i)
363 #if BX_SUPPORT_FPU
364 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
366 Bit16u swd = BX_CPU_THIS_PTR the_i387.get_status_word();
368 BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
370 write_virtual_word(i->seg(), RMAddr(i), swd);
371 #else
372 BX_INFO(("FNSTSW: required FPU, configure --enable-fpu"));
373 #endif
376 /* DF E0 */
377 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTSW_AX(bxInstruction_c *i)
379 #if BX_SUPPORT_FPU
380 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
381 AX = BX_CPU_THIS_PTR the_i387.get_status_word();
382 #else
383 BX_INFO(("FNSTSW_AX: required FPU, configure --enable-fpu"));
384 #endif
387 /* DD /4 */
388 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FRSTOR(bxInstruction_c *i)
390 #if BX_SUPPORT_FPU
391 BX_CPU_THIS_PTR prepareFPU(i, CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
393 int offset = fpu_load_environment(i);
394 floatx80 tmp;
396 /* read all registers in stack order */
397 for(int n=0;n<8;n++)
399 read_virtual_tword(i->seg(), RMAddr(i) + offset + n*10, &tmp);
400 // update tag only if it is not empty
401 BX_WRITE_FPU_REGISTER_AND_TAG(tmp,
402 IS_TAG_EMPTY(n) ? FPU_Tag_Empty : FPU_tagof(tmp), n);
404 #else
405 BX_INFO(("FRSTOR: required FPU, configure --enable-fpu"));
406 #endif
409 /* DD /6 */
410 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSAVE(bxInstruction_c *i)
412 #if BX_SUPPORT_FPU
413 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
415 int offset = fpu_save_environment(i);
417 /* save all registers in stack order. */
418 for(int n=0;n<8;n++)
420 floatx80 stn = BX_READ_FPU_REG(n);
421 write_virtual_tword(i->seg(), RMAddr(i) + offset + n*10, &stn);
424 BX_CPU_THIS_PTR the_i387.init();
425 #else
426 BX_INFO(("FNSAVE: required FPU, configure --enable-fpu"));
427 #endif
430 /* 9B E2 */
431 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNCLEX(bxInstruction_c *i)
433 #if BX_SUPPORT_FPU
434 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
436 FPU_PARTIAL_STATUS &= ~(FPU_SW_Backward|FPU_SW_Summary|FPU_SW_Stack_Fault|FPU_SW_Precision|
437 FPU_SW_Underflow|FPU_SW_Overflow|FPU_SW_Zero_Div|FPU_SW_Denormal_Op|
438 FPU_SW_Invalid);
440 // do not update last fpu instruction pointer
441 #else
442 BX_INFO(("FNCLEX: required FPU, configure --enable-fpu"));
443 #endif
446 /* DB E3 */
447 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNINIT(bxInstruction_c *i)
449 #if BX_SUPPORT_FPU
450 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
451 BX_CPU_THIS_PTR the_i387.init();
452 #else
453 BX_INFO(("FNINIT: required FPU, configure --enable-fpu"));
454 #endif
457 /* D9 /4 */
458 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDENV(bxInstruction_c *i)
460 #if BX_SUPPORT_FPU
461 BX_CPU_THIS_PTR prepareFPU(i, CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
462 fpu_load_environment(i);
464 /* read all registers in stack order */
465 for(int n=0;n<8;n++)
467 // update tag only if it is not empty
468 if (! IS_TAG_EMPTY(n))
470 int tag = FPU_tagof(BX_READ_FPU_REG(n));
471 BX_CPU_THIS_PTR the_i387.FPU_settagi(tag, n);
474 #else
475 BX_INFO(("FLDENV: required FPU, configure --enable-fpu"));
476 #endif
479 /* D9 /6 */
480 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTENV(bxInstruction_c *i)
482 #if BX_SUPPORT_FPU
483 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
484 fpu_save_environment(i);
485 /* mask all floating point exceptions */
486 FPU_CONTROL_WORD |= FPU_CW_Exceptions_Mask;
487 /* clear the B and ES bits in the status word */
488 FPU_PARTIAL_STATUS &= ~(FPU_SW_Backward|FPU_SW_Summary);
489 #else
490 BX_INFO(("FNSTENV: required FPU, configure --enable-fpu"));
491 #endif
494 /* D9 D0 */
495 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNOP(bxInstruction_c *i)
497 #if BX_SUPPORT_FPU
498 BX_CPU_THIS_PTR prepareFPU(i, CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
500 // Perform no FPU operation. This instruction takes up space in the
501 // instruction stream but does not affect the FPU or machine
502 // context, except the EIP register.
503 #else
504 BX_INFO(("FNOP: required FPU, configure --enable-fpu"));
505 #endif
508 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPLEGACY(bxInstruction_c *i)
510 #if BX_SUPPORT_FPU
511 BX_CPU_THIS_PTR prepareFPU(i, !CHECK_PENDING_EXCEPTIONS, !UPDATE_LAST_OPCODE);
513 // FPU performs no specific operation and no internal x87 states
514 // are affected
515 #else
516 BX_INFO(("legacy FPU opcodes: required FPU, configure --enable-fpu"));
517 #endif
520 #endif
522 #if BX_SUPPORT_FPU
524 #include <math.h>
526 void BX_CPU_C::print_state_FPU(void)
528 static double scale_factor = pow(2.0, -63.0);
530 Bit32u reg;
531 reg = BX_CPU_THIS_PTR the_i387.get_control_word();
532 fprintf(stderr, "control word: 0x%04x\n", reg);
533 reg = BX_CPU_THIS_PTR the_i387.get_status_word();
534 fprintf(stderr, "status word: 0x%04x\n", reg);
535 fprintf(stderr, " TOS : %d\n", FPU_TOS&7);
536 reg = BX_CPU_THIS_PTR the_i387.get_tag_word();
537 fprintf(stderr, "tag word: 0x%04x\n", reg);
538 reg = BX_CPU_THIS_PTR the_i387.foo;
539 fprintf(stderr, "operand: 0x%04x\n", reg);
540 reg = (Bit32u)(BX_CPU_THIS_PTR the_i387.fip) & 0xffffffff;
541 fprintf(stderr, "fip: 0x%08x\n", reg);
542 reg = BX_CPU_THIS_PTR the_i387.fcs;
543 fprintf(stderr, "fcs: 0x%04x\n", reg);
544 reg = (Bit32u)(BX_CPU_THIS_PTR the_i387.fdp) & 0xffffffff;
545 fprintf(stderr, "fdp: 0x%08x\n", reg);
546 reg = BX_CPU_THIS_PTR the_i387.fds;
547 fprintf(stderr, "fds: 0x%04x\n", reg);
549 // print stack too
550 int tos = FPU_TOS & 7;
551 for (int i=0; i<8; i++) {
552 const floatx80 &fp = BX_FPU_REG(i);
553 double f = pow(2.0, ((0x7fff & fp.exp) - 0x3fff));
554 if (fp.exp & 0x8000) f = -f;
555 #ifdef _MSC_VER
556 f *= (double)(signed __int64)(fp.fraction>>1) * scale_factor * 2;
557 #else
558 f *= fp.fraction*scale_factor;
559 #endif
560 fprintf(stderr, "%sFPR%d(%c): raw 0x%04x:%08lx%08lx (%.10f)\n",
561 i==tos?"=>":" ",
563 "v0se"[BX_CPU_THIS_PTR the_i387.FPU_gettagi((i-tos)&7)],
564 fp.exp & 0xffff, GET32H(fp.fraction), GET32L(fp.fraction),
568 #endif