- added instructions how to update the online documentation
[bochs-mirror.git] / fpu / fpu_load_store.cc
blob4f870d1838dec06a5a52718ae8aaf3015d9f3187
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: fpu_load_store.cc,v 1.29 2008/09/03 20:13:52 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 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())
55 return;
57 else {
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);
63 #else
64 BX_INFO(("FLD_STi: required FPU, configure --enable-fpu"));
65 #endif
68 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_SINGLE_REAL(bxInstruction_c *i)
70 #if BX_SUPPORT_FPU
71 BX_CPU_THIS_PTR prepareFPU(i);
73 float32 load_reg = read_virtual_dword(i->seg(), RMAddr(i));
75 clear_C1();
77 if (! IS_TAG_EMPTY(-1)) {
78 BX_CPU_THIS_PTR FPU_stack_overflow();
79 return;
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))
89 return;
91 BX_CPU_THIS_PTR the_i387.FPU_push();
92 BX_WRITE_FPU_REG(result, 0);
93 #else
94 BX_INFO(("FLD_SINGLE_REAL: required FPU, configure --enable-fpu"));
95 #endif
98 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_DOUBLE_REAL(bxInstruction_c *i)
100 #if BX_SUPPORT_FPU
101 BX_CPU_THIS_PTR prepareFPU(i);
103 float64 load_reg = read_virtual_qword(i->seg(), RMAddr(i));
105 clear_C1();
107 if (! IS_TAG_EMPTY(-1)) {
108 BX_CPU_THIS_PTR FPU_stack_overflow();
109 return;
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))
119 return;
121 BX_CPU_THIS_PTR the_i387.FPU_push();
122 BX_WRITE_FPU_REG(result, 0);
123 #else
124 BX_INFO(("FLD_DOUBLE_REAL: required FPU, configure --enable-fpu"));
125 #endif
128 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_EXTENDED_REAL(bxInstruction_c *i)
130 #if BX_SUPPORT_FPU
131 BX_CPU_THIS_PTR prepareFPU(i);
133 floatx80 result;
134 result.fraction = read_virtual_qword(i->seg(), RMAddr(i));
135 result.exp = read_virtual_word (i->seg(), RMAddr(i)+8);
137 clear_C1();
139 if (! IS_TAG_EMPTY(-1)) {
140 BX_CPU_THIS_PTR FPU_stack_overflow();
141 return;
144 BX_CPU_THIS_PTR the_i387.FPU_push();
146 BX_WRITE_FPU_REG(result, 0);
147 #else
148 BX_INFO(("FLD_EXTENDED_REAL: required FPU, configure --enable-fpu"));
149 #endif
152 /* DF /0 */
153 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_WORD_INTEGER(bxInstruction_c *i)
155 #if BX_SUPPORT_FPU
156 BX_CPU_THIS_PTR prepareFPU(i);
158 Bit16s load_reg = (Bit16s) read_virtual_word(i->seg(), RMAddr(i));
160 clear_C1();
162 if (! IS_TAG_EMPTY(-1)) {
163 BX_CPU_THIS_PTR FPU_stack_overflow();
164 return;
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);
170 #else
171 BX_INFO(("FILD_WORD_INTEGER: required FPU, configure --enable-fpu"));
172 #endif
175 /* DB /0 */
176 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_DWORD_INTEGER(bxInstruction_c *i)
178 #if BX_SUPPORT_FPU
179 BX_CPU_THIS_PTR prepareFPU(i);
181 Bit32s load_reg = (Bit32s) read_virtual_dword(i->seg(), RMAddr(i));
183 clear_C1();
185 if (! IS_TAG_EMPTY(-1)) {
186 BX_CPU_THIS_PTR FPU_stack_overflow();
187 return;
190 floatx80 result = int32_to_floatx80(load_reg);
191 BX_CPU_THIS_PTR the_i387.FPU_push();
192 BX_WRITE_FPU_REG(result, 0);
193 #else
194 BX_INFO(("FILD_DWORD_INTEGER: required FPU, configure --enable-fpu"));
195 #endif
198 /* DF /5 */
199 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_QWORD_INTEGER(bxInstruction_c *i)
201 #if BX_SUPPORT_FPU
202 BX_CPU_THIS_PTR prepareFPU(i);
204 Bit64s load_reg = (Bit64s) read_virtual_qword(i->seg(), RMAddr(i));
206 clear_C1();
208 if (! IS_TAG_EMPTY(-1)) {
209 BX_CPU_THIS_PTR FPU_stack_overflow();
210 return;
213 floatx80 result = int64_to_floatx80(load_reg);
214 BX_CPU_THIS_PTR the_i387.FPU_push();
215 BX_WRITE_FPU_REG(result, 0);
216 #else
217 BX_INFO(("FILD_QWORD_INTEGER: required FPU, configure --enable-fpu"));
218 #endif
221 /* DF /4 */
222 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FBLD_PACKED_BCD(bxInstruction_c *i)
224 #if BX_SUPPORT_FPU
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));
231 clear_C1();
233 if (! IS_TAG_EMPTY(-1))
235 BX_CPU_THIS_PTR FPU_stack_overflow();
236 return;
239 // convert packed BCD to 64-bit integer
240 Bit64s scale = 1;
241 Bit64s val64 = 0;
243 for (int n = 0; n < 16; n++)
245 val64 += (lo8 & 0x0f) * scale;
246 lo8 >>= 4;
247 scale *= 10;
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);
259 #else
260 BX_INFO(("FBLD_PACKED_BCD: required FPU, configure --enable-fpu"));
261 #endif
264 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_STi(bxInstruction_c *i)
266 #if BX_SUPPORT_FPU
267 BX_CPU_THIS_PTR prepareFPU(i);
269 int pop_stack = i->nnn() & 1;
270 // handle special case of FSTP opcode @ 0xDF 0xD0..D7
271 if (i->b1() == 0xdf)
272 pop_stack = 1;
274 clear_C1();
276 if (IS_TAG_EMPTY(0)) {
277 BX_CPU_THIS_PTR FPU_stack_underflow(i->rm(), pop_stack);
278 return;
281 floatx80 st0_reg = BX_READ_FPU_REG(0);
283 BX_WRITE_FPU_REG(st0_reg, i->rm());
284 if (pop_stack)
285 BX_CPU_THIS_PTR the_i387.FPU_pop();
286 #else
287 BX_INFO(("FST(P)_STi: required FPU, configure --enable-fpu"));
288 #endif
291 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_SINGLE_REAL(bxInstruction_c *i)
293 #if BX_SUPPORT_FPU
294 BX_CPU_THIS_PTR prepareFPU(i);
296 clear_C1();
298 float32 save_reg = float32_default_nan; /* The masked response */
300 int pop_stack = i->nnn() & 1;
302 if (IS_TAG_EMPTY(0))
304 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
306 if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
307 return;
309 else
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))
317 return;
320 write_virtual_dword(i->seg(), RMAddr(i), save_reg);
322 if (pop_stack)
323 BX_CPU_THIS_PTR the_i387.FPU_pop();
324 #else
325 BX_INFO(("FST(P)_SINGLE_REAL: required FPU, configure --enable-fpu"));
326 #endif
329 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_DOUBLE_REAL(bxInstruction_c *i)
331 #if BX_SUPPORT_FPU
332 BX_CPU_THIS_PTR prepareFPU(i);
334 clear_C1();
336 float64 save_reg = float64_default_nan; /* The masked response */
338 int pop_stack = i->nnn() & 1;
340 if (IS_TAG_EMPTY(0))
342 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
344 if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
345 return;
347 else
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))
355 return;
358 write_virtual_qword(i->seg(), RMAddr(i), save_reg);
360 if (pop_stack)
361 BX_CPU_THIS_PTR the_i387.FPU_pop();
362 #else
363 BX_INFO(("FST(P)_DOUBLE_REAL: required FPU, configure --enable-fpu"));
364 #endif
367 /* DB /7 */
368 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FSTP_EXTENDED_REAL(bxInstruction_c *i)
370 #if BX_SUPPORT_FPU
371 BX_CPU_THIS_PTR prepareFPU(i);
373 clear_C1();
375 floatx80 save_reg = floatx80_default_nan; /* The masked response */
377 if (IS_TAG_EMPTY(0))
379 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
381 if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
382 return;
384 else
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();
393 #else
394 BX_INFO(("FSTP_EXTENDED_REAL: required FPU, configure --enable-fpu"));
395 #endif
398 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FIST_WORD_INTEGER(bxInstruction_c *i)
400 #if BX_SUPPORT_FPU
401 BX_CPU_THIS_PTR prepareFPU(i);
403 Bit16s save_reg = int16_indefinite;
405 int pop_stack = i->nnn() & 1;
407 clear_C1();
409 if (IS_TAG_EMPTY(0))
411 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
413 if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
414 return;
416 else
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))
424 return;
427 write_virtual_word(i->seg(), RMAddr(i), (Bit16u)(save_reg));
429 if (pop_stack)
430 BX_CPU_THIS_PTR the_i387.FPU_pop();
431 #else
432 BX_INFO(("FIST(P)_WORD_INTEGER: required FPU, configure --enable-fpu"));
433 #endif
436 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FIST_DWORD_INTEGER(bxInstruction_c *i)
438 #if BX_SUPPORT_FPU
439 BX_CPU_THIS_PTR prepareFPU(i);
441 Bit32s save_reg = int32_indefinite; /* The masked response */
443 int pop_stack = i->nnn() & 1;
445 clear_C1();
447 if (IS_TAG_EMPTY(0))
449 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
451 if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
452 return;
454 else
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))
462 return;
465 write_virtual_dword(i->seg(), RMAddr(i), (Bit32u)(save_reg));
467 if (pop_stack)
468 BX_CPU_THIS_PTR the_i387.FPU_pop();
469 #else
470 BX_INFO(("FIST(P)_DWORD_INTEGER: required FPU, configure --enable-fpu"));
471 #endif
474 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTP_QWORD_INTEGER(bxInstruction_c *i)
476 #if BX_SUPPORT_FPU
477 BX_CPU_THIS_PTR prepareFPU(i);
479 Bit64s save_reg = int64_indefinite; /* The masked response */
481 clear_C1();
483 if (IS_TAG_EMPTY(0))
485 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
487 if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
488 return;
490 else
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))
498 return;
501 write_virtual_qword(i->seg(), RMAddr(i), (Bit64u)(save_reg));
502 BX_CPU_THIS_PTR the_i387.FPU_pop();
503 #else
504 BX_INFO(("FISTP_QWORD_INTEGER: required FPU, configure --enable-fpu"));
505 #endif
508 void BX_CPP_AttrRegparmN(1) BX_CPU_C::FBSTP_PACKED_BCD(bxInstruction_c *i)
510 #if BX_SUPPORT_FPU
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
516 * exception.
518 Bit16u save_reg_hi = 0xFFFF;
519 Bit64u save_reg_lo = BX_CONST64(0xC000000000000000);
521 clear_C1();
523 if (IS_TAG_EMPTY(0))
525 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
527 if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
528 return;
530 else
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;
540 if (sign)
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;
551 save_reg_lo = 0;
553 for (int i=0; i<16; i++)
555 save_reg_lo += ((Bit64u)(save_val % 10)) << (4*i);
556 save_val /= 10;
559 save_reg_hi += (Bit16u)(save_val % 10);
560 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))
566 return;
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();
574 #else
575 BX_INFO(("FBSTP_PACKED_BCD: required FPU, configure --enable-fpu"));
576 #endif
579 /* DF /1 */
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 */
587 clear_C1();
589 if (IS_TAG_EMPTY(0))
591 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
593 if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
594 return;
596 else
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))
604 return;
607 write_virtual_word(i->seg(), RMAddr(i), (Bit16u)(save_reg));
608 BX_CPU_THIS_PTR the_i387.FPU_pop();
609 #else
610 BX_INFO(("FISTTP16: required SSE3, use --enable-sse option"));
611 exception(BX_UD_EXCEPTION, 0, 0);
612 #endif
615 /* DB /1 */
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 */
623 clear_C1();
625 if (IS_TAG_EMPTY(0))
627 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
629 if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
630 return;
632 else
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))
640 return;
643 write_virtual_dword(i->seg(), RMAddr(i), (Bit32u)(save_reg));
644 BX_CPU_THIS_PTR the_i387.FPU_pop();
645 #else
646 BX_INFO(("FISTTP32: required SSE3, use --enable-sse option"));
647 exception(BX_UD_EXCEPTION, 0, 0);
648 #endif
651 /* DD /1 */
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 */
659 clear_C1();
661 if (IS_TAG_EMPTY(0))
663 BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow);
665 if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
666 return;
668 else
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))
676 return;
679 write_virtual_qword(i->seg(), RMAddr(i), (Bit64u)(save_reg));
680 BX_CPU_THIS_PTR the_i387.FPU_pop();
681 #else
682 BX_INFO(("FISTTP64: required SSE3, use --enable-sse option"));
683 exception(BX_UD_EXCEPTION, 0, 0);
684 #endif
687 #endif