1 /////////////////////////////////////////////////////////////////////////
2 // $Id: fpu_compare.cc,v 1.18 2008/07/13 15:35:10 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 /////////////////////////////////////////////////////////////////////////
24 #define NEED_CPU_REG_SHORTCUTS 1
27 #define LOG_THIS BX_CPU_THIS_PTR
31 extern float_status_t
FPU_pre_exception_handling(Bit16u control_word
);
33 #include "softfloatx80.h"
35 static int status_word_flags_fpu_compare(int float_relation
)
37 switch(float_relation
) {
38 case float_relation_unordered
:
39 return (FPU_SW_C0
|FPU_SW_C2
|FPU_SW_C3
);
41 case float_relation_greater
:
44 case float_relation_less
:
47 case float_relation_equal
:
51 return (-1); // should never get here
54 #if BX_SUPPORT_FPU || BX_SUPPORT_SSE >= 1
55 void BX_CPU_C::write_eflags_fpu_compare(int float_relation
)
57 switch(float_relation
) {
58 case float_relation_unordered
:
59 setEFlagsOSZAPC(EFlagsZFMask
| EFlagsPFMask
| EFlagsCFMask
);
62 case float_relation_greater
:
66 case float_relation_less
:
67 setEFlagsOSZAPC(EFlagsCFMask
);
70 case float_relation_equal
:
71 setEFlagsOSZAPC(EFlagsZFMask
);
75 BX_PANIC(("write_eflags: unknown floating point compare relation"));
80 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOM_STi(bxInstruction_c
*i
)
83 BX_CPU_THIS_PTR
prepareFPU(i
);
85 int pop_stack
= i
->nnn() & 1;
86 // handle special case of FSTP opcode @ 0xDE 0xD0..D7
92 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(i
->rm()))
94 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
96 if(BX_CPU_THIS_PTR the_i387
.is_IA_masked())
98 /* the masked response */
99 setcc(FPU_SW_C0
|FPU_SW_C2
|FPU_SW_C3
);
101 BX_CPU_THIS_PTR the_i387
.FPU_pop();
106 float_status_t status
=
107 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
109 int rc
= floatx80_compare(BX_READ_FPU_REG(0), BX_READ_FPU_REG(i
->rm()), status
);
111 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
114 setcc(status_word_flags_fpu_compare(rc
));
117 BX_CPU_THIS_PTR the_i387
.FPU_pop();
119 BX_INFO(("FCOM(P)_STi: required FPU, configure --enable-fpu"));
123 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOMI_ST0_STj(bxInstruction_c
*i
)
125 #if (BX_CPU_LEVEL >= 6) || (BX_CPU_LEVEL_HACKED >= 6)
126 BX_CPU_THIS_PTR
prepareFPU(i
);
128 int pop_stack
= i
->b1() & 4;
132 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(i
->rm()))
134 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
136 if(BX_CPU_THIS_PTR the_i387
.is_IA_masked())
138 /* the masked response */
139 setEFlagsOSZAPC(EFlagsZFMask
| EFlagsPFMask
| EFlagsCFMask
);
141 BX_CPU_THIS_PTR the_i387
.FPU_pop();
146 float_status_t status
=
147 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
149 int rc
= floatx80_compare(BX_READ_FPU_REG(0), BX_READ_FPU_REG(i
->rm()), status
);
151 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
154 BX_CPU_THIS_PTR
write_eflags_fpu_compare(rc
);
157 BX_CPU_THIS_PTR the_i387
.FPU_pop();
159 BX_INFO(("FCOMI(P)_ST0_STj: required P6 FPU, configure --enable-fpu, cpu-level=6"));
160 exception(BX_UD_EXCEPTION
, 0, 0);
164 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FUCOMI_ST0_STj(bxInstruction_c
*i
)
166 #if (BX_CPU_LEVEL >= 6) || (BX_CPU_LEVEL_HACKED >= 6)
167 BX_CPU_THIS_PTR
prepareFPU(i
);
169 int pop_stack
= i
->b1() & 4;
173 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(i
->rm()))
175 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
177 if(BX_CPU_THIS_PTR the_i387
.is_IA_masked())
179 /* the masked response */
180 setEFlagsOSZAPC(EFlagsZFMask
| EFlagsPFMask
| EFlagsCFMask
);
182 BX_CPU_THIS_PTR the_i387
.FPU_pop();
187 float_status_t status
=
188 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
190 int rc
= floatx80_compare_quiet(BX_READ_FPU_REG(0), BX_READ_FPU_REG(i
->rm()), status
);
192 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
195 BX_CPU_THIS_PTR
write_eflags_fpu_compare(rc
);
198 BX_CPU_THIS_PTR the_i387
.FPU_pop();
200 BX_INFO(("FUCOMI(P)_ST0_STj: required P6 FPU, configure --enable-fpu, cpu-level=6"));
201 exception(BX_UD_EXCEPTION
, 0, 0);
205 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FUCOM_STi(bxInstruction_c
*i
)
208 BX_CPU_THIS_PTR
prepareFPU(i
);
210 int pop_stack
= i
->nnn() & 1;
212 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(i
->rm()))
214 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
216 if(BX_CPU_THIS_PTR the_i387
.is_IA_masked())
218 /* the masked response */
219 setcc(FPU_SW_C0
|FPU_SW_C2
|FPU_SW_C3
);
221 BX_CPU_THIS_PTR the_i387
.FPU_pop();
226 float_status_t status
=
227 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
229 int rc
= floatx80_compare_quiet(BX_READ_FPU_REG(0), BX_READ_FPU_REG(i
->rm()), status
);
231 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
234 setcc(status_word_flags_fpu_compare(rc
));
237 BX_CPU_THIS_PTR the_i387
.FPU_pop();
239 BX_INFO(("FUCOM(P)_STi: required FPU, configure --enable-fpu"));
243 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOM_SINGLE_REAL(bxInstruction_c
*i
)
246 BX_CPU_THIS_PTR
prepareFPU(i
);
248 int pop_stack
= i
->nnn() & 1;
250 float32 load_reg
= read_virtual_dword(i
->seg(), RMAddr(i
));
256 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
258 if(BX_CPU_THIS_PTR the_i387
.is_IA_masked())
260 /* the masked response */
261 setcc(FPU_SW_C0
|FPU_SW_C2
|FPU_SW_C3
);
263 BX_CPU_THIS_PTR the_i387
.FPU_pop();
268 float_status_t status
=
269 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
271 int rc
= floatx80_compare(BX_READ_FPU_REG(0),
272 float32_to_floatx80(load_reg
, status
), status
);
274 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
277 setcc(status_word_flags_fpu_compare(rc
));
280 BX_CPU_THIS_PTR the_i387
.FPU_pop();
282 BX_INFO(("FCOM(P)_SINGLE_REAL: required FPU, configure --enable-fpu"));
286 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOM_DOUBLE_REAL(bxInstruction_c
*i
)
289 BX_CPU_THIS_PTR
prepareFPU(i
);
291 int pop_stack
= i
->nnn() & 1;
293 float64 load_reg
= read_virtual_qword(i
->seg(), RMAddr(i
));
299 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
301 if(BX_CPU_THIS_PTR the_i387
.is_IA_masked())
303 /* the masked response */
304 setcc(FPU_SW_C0
|FPU_SW_C2
|FPU_SW_C3
);
306 BX_CPU_THIS_PTR the_i387
.FPU_pop();
311 float_status_t status
=
312 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
314 int rc
= floatx80_compare(BX_READ_FPU_REG(0),
315 float64_to_floatx80(load_reg
, status
), status
);
317 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
320 setcc(status_word_flags_fpu_compare(rc
));
323 BX_CPU_THIS_PTR the_i387
.FPU_pop();
325 BX_INFO(("FCOM(P)_DOUBLE_REAL: required FPU, configure --enable-fpu"));
329 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FICOM_WORD_INTEGER(bxInstruction_c
*i
)
332 BX_CPU_THIS_PTR
prepareFPU(i
);
334 int pop_stack
= i
->nnn() & 1;
336 Bit16s load_reg
= (Bit16s
) read_virtual_word(i
->seg(), RMAddr(i
));
342 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
344 if(BX_CPU_THIS_PTR the_i387
.is_IA_masked())
346 /* the masked response */
347 setcc(FPU_SW_C0
|FPU_SW_C2
|FPU_SW_C3
);
349 BX_CPU_THIS_PTR the_i387
.FPU_pop();
354 float_status_t status
=
355 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
357 int rc
= floatx80_compare(BX_READ_FPU_REG(0),
358 int32_to_floatx80((Bit32s
)(load_reg
)), status
);
360 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
363 setcc(status_word_flags_fpu_compare(rc
));
366 BX_CPU_THIS_PTR the_i387
.FPU_pop();
368 BX_INFO(("FICOM(P)_WORD_INTEGER: required FPU, configure --enable-fpu"));
372 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FICOM_DWORD_INTEGER(bxInstruction_c
*i
)
375 BX_CPU_THIS_PTR
prepareFPU(i
);
377 int pop_stack
= i
->nnn() & 1;
379 Bit32s load_reg
= (Bit32s
) read_virtual_dword(i
->seg(), RMAddr(i
));
385 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
387 if(BX_CPU_THIS_PTR the_i387
.is_IA_masked())
389 /* the masked response */
390 setcc(FPU_SW_C0
|FPU_SW_C2
|FPU_SW_C3
);
392 BX_CPU_THIS_PTR the_i387
.FPU_pop();
397 float_status_t status
=
398 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
400 int rc
= floatx80_compare(BX_READ_FPU_REG(0),
401 int32_to_floatx80(load_reg
), status
);
403 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
406 setcc(status_word_flags_fpu_compare(rc
));
409 BX_CPU_THIS_PTR the_i387
.FPU_pop();
411 BX_INFO(("FICOM(P)_DWORD_INTEGER: required FPU, configure --enable-fpu"));
416 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOMPP(bxInstruction_c
*i
)
419 BX_CPU_THIS_PTR
prepareFPU(i
);
423 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
425 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
427 if(BX_CPU_THIS_PTR the_i387
.is_IA_masked())
429 /* the masked response */
430 setcc(FPU_SW_C0
|FPU_SW_C2
|FPU_SW_C3
);
432 BX_CPU_THIS_PTR the_i387
.FPU_pop();
433 BX_CPU_THIS_PTR the_i387
.FPU_pop();
438 float_status_t status
=
439 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
441 int rc
= floatx80_compare(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status
);
443 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
446 setcc(status_word_flags_fpu_compare(rc
));
448 BX_CPU_THIS_PTR the_i387
.FPU_pop();
449 BX_CPU_THIS_PTR the_i387
.FPU_pop();
451 BX_INFO(("FCOMPP: required FPU, configure --enable-fpu"));
456 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FUCOMPP(bxInstruction_c
*i
)
459 BX_CPU_THIS_PTR
prepareFPU(i
);
461 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
463 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
465 if(BX_CPU_THIS_PTR the_i387
.is_IA_masked())
467 /* the masked response */
468 setcc(FPU_SW_C0
|FPU_SW_C2
|FPU_SW_C3
);
470 BX_CPU_THIS_PTR the_i387
.FPU_pop();
471 BX_CPU_THIS_PTR the_i387
.FPU_pop();
476 float_status_t status
=
477 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
479 int rc
= floatx80_compare_quiet(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status
);
481 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
484 setcc(status_word_flags_fpu_compare(rc
));
486 BX_CPU_THIS_PTR the_i387
.FPU_pop();
487 BX_CPU_THIS_PTR the_i387
.FPU_pop();
489 BX_INFO(("FUCOMPP: required FPU, configure --enable-fpu"));
493 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCMOV_ST0_STj(bxInstruction_c
*i
)
495 #if (BX_CPU_LEVEL >= 6) || (BX_CPU_LEVEL_HACKED >= 6)
496 BX_CPU_THIS_PTR
prepareFPU(i
);
498 if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(i
->rm()))
500 BX_CPU_THIS_PTR
FPU_stack_underflow(0);
504 floatx80 sti_reg
= BX_READ_FPU_REG(i
->rm());
506 bx_bool condition
= 0;
509 case 0: condition
= get_CF(); break;
510 case 1: condition
= get_ZF(); break;
511 case 2: condition
= get_CF() || get_ZF(); break;
512 case 3: condition
= get_PF(); break;
514 BX_PANIC(("FCMOV_ST0_STj: default case"));
517 condition
= !condition
;
520 BX_WRITE_FPU_REG(sti_reg
, 0);
523 BX_INFO(("FCMOV_ST0_STj: required P6 FPU, configure --enable-fpu, cpu-level=6"));
524 exception(BX_UD_EXCEPTION
, 0, 0);
529 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FTST(bxInstruction_c
*i
)
532 BX_CPU_THIS_PTR
prepareFPU(i
);
538 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
540 if(BX_CPU_THIS_PTR the_i387
.is_IA_masked())
542 /* the masked response */
543 setcc(FPU_SW_C0
|FPU_SW_C2
|FPU_SW_C3
);
548 extern const floatx80 Const_Z
;
550 float_status_t status
=
551 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
553 int rc
= floatx80_compare(BX_READ_FPU_REG(0), Const_Z
, status
);
555 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
558 setcc(status_word_flags_fpu_compare(rc
));
560 BX_INFO(("FTST: required FPU, configure --enable-fpu"));
565 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FXAM(bxInstruction_c
*i
)
568 BX_CPU_THIS_PTR
prepareFPU(i
);
570 floatx80 reg
= BX_READ_FPU_REG(0);
571 int sign
= floatx80_sign(reg
);
574 * Examine the contents of the ST(0) register and sets the condition
575 * code flags C0, C2 and C3 in the FPU status word to indicate the
576 * class of value or number in the register.
581 setcc(FPU_SW_C3
|FPU_SW_C1
|FPU_SW_C0
);
585 float_class_t aClass
= floatx80_class(reg
);
590 setcc(FPU_SW_C3
|FPU_SW_C1
);
594 // unsupported handled as NaNs
595 if (floatx80_is_unsupported(reg
)) {
598 setcc(FPU_SW_C1
|FPU_SW_C0
);
602 case float_negative_inf
:
603 case float_positive_inf
:
604 setcc(FPU_SW_C2
|FPU_SW_C1
|FPU_SW_C0
);
608 setcc(FPU_SW_C3
|FPU_SW_C2
|FPU_SW_C1
);
611 case float_normalized
:
612 setcc(FPU_SW_C2
|FPU_SW_C1
);
618 * The C1 flag is set to the sign of the value in ST(0), regardless
619 * of whether the register is empty or full.
625 BX_INFO(("FXAM: required FPU, configure --enable-fpu"));