1 /////////////////////////////////////////////////////////////////////////
2 // $Id: fpu.cc,v 1.48 2008/09/18 19:10:23 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 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.
69 if (BX_CPU_THIS_PTR cr0
.get_NE() != 0) {
70 exception(BX_MF_EXCEPTION
, 0, 0);
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
)
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())
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
);
121 else /* Protected Mode - 16 bit */
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
);
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
);
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
);
171 else /* Real or V86 Mode - 16 bit */
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
);
194 return (eaddr
+ offset
);
197 bx_address
BX_CPU_C::fpu_load_environment(bxInstruction_c
*i
)
201 bx_address eaddr
= BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
203 if (protected_mode()) /* Protected Mode */
205 if (i
->os32L() || i
->os64L())
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;
227 else /* Protected Mode - 16 bit */
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;
251 else /* Real or V86 Mode */
253 Bit32u fp_ip
= 0, fp_dp
= 0;
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;
281 else /* Real or V86 Mode - 16 bit */
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;
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
;
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
);
329 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDCW(bxInstruction_c
*i
)
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
;
347 /* clear the B and ES bits in the status-word */
348 FPU_PARTIAL_STATUS
&= ~(FPU_SW_Summary
| FPU_SW_Backward
);
351 BX_INFO(("FLDCW: required FPU, configure --enable-fpu"));
356 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTCW(bxInstruction_c
*i
)
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
);
367 BX_INFO(("FNSTCW: required FPU, configure --enable-fpu"));
372 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTSW(bxInstruction_c
*i
)
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
);
383 BX_INFO(("FNSTSW: required FPU, configure --enable-fpu"));
388 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTSW_AX(bxInstruction_c
*i
)
391 BX_CPU_THIS_PTR
prepareFPU(i
, !CHECK_PENDING_EXCEPTIONS
, !UPDATE_LAST_OPCODE
);
392 AX
= BX_CPU_THIS_PTR the_i387
.get_status_word();
394 BX_INFO(("FNSTSW_AX: required FPU, configure --enable-fpu"));
399 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FRSTOR(bxInstruction_c
*i
)
402 BX_CPU_THIS_PTR
prepareFPU(i
, CHECK_PENDING_EXCEPTIONS
, !UPDATE_LAST_OPCODE
);
404 bx_address offset
= fpu_load_environment(i
);
407 /* read all registers in stack order */
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
);
418 BX_INFO(("FRSTOR: required FPU, configure --enable-fpu"));
423 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSAVE(bxInstruction_c
*i
)
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. */
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();
440 BX_INFO(("FNSAVE: required FPU, configure --enable-fpu"));
445 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNCLEX(bxInstruction_c
*i
)
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
|
454 // do not update last fpu instruction pointer
456 BX_INFO(("FNCLEX: required FPU, configure --enable-fpu"));
461 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNINIT(bxInstruction_c
*i
)
464 BX_CPU_THIS_PTR
prepareFPU(i
, !CHECK_PENDING_EXCEPTIONS
, !UPDATE_LAST_OPCODE
);
465 BX_CPU_THIS_PTR the_i387
.init();
467 BX_INFO(("FNINIT: required FPU, configure --enable-fpu"));
472 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDENV(bxInstruction_c
*i
)
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
);
487 BX_INFO(("FLDENV: required FPU, configure --enable-fpu"));
492 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTENV(bxInstruction_c
*i
)
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
);
502 BX_INFO(("FNSTENV: required FPU, configure --enable-fpu"));
507 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNOP(bxInstruction_c
*i
)
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.
516 BX_INFO(("FNOP: required FPU, configure --enable-fpu"));
520 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPLEGACY(bxInstruction_c
*i
)
523 BX_CPU_THIS_PTR
prepareFPU(i
, !CHECK_PENDING_EXCEPTIONS
, !UPDATE_LAST_OPCODE
);
525 // FPU performs no specific operation and no internal x87 states
528 BX_INFO(("legacy FPU opcodes: required FPU, configure --enable-fpu"));
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"
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
);
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
;
601 f
*= (double)(signed __int64
)(fp
.fraction
>>1) * scale_factor
* 2;
603 f
*= fp
.fraction
*scale_factor
;
605 fprintf(stderr
, "%sFP%d ST%d(%c): raw 0x%04x:%08lx%08lx (%.10f)\n",
606 i
==tos
?"=>":" ", i
, (i
-tos
)&7,
608 fp
.exp
& 0xffff, GET32H(fp
.fraction
), GET32L(fp
.fraction
),