1 /////////////////////////////////////////////////////////////////////////
2 // $Id: fpu.cc,v 1.39 2008/04/30 20:41:15 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (c) 2003 Stanislav Shwartsman
6 // Written by Stanislav Shwartsman [sshwarts at sourceforge net]
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
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
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
;
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
);
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.
72 if (BX_CPU_THIS_PTR cr0
.get_NE() != 0) {
73 exception(BX_MF_EXCEPTION
, 0, 0);
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())
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
);
113 else /* Protected Mode - 16 bit */
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
);
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())
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
);
163 else /* Real or V86 Mode - 16 bit */
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
);
187 int BX_CPU_C::fpu_load_environment(bxInstruction_c
*i
)
191 BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
193 if (protected_mode()) /* Protected Mode */
195 if (i
->os32L() || i
->os64L())
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;
217 else /* Protected Mode - 16 bit */
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;
241 else /* Real or V86 Mode */
243 Bit32u fp_ip
= 0, fp_dp
= 0;
245 if (i
->os32L() || i
->os64L())
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;
271 else /* Real or V86 Mode - 16 bit */
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;
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
;
310 /* clear the B and ES bits in the status-word */
311 FPU_PARTIAL_STATUS
&= ~(FPU_SW_Summary
| FPU_SW_Backward
);
318 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDCW(bxInstruction_c
*i
)
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
;
336 /* clear the B and ES bits in the status-word */
337 FPU_PARTIAL_STATUS
&= ~(FPU_SW_Summary
| FPU_SW_Backward
);
340 BX_INFO(("FLDCW: required FPU, configure --enable-fpu"));
345 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTCW(bxInstruction_c
*i
)
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
);
356 BX_INFO(("FNSTCW: required FPU, configure --enable-fpu"));
361 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTSW(bxInstruction_c
*i
)
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
);
372 BX_INFO(("FNSTSW: required FPU, configure --enable-fpu"));
377 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTSW_AX(bxInstruction_c
*i
)
380 BX_CPU_THIS_PTR
prepareFPU(i
, !CHECK_PENDING_EXCEPTIONS
, !UPDATE_LAST_OPCODE
);
381 AX
= BX_CPU_THIS_PTR the_i387
.get_status_word();
383 BX_INFO(("FNSTSW_AX: required FPU, configure --enable-fpu"));
388 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FRSTOR(bxInstruction_c
*i
)
391 BX_CPU_THIS_PTR
prepareFPU(i
, CHECK_PENDING_EXCEPTIONS
, !UPDATE_LAST_OPCODE
);
393 int offset
= fpu_load_environment(i
);
396 /* read all registers in stack order */
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
);
405 BX_INFO(("FRSTOR: required FPU, configure --enable-fpu"));
410 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSAVE(bxInstruction_c
*i
)
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. */
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();
426 BX_INFO(("FNSAVE: required FPU, configure --enable-fpu"));
431 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNCLEX(bxInstruction_c
*i
)
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
|
440 // do not update last fpu instruction pointer
442 BX_INFO(("FNCLEX: required FPU, configure --enable-fpu"));
447 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNINIT(bxInstruction_c
*i
)
450 BX_CPU_THIS_PTR
prepareFPU(i
, !CHECK_PENDING_EXCEPTIONS
, !UPDATE_LAST_OPCODE
);
451 BX_CPU_THIS_PTR the_i387
.init();
453 BX_INFO(("FNINIT: required FPU, configure --enable-fpu"));
458 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDENV(bxInstruction_c
*i
)
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 */
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
);
475 BX_INFO(("FLDENV: required FPU, configure --enable-fpu"));
480 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTENV(bxInstruction_c
*i
)
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
);
490 BX_INFO(("FNSTENV: required FPU, configure --enable-fpu"));
495 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNOP(bxInstruction_c
*i
)
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.
504 BX_INFO(("FNOP: required FPU, configure --enable-fpu"));
508 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPLEGACY(bxInstruction_c
*i
)
511 BX_CPU_THIS_PTR
prepareFPU(i
, !CHECK_PENDING_EXCEPTIONS
, !UPDATE_LAST_OPCODE
);
513 // FPU performs no specific operation and no internal x87 states
516 BX_INFO(("legacy FPU opcodes: required FPU, configure --enable-fpu"));
526 void BX_CPU_C::print_state_FPU(void)
528 static double scale_factor
= pow(2.0, -63.0);
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
);
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
;
556 f
*= (double)(signed __int64
)(fp
.fraction
>>1) * scale_factor
* 2;
558 f
*= fp
.fraction
*scale_factor
;
560 fprintf(stderr
, "%sFPR%d(%c): raw 0x%04x:%08lx%08lx (%.10f)\n",
563 "v0se"[BX_CPU_THIS_PTR the_i387
.FPU_gettagi((i
-tos
)&7)],
564 fp
.exp
& 0xffff, GET32H(fp
.fraction
), GET32L(fp
.fraction
),