1 /////////////////////////////////////////////////////////////////////////
2 // $Id: fpu_load_store.cc,v 1.21 2008/04/26 19:56:48 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 if (IS_TAG_EMPTY(i
->rm()))
50 BX_CPU_THIS_PTR
FPU_stack_underflow(0);
54 int sti_tag
= BX_CPU_THIS_PTR the_i387
.FPU_gettagi(i
->rm());
55 floatx80 sti_reg
= BX_READ_FPU_REG(i
->rm());
57 BX_CPU_THIS_PTR the_i387
.FPU_push();
58 BX_WRITE_FPU_REGISTER_AND_TAG(sti_reg
, sti_tag
, 0);
60 BX_INFO(("FLD_STi: required FPU, configure --enable-fpu"));
64 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_SINGLE_REAL(bxInstruction_c
*i
)
67 BX_CPU_THIS_PTR
prepareFPU(i
);
69 float32 load_reg
= read_virtual_dword(i
->seg(), RMAddr(i
));
73 if (! IS_TAG_EMPTY(-1)) {
74 BX_CPU_THIS_PTR
FPU_stack_overflow();
78 float_status_t status
=
79 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
81 // convert to floatx80 format
82 floatx80 result
= float32_to_floatx80(load_reg
, status
);
84 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
87 BX_CPU_THIS_PTR the_i387
.FPU_push();
88 BX_WRITE_FPU_REG(result
, 0);
90 BX_INFO(("FLD_SINGLE_REAL: required FPU, configure --enable-fpu"));
94 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_DOUBLE_REAL(bxInstruction_c
*i
)
97 BX_CPU_THIS_PTR
prepareFPU(i
);
99 float64 load_reg
= read_virtual_qword(i
->seg(), RMAddr(i
));
103 if (! IS_TAG_EMPTY(-1)) {
104 BX_CPU_THIS_PTR
FPU_stack_overflow();
108 float_status_t status
=
109 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
111 // convert to floatx80 format
112 floatx80 result
= float64_to_floatx80(load_reg
, status
);
114 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
117 BX_CPU_THIS_PTR the_i387
.FPU_push();
118 BX_WRITE_FPU_REG(result
, 0);
120 BX_INFO(("FLD_DOUBLE_REAL: required FPU, configure --enable-fpu"));
124 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_EXTENDED_REAL(bxInstruction_c
*i
)
127 BX_CPU_THIS_PTR
prepareFPU(i
);
130 read_virtual_tword(i
->seg(), RMAddr(i
), &result
);
134 if (! IS_TAG_EMPTY(-1)) {
135 BX_CPU_THIS_PTR
FPU_stack_overflow();
139 BX_CPU_THIS_PTR the_i387
.FPU_push();
141 BX_WRITE_FPU_REG(result
, 0);
143 BX_INFO(("FLD_EXTENDED_REAL: required FPU, configure --enable-fpu"));
148 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_WORD_INTEGER(bxInstruction_c
*i
)
151 BX_CPU_THIS_PTR
prepareFPU(i
);
153 Bit16s load_reg
= (Bit16s
) read_virtual_word(i
->seg(), RMAddr(i
));
157 if (! IS_TAG_EMPTY(-1)) {
158 BX_CPU_THIS_PTR
FPU_stack_overflow();
162 floatx80 result
= int32_to_floatx80((Bit32s
) load_reg
);
163 BX_CPU_THIS_PTR the_i387
.FPU_push();
164 BX_WRITE_FPU_REG(result
, 0);
166 BX_INFO(("FILD_WORD_INTEGER: required FPU, configure --enable-fpu"));
171 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_DWORD_INTEGER(bxInstruction_c
*i
)
174 BX_CPU_THIS_PTR
prepareFPU(i
);
176 Bit32s load_reg
= (Bit32s
) read_virtual_dword(i
->seg(), RMAddr(i
));
180 if (! IS_TAG_EMPTY(-1)) {
181 BX_CPU_THIS_PTR
FPU_stack_overflow();
185 floatx80 result
= int32_to_floatx80(load_reg
);
186 BX_CPU_THIS_PTR the_i387
.FPU_push();
187 BX_WRITE_FPU_REG(result
, 0);
189 BX_INFO(("FILD_DWORD_INTEGER: required FPU, configure --enable-fpu"));
194 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_QWORD_INTEGER(bxInstruction_c
*i
)
197 BX_CPU_THIS_PTR
prepareFPU(i
);
199 Bit64s load_reg
= (Bit64s
) read_virtual_qword(i
->seg(), RMAddr(i
));
203 if (! IS_TAG_EMPTY(-1)) {
204 BX_CPU_THIS_PTR
FPU_stack_overflow();
208 floatx80 result
= int64_to_floatx80(load_reg
);
209 BX_CPU_THIS_PTR the_i387
.FPU_push();
210 BX_WRITE_FPU_REG(result
, 0);
212 BX_INFO(("FILD_QWORD_INTEGER: required FPU, configure --enable-fpu"));
217 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FBLD_PACKED_BCD(bxInstruction_c
*i
)
220 BX_CPU_THIS_PTR
prepareFPU(i
);
222 // read packed bcd from memory
223 Bit16u hi2
= read_virtual_word (i
->seg(), RMAddr(i
) + 8);
224 Bit64u lo8
= read_virtual_qword(i
->seg(), RMAddr(i
));
228 if (! IS_TAG_EMPTY(-1))
230 BX_CPU_THIS_PTR
FPU_stack_overflow();
234 // convert packed BCD to 64-bit integer
238 for (int n
= 0; n
< 16; n
++)
240 val64
+= (lo8
& 0x0F) * scale
;
245 val64
+= (hi2
& 0x0F) * scale
;
246 val64
+= ((hi2
>>4) & 0x0F) * scale
* 10;
248 floatx80 result
= int64_to_floatx80(val64
);
249 if (hi2
& 0x8000) // set negative
250 floatx80_chs(result
);
252 BX_CPU_THIS_PTR the_i387
.FPU_push();
253 BX_WRITE_FPU_REG(result
, 0);
255 BX_INFO(("FBLD_PACKED_BCD: required FPU, configure --enable-fpu"));
259 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_STi(bxInstruction_c
*i
)
262 BX_CPU_THIS_PTR
prepareFPU(i
);
264 int pop_stack
= i
->nnn() & 1;
265 // handle special case of FSTP opcode @ 0xDF 0xD0..D7
269 int st0_tag
= BX_CPU_THIS_PTR the_i387
.FPU_gettagi(0);
270 if (st0_tag
== FPU_Tag_Empty
)
272 BX_CPU_THIS_PTR
FPU_stack_underflow(i
->rm(), pop_stack
);
276 floatx80 st0_reg
= BX_READ_FPU_REG(0);
278 BX_WRITE_FPU_REGISTER_AND_TAG(st0_reg
, st0_tag
, i
->rm());
280 BX_CPU_THIS_PTR the_i387
.FPU_pop();
282 BX_INFO(("FST(P)_STi: required FPU, configure --enable-fpu"));
286 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_SINGLE_REAL(bxInstruction_c
*i
)
289 BX_CPU_THIS_PTR
prepareFPU(i
);
291 float32 save_reg
= float32_default_nan
; /* The masked response */
293 int pop_stack
= i
->nnn() & 1;
297 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
299 if (! (BX_CPU_THIS_PTR the_i387
.is_IA_masked()))
304 float_status_t status
=
305 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
307 save_reg
= floatx80_to_float32(BX_READ_FPU_REG(0), status
);
309 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
313 write_virtual_dword(i
->seg(), RMAddr(i
), save_reg
);
316 BX_CPU_THIS_PTR the_i387
.FPU_pop();
318 BX_INFO(("FST(P)_SINGLE_REAL: required FPU, configure --enable-fpu"));
322 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_DOUBLE_REAL(bxInstruction_c
*i
)
325 BX_CPU_THIS_PTR
prepareFPU(i
);
327 float64 save_reg
= float64_default_nan
; /* The masked response */
329 int pop_stack
= i
->nnn() & 1;
333 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
335 if (! (BX_CPU_THIS_PTR the_i387
.is_IA_masked()))
340 float_status_t status
=
341 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
343 save_reg
= floatx80_to_float64(BX_READ_FPU_REG(0), status
);
345 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
349 write_virtual_qword(i
->seg(), RMAddr(i
), save_reg
);
352 BX_CPU_THIS_PTR the_i387
.FPU_pop();
354 BX_INFO(("FST(P)_DOUBLE_REAL: required FPU, configure --enable-fpu"));
359 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FSTP_EXTENDED_REAL(bxInstruction_c
*i
)
362 BX_CPU_THIS_PTR
prepareFPU(i
);
364 floatx80 save_reg
= floatx80_default_nan
; /* The masked response */
368 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
370 if (! (BX_CPU_THIS_PTR the_i387
.is_IA_masked()))
375 save_reg
= BX_READ_FPU_REG(0);
378 write_virtual_tword(i
->seg(), RMAddr(i
), &save_reg
);
380 BX_CPU_THIS_PTR the_i387
.FPU_pop();
382 BX_INFO(("FSTP_EXTENDED_REAL: required FPU, configure --enable-fpu"));
386 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FIST_WORD_INTEGER(bxInstruction_c
*i
)
389 BX_CPU_THIS_PTR
prepareFPU(i
);
391 Bit16s save_reg
= int16_indefinite
;
393 int pop_stack
= i
->nnn() & 1;
399 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
401 if (! (BX_CPU_THIS_PTR the_i387
.is_IA_masked()))
406 float_status_t status
=
407 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
409 save_reg
= floatx80_to_int16(BX_READ_FPU_REG(0), status
);
411 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
415 write_virtual_word(i
->seg(), RMAddr(i
), (Bit16u
)(save_reg
));
418 BX_CPU_THIS_PTR the_i387
.FPU_pop();
420 BX_INFO(("FIST(P)_WORD_INTEGER: required FPU, configure --enable-fpu"));
424 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FIST_DWORD_INTEGER(bxInstruction_c
*i
)
427 BX_CPU_THIS_PTR
prepareFPU(i
);
429 Bit32s save_reg
= int32_indefinite
; /* The masked response */
431 int pop_stack
= i
->nnn() & 1;
437 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
439 if (! (BX_CPU_THIS_PTR the_i387
.is_IA_masked()))
444 float_status_t status
=
445 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
447 save_reg
= floatx80_to_int32(BX_READ_FPU_REG(0), status
);
449 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
453 write_virtual_dword(i
->seg(), RMAddr(i
), (Bit32u
)(save_reg
));
456 BX_CPU_THIS_PTR the_i387
.FPU_pop();
458 BX_INFO(("FIST(P)_DWORD_INTEGER: required FPU, configure --enable-fpu"));
462 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTP_QWORD_INTEGER(bxInstruction_c
*i
)
465 BX_CPU_THIS_PTR
prepareFPU(i
);
467 Bit64s save_reg
= int64_indefinite
; /* The masked response */
473 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
475 if (! (BX_CPU_THIS_PTR the_i387
.is_IA_masked()))
480 float_status_t status
=
481 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
483 save_reg
= floatx80_to_int64(BX_READ_FPU_REG(0), status
);
485 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
489 write_virtual_qword(i
->seg(), RMAddr(i
), (Bit64u
)(save_reg
));
490 BX_CPU_THIS_PTR the_i387
.FPU_pop();
492 BX_INFO(("FISTP_QWORD_INTEGER: required FPU, configure --enable-fpu"));
496 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FBSTP_PACKED_BCD(bxInstruction_c
*i
)
499 BX_CPU_THIS_PTR
prepareFPU(i
);
502 * The packed BCD integer indefinite encoding (FFFFC000000000000000H)
503 * is stored in response to a masked floating-point invalid-operation
506 Bit16u save_reg_hi
= 0xFFFF;
507 Bit64u save_reg_lo
= BX_CONST64(0xC000000000000000);
513 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
515 if (! (BX_CPU_THIS_PTR the_i387
.is_IA_masked()))
520 float_status_t status
=
521 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
523 Bit64s save_val
= floatx80_to_int64(BX_READ_FPU_REG(0), status
);
525 int sign
= (save_val
< 0);
527 save_val
= -save_val
;
529 if (save_val
> BX_CONST64(999999999999999999))
531 float_raise(status
, float_flag_invalid
);
534 if (! (status
.float_exception_flags
& float_flag_invalid
))
536 save_reg_hi
= (sign
) ? 0x8000 : 0;
539 for (int i
=0; i
<16; i
++)
541 save_reg_lo
+= ((Bit64u
)(save_val
% 10)) << (4*i
);
545 save_reg_hi
+= (Bit16u
)(save_val
% 10);
547 save_reg_hi
+= (Bit16u
)(save_val
% 10) << 4;
550 /* check for fpu arithmetic exceptions */
551 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
555 // write packed bcd to memory
556 write_virtual_qword(i
->seg(), RMAddr(i
), save_reg_lo
);
557 write_virtual_word (i
->seg(), RMAddr(i
) + 8, save_reg_hi
);
559 BX_CPU_THIS_PTR the_i387
.FPU_pop();
561 BX_INFO(("FBSTP_PACKED_BCD: required FPU, configure --enable-fpu"));
566 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTTP16(bxInstruction_c
*i
)
568 #if BX_SUPPORT_SSE >= 3
569 BX_CPU_THIS_PTR
prepareFPU(i
);
571 Bit16s save_reg
= int16_indefinite
; /* The masked response */
577 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
579 if (! (BX_CPU_THIS_PTR the_i387
.is_IA_masked()))
584 float_status_t status
=
585 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
587 save_reg
= floatx80_to_int16_round_to_zero(BX_READ_FPU_REG(0), status
);
589 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
593 write_virtual_word(i
->seg(), RMAddr(i
), (Bit16u
)(save_reg
));
594 BX_CPU_THIS_PTR the_i387
.FPU_pop();
596 BX_INFO(("FISTTP16: required SSE3, use --enable-sse option"));
602 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTTP32(bxInstruction_c
*i
)
604 #if BX_SUPPORT_SSE >= 3
605 BX_CPU_THIS_PTR
prepareFPU(i
);
607 Bit32s save_reg
= int32_indefinite
; /* The masked response */
613 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
615 if (! (BX_CPU_THIS_PTR the_i387
.is_IA_masked()))
620 float_status_t status
=
621 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
623 save_reg
= floatx80_to_int32_round_to_zero(BX_READ_FPU_REG(0), status
);
625 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
629 write_virtual_dword(i
->seg(), RMAddr(i
), (Bit32u
)(save_reg
));
630 BX_CPU_THIS_PTR the_i387
.FPU_pop();
632 BX_INFO(("FISTTP32: required SSE3, use --enable-sse option"));
638 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTTP64(bxInstruction_c
*i
)
640 #if BX_SUPPORT_SSE >= 3
641 BX_CPU_THIS_PTR
prepareFPU(i
);
643 Bit64s save_reg
= int64_indefinite
; /* The masked response */
649 BX_CPU_THIS_PTR
FPU_exception(FPU_EX_Stack_Underflow
);
651 if (! (BX_CPU_THIS_PTR the_i387
.is_IA_masked()))
656 float_status_t status
=
657 FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387
.get_control_word());
659 save_reg
= floatx80_to_int64_round_to_zero(BX_READ_FPU_REG(0), status
);
661 if (BX_CPU_THIS_PTR
FPU_exception(status
.float_exception_flags
))
665 write_virtual_qword(i
->seg(), RMAddr(i
), (Bit64u
)(save_reg
));
666 BX_CPU_THIS_PTR the_i387
.FPU_pop();
668 BX_INFO(("FISTTP64: required SSE3, use --enable-sse option"));