- removed support for old-style syntax userbutton shortcuts
[bochs-mirror.git] / fpu / fpu_load_store.cc
blob89f61a80fbd25ae05abf6b487bd7931b26a68826
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: fpu_load_store.cc,v 1.21 2008/04/26 19:56:48 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (c) 2003 Stanislav Shwartsman
6 // Written by Stanislav Shwartsman [sshwarts at sourceforge net]
7 //
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
25 #include "bochs.h"
26 #include "cpu/cpu.h"
27 #define LOG_THIS BX_CPU_THIS_PTR
29 #if BX_SUPPORT_FPU
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)
37 #if BX_SUPPORT_FPU
38 BX_CPU_THIS_PTR prepareFPU(i);
40 clear_C1();
42 if (! IS_TAG_EMPTY(-1))
44 BX_CPU_THIS_PTR FPU_stack_overflow();
45 return;
48 if (IS_TAG_EMPTY(i->rm()))
50 BX_CPU_THIS_PTR FPU_stack_underflow(0);
51 return;
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);
59 #else
60 BX_INFO(("FLD_STi: required FPU, configure --enable-fpu"));
61 #endif
64 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_SINGLE_REAL(bxInstruction_c *i)
66 #if BX_SUPPORT_FPU
67 BX_CPU_THIS_PTR prepareFPU(i);
69 float32 load_reg = read_virtual_dword(i->seg(), RMAddr(i));
71 clear_C1();
73 if (! IS_TAG_EMPTY(-1)) {
74 BX_CPU_THIS_PTR FPU_stack_overflow();
75 return;
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))
85 return;
87 BX_CPU_THIS_PTR the_i387.FPU_push();
88 BX_WRITE_FPU_REG(result, 0);
89 #else
90 BX_INFO(("FLD_SINGLE_REAL: required FPU, configure --enable-fpu"));
91 #endif
94 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_DOUBLE_REAL(bxInstruction_c *i)
96 #if BX_SUPPORT_FPU
97 BX_CPU_THIS_PTR prepareFPU(i);
99 float64 load_reg = read_virtual_qword(i->seg(), RMAddr(i));
101 clear_C1();
103 if (! IS_TAG_EMPTY(-1)) {
104 BX_CPU_THIS_PTR FPU_stack_overflow();
105 return;
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))
115 return;
117 BX_CPU_THIS_PTR the_i387.FPU_push();
118 BX_WRITE_FPU_REG(result, 0);
119 #else
120 BX_INFO(("FLD_DOUBLE_REAL: required FPU, configure --enable-fpu"));
121 #endif
124 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_EXTENDED_REAL(bxInstruction_c *i)
126 #if BX_SUPPORT_FPU
127 BX_CPU_THIS_PTR prepareFPU(i);
129 floatx80 result;
130 read_virtual_tword(i->seg(), RMAddr(i), &result);
132 clear_C1();
134 if (! IS_TAG_EMPTY(-1)) {
135 BX_CPU_THIS_PTR FPU_stack_overflow();
136 return;
139 BX_CPU_THIS_PTR the_i387.FPU_push();
141 BX_WRITE_FPU_REG(result, 0);
142 #else
143 BX_INFO(("FLD_EXTENDED_REAL: required FPU, configure --enable-fpu"));
144 #endif
147 /* DF /0 */
148 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_WORD_INTEGER(bxInstruction_c *i)
150 #if BX_SUPPORT_FPU
151 BX_CPU_THIS_PTR prepareFPU(i);
153 Bit16s load_reg = (Bit16s) read_virtual_word(i->seg(), RMAddr(i));
155 clear_C1();
157 if (! IS_TAG_EMPTY(-1)) {
158 BX_CPU_THIS_PTR FPU_stack_overflow();
159 return;
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);
165 #else
166 BX_INFO(("FILD_WORD_INTEGER: required FPU, configure --enable-fpu"));
167 #endif
170 /* DB /0 */
171 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_DWORD_INTEGER(bxInstruction_c *i)
173 #if BX_SUPPORT_FPU
174 BX_CPU_THIS_PTR prepareFPU(i);
176 Bit32s load_reg = (Bit32s) read_virtual_dword(i->seg(), RMAddr(i));
178 clear_C1();
180 if (! IS_TAG_EMPTY(-1)) {
181 BX_CPU_THIS_PTR FPU_stack_overflow();
182 return;
185 floatx80 result = int32_to_floatx80(load_reg);
186 BX_CPU_THIS_PTR the_i387.FPU_push();
187 BX_WRITE_FPU_REG(result, 0);
188 #else
189 BX_INFO(("FILD_DWORD_INTEGER: required FPU, configure --enable-fpu"));
190 #endif
193 /* DF /5 */
194 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_QWORD_INTEGER(bxInstruction_c *i)
196 #if BX_SUPPORT_FPU
197 BX_CPU_THIS_PTR prepareFPU(i);
199 Bit64s load_reg = (Bit64s) read_virtual_qword(i->seg(), RMAddr(i));
201 clear_C1();
203 if (! IS_TAG_EMPTY(-1)) {
204 BX_CPU_THIS_PTR FPU_stack_overflow();
205 return;
208 floatx80 result = int64_to_floatx80(load_reg);
209 BX_CPU_THIS_PTR the_i387.FPU_push();
210 BX_WRITE_FPU_REG(result, 0);
211 #else
212 BX_INFO(("FILD_QWORD_INTEGER: required FPU, configure --enable-fpu"));
213 #endif
216 /* DF /4 */
217 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FBLD_PACKED_BCD(bxInstruction_c *i)
219 #if BX_SUPPORT_FPU
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));
226 clear_C1();
228 if (! IS_TAG_EMPTY(-1))
230 BX_CPU_THIS_PTR FPU_stack_overflow();
231 return;
234 // convert packed BCD to 64-bit integer
235 Bit64s scale = 1;
236 Bit64s val64 = 0;
238 for (int n = 0; n < 16; n++)
240 val64 += (lo8 & 0x0F) * scale;
241 lo8 >>= 4;
242 scale *= 10;
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);
254 #else
255 BX_INFO(("FBLD_PACKED_BCD: required FPU, configure --enable-fpu"));
256 #endif
259 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_STi(bxInstruction_c *i)
261 #if BX_SUPPORT_FPU
262 BX_CPU_THIS_PTR prepareFPU(i);
264 int pop_stack = i->nnn() & 1;
265 // handle special case of FSTP opcode @ 0xDF 0xD0..D7
266 if (i->b1() == 0xdf)
267 pop_stack = 1;
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);
273 return;
276 floatx80 st0_reg = BX_READ_FPU_REG(0);
278 BX_WRITE_FPU_REGISTER_AND_TAG(st0_reg, st0_tag, i->rm());
279 if (pop_stack)
280 BX_CPU_THIS_PTR the_i387.FPU_pop();
281 #else
282 BX_INFO(("FST(P)_STi: required FPU, configure --enable-fpu"));
283 #endif
286 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_SINGLE_REAL(bxInstruction_c *i)
288 #if BX_SUPPORT_FPU
289 BX_CPU_THIS_PTR prepareFPU(i);
291 float32 save_reg = float32_default_nan; /* The masked response */
293 int pop_stack = i->nnn() & 1;
295 if (IS_TAG_EMPTY(0))
297 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
299 if (! (BX_CPU_THIS_PTR the_i387.is_IA_masked()))
300 return;
302 else
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))
310 return;
313 write_virtual_dword(i->seg(), RMAddr(i), save_reg);
315 if (pop_stack)
316 BX_CPU_THIS_PTR the_i387.FPU_pop();
317 #else
318 BX_INFO(("FST(P)_SINGLE_REAL: required FPU, configure --enable-fpu"));
319 #endif
322 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_DOUBLE_REAL(bxInstruction_c *i)
324 #if BX_SUPPORT_FPU
325 BX_CPU_THIS_PTR prepareFPU(i);
327 float64 save_reg = float64_default_nan; /* The masked response */
329 int pop_stack = i->nnn() & 1;
331 if (IS_TAG_EMPTY(0))
333 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
335 if (! (BX_CPU_THIS_PTR the_i387.is_IA_masked()))
336 return;
338 else
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))
346 return;
349 write_virtual_qword(i->seg(), RMAddr(i), save_reg);
351 if (pop_stack)
352 BX_CPU_THIS_PTR the_i387.FPU_pop();
353 #else
354 BX_INFO(("FST(P)_DOUBLE_REAL: required FPU, configure --enable-fpu"));
355 #endif
358 /* DB /7 */
359 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FSTP_EXTENDED_REAL(bxInstruction_c *i)
361 #if BX_SUPPORT_FPU
362 BX_CPU_THIS_PTR prepareFPU(i);
364 floatx80 save_reg = floatx80_default_nan; /* The masked response */
366 if (IS_TAG_EMPTY(0))
368 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
370 if (! (BX_CPU_THIS_PTR the_i387.is_IA_masked()))
371 return;
373 else
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();
381 #else
382 BX_INFO(("FSTP_EXTENDED_REAL: required FPU, configure --enable-fpu"));
383 #endif
386 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FIST_WORD_INTEGER(bxInstruction_c *i)
388 #if BX_SUPPORT_FPU
389 BX_CPU_THIS_PTR prepareFPU(i);
391 Bit16s save_reg = int16_indefinite;
393 int pop_stack = i->nnn() & 1;
395 clear_C1();
397 if (IS_TAG_EMPTY(0))
399 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
401 if (! (BX_CPU_THIS_PTR the_i387.is_IA_masked()))
402 return;
404 else
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))
412 return;
415 write_virtual_word(i->seg(), RMAddr(i), (Bit16u)(save_reg));
417 if (pop_stack)
418 BX_CPU_THIS_PTR the_i387.FPU_pop();
419 #else
420 BX_INFO(("FIST(P)_WORD_INTEGER: required FPU, configure --enable-fpu"));
421 #endif
424 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FIST_DWORD_INTEGER(bxInstruction_c *i)
426 #if BX_SUPPORT_FPU
427 BX_CPU_THIS_PTR prepareFPU(i);
429 Bit32s save_reg = int32_indefinite; /* The masked response */
431 int pop_stack = i->nnn() & 1;
433 clear_C1();
435 if (IS_TAG_EMPTY(0))
437 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
439 if (! (BX_CPU_THIS_PTR the_i387.is_IA_masked()))
440 return;
442 else
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))
450 return;
453 write_virtual_dword(i->seg(), RMAddr(i), (Bit32u)(save_reg));
455 if (pop_stack)
456 BX_CPU_THIS_PTR the_i387.FPU_pop();
457 #else
458 BX_INFO(("FIST(P)_DWORD_INTEGER: required FPU, configure --enable-fpu"));
459 #endif
462 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTP_QWORD_INTEGER(bxInstruction_c *i)
464 #if BX_SUPPORT_FPU
465 BX_CPU_THIS_PTR prepareFPU(i);
467 Bit64s save_reg = int64_indefinite; /* The masked response */
469 clear_C1();
471 if (IS_TAG_EMPTY(0))
473 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
475 if (! (BX_CPU_THIS_PTR the_i387.is_IA_masked()))
476 return;
478 else
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))
486 return;
489 write_virtual_qword(i->seg(), RMAddr(i), (Bit64u)(save_reg));
490 BX_CPU_THIS_PTR the_i387.FPU_pop();
491 #else
492 BX_INFO(("FISTP_QWORD_INTEGER: required FPU, configure --enable-fpu"));
493 #endif
496 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FBSTP_PACKED_BCD(bxInstruction_c *i)
498 #if BX_SUPPORT_FPU
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
504 * exception.
506 Bit16u save_reg_hi = 0xFFFF;
507 Bit64u save_reg_lo = BX_CONST64(0xC000000000000000);
509 clear_C1();
511 if (IS_TAG_EMPTY(0))
513 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
515 if (! (BX_CPU_THIS_PTR the_i387.is_IA_masked()))
516 return;
518 else
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);
526 if (sign)
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;
537 save_reg_lo = 0;
539 for (int i=0; i<16; i++)
541 save_reg_lo += ((Bit64u)(save_val % 10)) << (4*i);
542 save_val /= 10;
545 save_reg_hi += (Bit16u)(save_val % 10);
546 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))
552 return;
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();
560 #else
561 BX_INFO(("FBSTP_PACKED_BCD: required FPU, configure --enable-fpu"));
562 #endif
565 /* DF /1 */
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 */
573 clear_C1();
575 if (IS_TAG_EMPTY(0))
577 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
579 if (! (BX_CPU_THIS_PTR the_i387.is_IA_masked()))
580 return;
582 else
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))
590 return;
593 write_virtual_word(i->seg(), RMAddr(i), (Bit16u)(save_reg));
594 BX_CPU_THIS_PTR the_i387.FPU_pop();
595 #else
596 BX_INFO(("FISTTP16: required SSE3, use --enable-sse option"));
597 UndefinedOpcode(i);
598 #endif
601 /* DB /1 */
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 */
609 clear_C1();
611 if (IS_TAG_EMPTY(0))
613 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
615 if (! (BX_CPU_THIS_PTR the_i387.is_IA_masked()))
616 return;
618 else
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))
626 return;
629 write_virtual_dword(i->seg(), RMAddr(i), (Bit32u)(save_reg));
630 BX_CPU_THIS_PTR the_i387.FPU_pop();
631 #else
632 BX_INFO(("FISTTP32: required SSE3, use --enable-sse option"));
633 UndefinedOpcode(i);
634 #endif
637 /* DD /1 */
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 */
645 clear_C1();
647 if (IS_TAG_EMPTY(0))
649 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
651 if (! (BX_CPU_THIS_PTR the_i387.is_IA_masked()))
652 return;
654 else
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))
662 return;
665 write_virtual_qword(i->seg(), RMAddr(i), (Bit64u)(save_reg));
666 BX_CPU_THIS_PTR the_i387.FPU_pop();
667 #else
668 BX_INFO(("FISTTP64: required SSE3, use --enable-sse option"));
669 UndefinedOpcode(i);
670 #endif
673 #endif