1 /////////////////////////////////////////////////////////////////////////
2 // $Id: fpu_load_store.cc,v 1.29 2008/09/03 20:13:52 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 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_STi(bxInstruction_c
*i
)
38 BX_CPU_THIS_PTR
prepareFPU(i
);
42 if (! IS_TAG_EMPTY(-1))
44 BX_CPU_THIS_PTR
FPU_stack_overflow();
48 floatx80 sti_reg
= floatx80_default_nan
;
50 if (IS_TAG_EMPTY(i
->rm()))
52 FPU_exception(FPU_EX_Stack_Underflow
);
54 if (! BX_CPU_THIS_PTR the_i387
.is_IA_masked())
58 sti_reg
= BX_READ_FPU_REG(i
->rm());
61 BX_CPU_THIS_PTR the_i387
.FPU_push();
62 BX_WRITE_FPU_REG(sti_reg
, 0);
64 BX_INFO(("FLD_STi: required FPU, configure --enable-fpu"));
68 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_SINGLE_REAL(bxInstruction_c
*i
)
71 BX_CPU_THIS_PTR
prepareFPU(i
);
73 float32 load_reg
= read_virtual_dword(i
->seg(), RMAddr(i
));
77 if (! IS_TAG_EMPTY(-1)) {
78 BX_CPU_THIS_PTR
FPU_stack_overflow();
82 float_status_t status
=
83 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
85 // convert to floatx80 format
86 floatx80 result
= float32_to_floatx80(load_reg
, status
);
88 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
91 BX_CPU_THIS_PTR the_i387
.FPU_push();
92 BX_WRITE_FPU_REG(result
, 0);
94 BX_INFO(("FLD_SINGLE_REAL: required FPU, configure --enable-fpu"));
98 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_DOUBLE_REAL(bxInstruction_c
*i
)
101 BX_CPU_THIS_PTR
prepareFPU(i
);
103 float64 load_reg
= read_virtual_qword(i
->seg(), RMAddr(i
));
107 if (! IS_TAG_EMPTY(-1)) {
108 BX_CPU_THIS_PTR
FPU_stack_overflow();
112 float_status_t status
=
113 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
115 // convert to floatx80 format
116 floatx80 result
= float64_to_floatx80(load_reg
, status
);
118 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
121 BX_CPU_THIS_PTR the_i387
.FPU_push();
122 BX_WRITE_FPU_REG(result
, 0);
124 BX_INFO(("FLD_DOUBLE_REAL: required FPU, configure --enable-fpu"));
128 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_EXTENDED_REAL(bxInstruction_c
*i
)
131 BX_CPU_THIS_PTR
prepareFPU(i
);
134 result
.fraction
= read_virtual_qword(i
->seg(), RMAddr(i
));
135 result
.exp
= read_virtual_word (i
->seg(), RMAddr(i
)+8);
139 if (! IS_TAG_EMPTY(-1)) {
140 BX_CPU_THIS_PTR
FPU_stack_overflow();
144 BX_CPU_THIS_PTR the_i387
.FPU_push();
146 BX_WRITE_FPU_REG(result
, 0);
148 BX_INFO(("FLD_EXTENDED_REAL: required FPU, configure --enable-fpu"));
153 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_WORD_INTEGER(bxInstruction_c
*i
)
156 BX_CPU_THIS_PTR
prepareFPU(i
);
158 Bit16s load_reg
= (Bit16s
) read_virtual_word(i
->seg(), RMAddr(i
));
162 if (! IS_TAG_EMPTY(-1)) {
163 BX_CPU_THIS_PTR
FPU_stack_overflow();
167 floatx80 result
= int32_to_floatx80((Bit32s
) load_reg
);
168 BX_CPU_THIS_PTR the_i387
.FPU_push();
169 BX_WRITE_FPU_REG(result
, 0);
171 BX_INFO(("FILD_WORD_INTEGER: required FPU, configure --enable-fpu"));
176 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_DWORD_INTEGER(bxInstruction_c
*i
)
179 BX_CPU_THIS_PTR
prepareFPU(i
);
181 Bit32s load_reg
= (Bit32s
) read_virtual_dword(i
->seg(), RMAddr(i
));
185 if (! IS_TAG_EMPTY(-1)) {
186 BX_CPU_THIS_PTR
FPU_stack_overflow();
190 floatx80 result
= int32_to_floatx80(load_reg
);
191 BX_CPU_THIS_PTR the_i387
.FPU_push();
192 BX_WRITE_FPU_REG(result
, 0);
194 BX_INFO(("FILD_DWORD_INTEGER: required FPU, configure --enable-fpu"));
199 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_QWORD_INTEGER(bxInstruction_c
*i
)
202 BX_CPU_THIS_PTR
prepareFPU(i
);
204 Bit64s load_reg
= (Bit64s
) read_virtual_qword(i
->seg(), RMAddr(i
));
208 if (! IS_TAG_EMPTY(-1)) {
209 BX_CPU_THIS_PTR
FPU_stack_overflow();
213 floatx80 result
= int64_to_floatx80(load_reg
);
214 BX_CPU_THIS_PTR the_i387
.FPU_push();
215 BX_WRITE_FPU_REG(result
, 0);
217 BX_INFO(("FILD_QWORD_INTEGER: required FPU, configure --enable-fpu"));
222 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FBLD_PACKED_BCD(bxInstruction_c
*i
)
225 BX_CPU_THIS_PTR
prepareFPU(i
);
227 // read packed bcd from memory
228 Bit16u hi2
= read_virtual_word (i
->seg(), RMAddr(i
) + 8);
229 Bit64u lo8
= read_virtual_qword(i
->seg(), RMAddr(i
));
233 if (! IS_TAG_EMPTY(-1))
235 BX_CPU_THIS_PTR
FPU_stack_overflow();
239 // convert packed BCD to 64-bit integer
243 for (int n
= 0; n
< 16; n
++)
245 val64
+= (lo8
& 0x0f) * scale
;
250 val64
+= (hi2
& 0x0f) * scale
;
251 val64
+= ((hi2
>>4) & 0x0f) * scale
* 10;
253 floatx80 result
= int64_to_floatx80(val64
);
254 if (hi2
& 0x8000) // set negative
255 floatx80_chs(result
);
257 BX_CPU_THIS_PTR the_i387
.FPU_push();
258 BX_WRITE_FPU_REG(result
, 0);
260 BX_INFO(("FBLD_PACKED_BCD: required FPU, configure --enable-fpu"));
264 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_STi(bxInstruction_c
*i
)
267 BX_CPU_THIS_PTR
prepareFPU(i
);
269 int pop_stack
= i
->nnn() & 1;
270 // handle special case of FSTP opcode @ 0xDF 0xD0..D7
276 if (IS_TAG_EMPTY(0)) {
277 BX_CPU_THIS_PTR
FPU_stack_underflow(i
->rm(), pop_stack
);
281 floatx80 st0_reg
= BX_READ_FPU_REG(0);
283 BX_WRITE_FPU_REG(st0_reg
, i
->rm());
285 BX_CPU_THIS_PTR the_i387
.FPU_pop();
287 BX_INFO(("FST(P)_STi: required FPU, configure --enable-fpu"));
291 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_SINGLE_REAL(bxInstruction_c
*i
)
294 BX_CPU_THIS_PTR
prepareFPU(i
);
298 float32 save_reg
= float32_default_nan
; /* The masked response */
300 int pop_stack
= i
->nnn() & 1;
304 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
306 if (! BX_CPU_THIS_PTR the_i387
.is_IA_masked())
311 float_status_t status
=
312 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
314 save_reg
= floatx80_to_float32(BX_READ_FPU_REG(0), status
);
316 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
, 1))
320 write_virtual_dword(i
->seg(), RMAddr(i
), save_reg
);
323 BX_CPU_THIS_PTR the_i387
.FPU_pop();
325 BX_INFO(("FST(P)_SINGLE_REAL: required FPU, configure --enable-fpu"));
329 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_DOUBLE_REAL(bxInstruction_c
*i
)
332 BX_CPU_THIS_PTR
prepareFPU(i
);
336 float64 save_reg
= float64_default_nan
; /* The masked response */
338 int pop_stack
= i
->nnn() & 1;
342 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
344 if (! BX_CPU_THIS_PTR the_i387
.is_IA_masked())
349 float_status_t status
=
350 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
352 save_reg
= floatx80_to_float64(BX_READ_FPU_REG(0), status
);
354 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
, 1))
358 write_virtual_qword(i
->seg(), RMAddr(i
), save_reg
);
361 BX_CPU_THIS_PTR the_i387
.FPU_pop();
363 BX_INFO(("FST(P)_DOUBLE_REAL: required FPU, configure --enable-fpu"));
368 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FSTP_EXTENDED_REAL(bxInstruction_c
*i
)
371 BX_CPU_THIS_PTR
prepareFPU(i
);
375 floatx80 save_reg
= floatx80_default_nan
; /* The masked response */
379 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
381 if (! BX_CPU_THIS_PTR the_i387
.is_IA_masked())
386 save_reg
= BX_READ_FPU_REG(0);
389 write_virtual_qword(i
->seg(), RMAddr(i
), save_reg
.fraction
);
390 write_virtual_word (i
->seg(), RMAddr(i
) + 8, save_reg
.exp
);
392 BX_CPU_THIS_PTR the_i387
.FPU_pop();
394 BX_INFO(("FSTP_EXTENDED_REAL: required FPU, configure --enable-fpu"));
398 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FIST_WORD_INTEGER(bxInstruction_c
*i
)
401 BX_CPU_THIS_PTR
prepareFPU(i
);
403 Bit16s save_reg
= int16_indefinite
;
405 int pop_stack
= i
->nnn() & 1;
411 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
413 if (! BX_CPU_THIS_PTR the_i387
.is_IA_masked())
418 float_status_t status
=
419 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
421 save_reg
= floatx80_to_int16(BX_READ_FPU_REG(0), status
);
423 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
, 1))
427 write_virtual_word(i
->seg(), RMAddr(i
), (Bit16u
)(save_reg
));
430 BX_CPU_THIS_PTR the_i387
.FPU_pop();
432 BX_INFO(("FIST(P)_WORD_INTEGER: required FPU, configure --enable-fpu"));
436 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FIST_DWORD_INTEGER(bxInstruction_c
*i
)
439 BX_CPU_THIS_PTR
prepareFPU(i
);
441 Bit32s save_reg
= int32_indefinite
; /* The masked response */
443 int pop_stack
= i
->nnn() & 1;
449 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
451 if (! BX_CPU_THIS_PTR the_i387
.is_IA_masked())
456 float_status_t status
=
457 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
459 save_reg
= floatx80_to_int32(BX_READ_FPU_REG(0), status
);
461 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
, 1))
465 write_virtual_dword(i
->seg(), RMAddr(i
), (Bit32u
)(save_reg
));
468 BX_CPU_THIS_PTR the_i387
.FPU_pop();
470 BX_INFO(("FIST(P)_DWORD_INTEGER: required FPU, configure --enable-fpu"));
474 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTP_QWORD_INTEGER(bxInstruction_c
*i
)
477 BX_CPU_THIS_PTR
prepareFPU(i
);
479 Bit64s save_reg
= int64_indefinite
; /* The masked response */
485 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
487 if (! BX_CPU_THIS_PTR the_i387
.is_IA_masked())
492 float_status_t status
=
493 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
495 save_reg
= floatx80_to_int64(BX_READ_FPU_REG(0), status
);
497 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
, 1))
501 write_virtual_qword(i
->seg(), RMAddr(i
), (Bit64u
)(save_reg
));
502 BX_CPU_THIS_PTR the_i387
.FPU_pop();
504 BX_INFO(("FISTP_QWORD_INTEGER: required FPU, configure --enable-fpu"));
508 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FBSTP_PACKED_BCD(bxInstruction_c
*i
)
511 BX_CPU_THIS_PTR
prepareFPU(i
);
514 * The packed BCD integer indefinite encoding (FFFFC000000000000000H)
515 * is stored in response to a masked floating-point invalid-operation
518 Bit16u save_reg_hi
= 0xFFFF;
519 Bit64u save_reg_lo
= BX_CONST64(0xC000000000000000);
525 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
527 if (! BX_CPU_THIS_PTR the_i387
.is_IA_masked())
532 float_status_t status
=
533 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
535 floatx80 reg
= BX_READ_FPU_REG(0);
537 Bit64s save_val
= floatx80_to_int64(reg
, status
);
539 int sign
= (reg
.exp
& 0x8000) != 0;
541 save_val
= -save_val
;
543 if (save_val
> BX_CONST64(999999999999999999))
545 float_raise(status
, float_flag_invalid
);
548 if (! (status
.float_exception_flags
& float_flag_invalid
))
550 save_reg_hi
= (sign
) ? 0x8000 : 0;
553 for (int i
=0; i
<16; i
++)
555 save_reg_lo
+= ((Bit64u
)(save_val
% 10)) << (4*i
);
559 save_reg_hi
+= (Bit16u
)(save_val
% 10);
561 save_reg_hi
+= (Bit16u
)(save_val
% 10) << 4;
564 /* check for fpu arithmetic exceptions */
565 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
, 1))
569 // write packed bcd to memory
570 write_virtual_qword(i
->seg(), RMAddr(i
), save_reg_lo
);
571 write_virtual_word (i
->seg(), RMAddr(i
) + 8, save_reg_hi
);
573 BX_CPU_THIS_PTR the_i387
.FPU_pop();
575 BX_INFO(("FBSTP_PACKED_BCD: required FPU, configure --enable-fpu"));
580 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTTP16(bxInstruction_c
*i
)
582 #if BX_SUPPORT_SSE >= 3
583 BX_CPU_THIS_PTR
prepareFPU(i
);
585 Bit16s save_reg
= int16_indefinite
; /* The masked response */
591 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
593 if (! BX_CPU_THIS_PTR the_i387
.is_IA_masked())
598 float_status_t status
=
599 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
601 save_reg
= floatx80_to_int16_round_to_zero(BX_READ_FPU_REG(0), status
);
603 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
, 1))
607 write_virtual_word(i
->seg(), RMAddr(i
), (Bit16u
)(save_reg
));
608 BX_CPU_THIS_PTR the_i387
.FPU_pop();
610 BX_INFO(("FISTTP16: required SSE3, use --enable-sse option"));
611 exception(BX_UD_EXCEPTION
, 0, 0);
616 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTTP32(bxInstruction_c
*i
)
618 #if BX_SUPPORT_SSE >= 3
619 BX_CPU_THIS_PTR
prepareFPU(i
);
621 Bit32s save_reg
= int32_indefinite
; /* The masked response */
627 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
629 if (! BX_CPU_THIS_PTR the_i387
.is_IA_masked())
634 float_status_t status
=
635 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
637 save_reg
= floatx80_to_int32_round_to_zero(BX_READ_FPU_REG(0), status
);
639 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
, 1))
643 write_virtual_dword(i
->seg(), RMAddr(i
), (Bit32u
)(save_reg
));
644 BX_CPU_THIS_PTR the_i387
.FPU_pop();
646 BX_INFO(("FISTTP32: required SSE3, use --enable-sse option"));
647 exception(BX_UD_EXCEPTION
, 0, 0);
652 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTTP64(bxInstruction_c
*i
)
654 #if BX_SUPPORT_SSE >= 3
655 BX_CPU_THIS_PTR
prepareFPU(i
);
657 Bit64s save_reg
= int64_indefinite
; /* The masked response */
663 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
665 if (! BX_CPU_THIS_PTR the_i387
.is_IA_masked())
670 float_status_t status
=
671 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
673 save_reg
= floatx80_to_int64_round_to_zero(BX_READ_FPU_REG(0), status
);
675 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
, 1))
679 write_virtual_qword(i
->seg(), RMAddr(i
), (Bit64u
)(save_reg
));
680 BX_CPU_THIS_PTR the_i387
.FPU_pop();
682 BX_INFO(("FISTTP64: required SSE3, use --enable-sse option"));
683 exception(BX_UD_EXCEPTION
, 0, 0);