Commit 417454b0322ab1eed03615fe563d770fa7e4c9f9
1 parent
c185970a
Full implementation of IEEE exceptions (Aurelien Jarno)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2625 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
154 additions
and
14 deletions
target-sparc/exec.h
... | ... | @@ -61,6 +61,8 @@ void do_fsqrts(void); |
61 | 61 | void do_fsqrtd(void); |
62 | 62 | void do_fcmps(void); |
63 | 63 | void do_fcmpd(void); |
64 | +void do_fcmpes(void); | |
65 | +void do_fcmped(void); | |
64 | 66 | #ifdef TARGET_SPARC64 |
65 | 67 | void do_fabsd(void); |
66 | 68 | void do_fcmps_fcc1(void); |
... | ... | @@ -69,6 +71,12 @@ void do_fcmps_fcc2(void); |
69 | 71 | void do_fcmpd_fcc2(void); |
70 | 72 | void do_fcmps_fcc3(void); |
71 | 73 | void do_fcmpd_fcc3(void); |
74 | +void do_fcmpes_fcc1(void); | |
75 | +void do_fcmped_fcc1(void); | |
76 | +void do_fcmpes_fcc2(void); | |
77 | +void do_fcmped_fcc2(void); | |
78 | +void do_fcmpes_fcc3(void); | |
79 | +void do_fcmped_fcc3(void); | |
72 | 80 | void do_popc(); |
73 | 81 | void do_wrpstate(); |
74 | 82 | void do_done(); |
... | ... | @@ -79,6 +87,7 @@ void do_ldd_user(target_ulong addr); |
79 | 87 | void do_ldd_raw(target_ulong addr); |
80 | 88 | void do_interrupt(int intno); |
81 | 89 | void raise_exception(int tt); |
90 | +void check_ieee_exceptions(); | |
82 | 91 | void memcpy32(target_ulong *dst, const target_ulong *src); |
83 | 92 | target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev); |
84 | 93 | void dump_mmu(CPUState *env); | ... | ... |
target-sparc/op.c
... | ... | @@ -1534,16 +1534,25 @@ void OPPROTO op_flush_T0(void) |
1534 | 1534 | helper_flush(T0); |
1535 | 1535 | } |
1536 | 1536 | |
1537 | +void OPPROTO op_clear_ieee_excp_and_FTT(void) | |
1538 | +{ | |
1539 | + env->fsr &= ~(FSR_FTT_MASK | FSR_CEXC_MASK);; | |
1540 | +} | |
1541 | + | |
1537 | 1542 | #define F_OP(name, p) void OPPROTO op_f##name##p(void) |
1538 | 1543 | |
1539 | 1544 | #define F_BINOP(name) \ |
1540 | 1545 | F_OP(name, s) \ |
1541 | 1546 | { \ |
1547 | + set_float_exception_flags(0, &env->fp_status); \ | |
1542 | 1548 | FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \ |
1549 | + check_ieee_exceptions(); \ | |
1543 | 1550 | } \ |
1544 | 1551 | F_OP(name, d) \ |
1545 | 1552 | { \ |
1553 | + set_float_exception_flags(0, &env->fp_status); \ | |
1546 | 1554 | DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ |
1555 | + check_ieee_exceptions(); \ | |
1547 | 1556 | } |
1548 | 1557 | |
1549 | 1558 | F_BINOP(add); |
... | ... | @@ -1554,9 +1563,11 @@ F_BINOP(div); |
1554 | 1563 | |
1555 | 1564 | void OPPROTO op_fsmuld(void) |
1556 | 1565 | { |
1566 | + set_float_exception_flags(0, &env->fp_status); | |
1557 | 1567 | DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status), |
1558 | 1568 | float32_to_float64(FT1, &env->fp_status), |
1559 | 1569 | &env->fp_status); |
1570 | + check_ieee_exceptions(); | |
1560 | 1571 | } |
1561 | 1572 | |
1562 | 1573 | #define F_HELPER(name) \ |
... | ... | @@ -1582,6 +1593,7 @@ F_OP(abs, s) |
1582 | 1593 | } |
1583 | 1594 | |
1584 | 1595 | F_HELPER(cmp); |
1596 | +F_HELPER(cmpe); | |
1585 | 1597 | |
1586 | 1598 | #ifdef TARGET_SPARC64 |
1587 | 1599 | F_OP(neg, d) |
... | ... | @@ -1623,6 +1635,37 @@ void OPPROTO op_fcmpd_fcc3(void) |
1623 | 1635 | { |
1624 | 1636 | do_fcmpd_fcc3(); |
1625 | 1637 | } |
1638 | + | |
1639 | +void OPPROTO op_fcmpes_fcc1(void) | |
1640 | +{ | |
1641 | + do_fcmpes_fcc1(); | |
1642 | +} | |
1643 | + | |
1644 | +void OPPROTO op_fcmped_fcc1(void) | |
1645 | +{ | |
1646 | + do_fcmped_fcc1(); | |
1647 | +} | |
1648 | + | |
1649 | +void OPPROTO op_fcmpes_fcc2(void) | |
1650 | +{ | |
1651 | + do_fcmpes_fcc2(); | |
1652 | +} | |
1653 | + | |
1654 | +void OPPROTO op_fcmped_fcc2(void) | |
1655 | +{ | |
1656 | + do_fcmped_fcc2(); | |
1657 | +} | |
1658 | + | |
1659 | +void OPPROTO op_fcmpes_fcc3(void) | |
1660 | +{ | |
1661 | + do_fcmpes_fcc3(); | |
1662 | +} | |
1663 | + | |
1664 | +void OPPROTO op_fcmped_fcc3(void) | |
1665 | +{ | |
1666 | + do_fcmped_fcc3(); | |
1667 | +} | |
1668 | + | |
1626 | 1669 | #endif |
1627 | 1670 | |
1628 | 1671 | /* Integer to float conversion. */ |
... | ... | @@ -1631,23 +1674,31 @@ F_HELPER(ito); |
1631 | 1674 | #else |
1632 | 1675 | F_OP(ito, s) |
1633 | 1676 | { |
1677 | + set_float_exception_flags(0, &env->fp_status); | |
1634 | 1678 | FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status); |
1679 | + check_ieee_exceptions(); | |
1635 | 1680 | } |
1636 | 1681 | |
1637 | 1682 | F_OP(ito, d) |
1638 | 1683 | { |
1684 | + set_float_exception_flags(0, &env->fp_status); | |
1639 | 1685 | DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status); |
1686 | + check_ieee_exceptions(); | |
1640 | 1687 | } |
1641 | 1688 | |
1642 | 1689 | #ifdef TARGET_SPARC64 |
1643 | 1690 | F_OP(xto, s) |
1644 | 1691 | { |
1692 | + set_float_exception_flags(0, &env->fp_status); | |
1645 | 1693 | FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status); |
1694 | + check_ieee_exceptions(); | |
1646 | 1695 | } |
1647 | 1696 | |
1648 | 1697 | F_OP(xto, d) |
1649 | 1698 | { |
1699 | + set_float_exception_flags(0, &env->fp_status); | |
1650 | 1700 | DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status); |
1701 | + check_ieee_exceptions(); | |
1651 | 1702 | } |
1652 | 1703 | #endif |
1653 | 1704 | #endif |
... | ... | @@ -1656,34 +1707,46 @@ F_OP(xto, d) |
1656 | 1707 | /* floating point conversion */ |
1657 | 1708 | void OPPROTO op_fdtos(void) |
1658 | 1709 | { |
1710 | + set_float_exception_flags(0, &env->fp_status); | |
1659 | 1711 | FT0 = float64_to_float32(DT1, &env->fp_status); |
1712 | + check_ieee_exceptions(); | |
1660 | 1713 | } |
1661 | 1714 | |
1662 | 1715 | void OPPROTO op_fstod(void) |
1663 | 1716 | { |
1717 | + set_float_exception_flags(0, &env->fp_status); | |
1664 | 1718 | DT0 = float32_to_float64(FT1, &env->fp_status); |
1719 | + check_ieee_exceptions(); | |
1665 | 1720 | } |
1666 | 1721 | |
1667 | 1722 | /* Float to integer conversion. */ |
1668 | 1723 | void OPPROTO op_fstoi(void) |
1669 | 1724 | { |
1725 | + set_float_exception_flags(0, &env->fp_status); | |
1670 | 1726 | *((int32_t *)&FT0) = float32_to_int32_round_to_zero(FT1, &env->fp_status); |
1727 | + check_ieee_exceptions(); | |
1671 | 1728 | } |
1672 | 1729 | |
1673 | 1730 | void OPPROTO op_fdtoi(void) |
1674 | 1731 | { |
1732 | + set_float_exception_flags(0, &env->fp_status); | |
1675 | 1733 | *((int32_t *)&FT0) = float64_to_int32_round_to_zero(DT1, &env->fp_status); |
1734 | + check_ieee_exceptions(); | |
1676 | 1735 | } |
1677 | 1736 | |
1678 | 1737 | #ifdef TARGET_SPARC64 |
1679 | 1738 | void OPPROTO op_fstox(void) |
1680 | 1739 | { |
1740 | + set_float_exception_flags(0, &env->fp_status); | |
1681 | 1741 | *((int64_t *)&DT0) = float32_to_int64_round_to_zero(FT1, &env->fp_status); |
1742 | + check_ieee_exceptions(); | |
1682 | 1743 | } |
1683 | 1744 | |
1684 | 1745 | void OPPROTO op_fdtox(void) |
1685 | 1746 | { |
1747 | + set_float_exception_flags(0, &env->fp_status); | |
1686 | 1748 | *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status); |
1749 | + check_ieee_exceptions(); | |
1687 | 1750 | } |
1688 | 1751 | |
1689 | 1752 | void OPPROTO op_fmovs_cc(void) | ... | ... |
target-sparc/op_helper.c
... | ... | @@ -9,10 +9,43 @@ void raise_exception(int tt) |
9 | 9 | cpu_loop_exit(); |
10 | 10 | } |
11 | 11 | |
12 | +void check_ieee_exceptions() | |
13 | +{ | |
14 | + T0 = get_float_exception_flags(&env->fp_status); | |
15 | + if (T0) | |
16 | + { | |
17 | + /* Copy IEEE 754 flags into FSR */ | |
18 | + if (T0 & float_flag_invalid) | |
19 | + env->fsr |= FSR_NVC; | |
20 | + if (T0 & float_flag_overflow) | |
21 | + env->fsr |= FSR_OFC; | |
22 | + if (T0 & float_flag_underflow) | |
23 | + env->fsr |= FSR_UFC; | |
24 | + if (T0 & float_flag_divbyzero) | |
25 | + env->fsr |= FSR_DZC; | |
26 | + if (T0 & float_flag_inexact) | |
27 | + env->fsr |= FSR_NXC; | |
28 | + | |
29 | + if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) | |
30 | + { | |
31 | + /* Unmasked exception, generate a trap */ | |
32 | + env->fsr |= FSR_FTT_IEEE_EXCP; | |
33 | + raise_exception(TT_FP_EXCP); | |
34 | + } | |
35 | + else | |
36 | + { | |
37 | + /* Accumulate exceptions */ | |
38 | + env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5; | |
39 | + } | |
40 | + } | |
41 | +} | |
42 | + | |
12 | 43 | #ifdef USE_INT_TO_FLOAT_HELPERS |
13 | 44 | void do_fitos(void) |
14 | 45 | { |
46 | + set_float_exception_flags(0, &env->fp_status); | |
15 | 47 | FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status); |
48 | + check_ieee_exceptions(); | |
16 | 49 | } |
17 | 50 | |
18 | 51 | void do_fitod(void) |
... | ... | @@ -35,23 +68,29 @@ void do_fabsd(void) |
35 | 68 | |
36 | 69 | void do_fsqrts(void) |
37 | 70 | { |
71 | + set_float_exception_flags(0, &env->fp_status); | |
38 | 72 | FT0 = float32_sqrt(FT1, &env->fp_status); |
73 | + check_ieee_exceptions(); | |
39 | 74 | } |
40 | 75 | |
41 | 76 | void do_fsqrtd(void) |
42 | 77 | { |
78 | + set_float_exception_flags(0, &env->fp_status); | |
43 | 79 | DT0 = float64_sqrt(DT1, &env->fp_status); |
80 | + check_ieee_exceptions(); | |
44 | 81 | } |
45 | 82 | |
46 | -#define GEN_FCMP(name, size, reg1, reg2, FS) \ | |
83 | +#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \ | |
47 | 84 | void glue(do_, name) (void) \ |
48 | 85 | { \ |
49 | 86 | env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ |
50 | 87 | switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \ |
51 | 88 | case float_relation_unordered: \ |
52 | 89 | T0 = (FSR_FCC1 | FSR_FCC0) << FS; \ |
53 | - if (env->fsr & FSR_NVM) { \ | |
90 | + if ((env->fsr & FSR_NVM) || TRAP) { \ | |
54 | 91 | env->fsr |= T0; \ |
92 | + env->fsr |= FSR_NVC; \ | |
93 | + env->fsr |= FSR_FTT_IEEE_EXCP; \ | |
55 | 94 | raise_exception(TT_FP_EXCP); \ |
56 | 95 | } else { \ |
57 | 96 | env->fsr |= FSR_NVA; \ |
... | ... | @@ -70,18 +109,30 @@ void do_fsqrtd(void) |
70 | 109 | env->fsr |= T0; \ |
71 | 110 | } |
72 | 111 | |
73 | -GEN_FCMP(fcmps, float32, FT0, FT1, 0); | |
74 | -GEN_FCMP(fcmpd, float64, DT0, DT1, 0); | |
112 | +GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0); | |
113 | +GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0); | |
114 | + | |
115 | +GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1); | |
116 | +GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1); | |
75 | 117 | |
76 | 118 | #ifdef TARGET_SPARC64 |
77 | -GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22); | |
78 | -GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22); | |
119 | +GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0); | |
120 | +GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0); | |
121 | + | |
122 | +GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24, 0); | |
123 | +GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0); | |
124 | + | |
125 | +GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26, 0); | |
126 | +GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0); | |
127 | + | |
128 | +GEN_FCMP(fcmpes_fcc1, float32, FT0, FT1, 22, 1); | |
129 | +GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1); | |
79 | 130 | |
80 | -GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24); | |
81 | -GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24); | |
131 | +GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1); | |
132 | +GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1); | |
82 | 133 | |
83 | -GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26); | |
84 | -GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26); | |
134 | +GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1); | |
135 | +GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); | |
85 | 136 | #endif |
86 | 137 | |
87 | 138 | #if defined(CONFIG_USER_ONLY) | ... | ... |
target-sparc/translate.c
... | ... | @@ -943,6 +943,21 @@ static GenOpFunc * const gen_fcmpd[4] = { |
943 | 943 | gen_op_fcmpd_fcc2, |
944 | 944 | gen_op_fcmpd_fcc3, |
945 | 945 | }; |
946 | + | |
947 | +static GenOpFunc * const gen_fcmpes[4] = { | |
948 | + gen_op_fcmpes, | |
949 | + gen_op_fcmpes_fcc1, | |
950 | + gen_op_fcmpes_fcc2, | |
951 | + gen_op_fcmpes_fcc3, | |
952 | +}; | |
953 | + | |
954 | +static GenOpFunc * const gen_fcmped[4] = { | |
955 | + gen_op_fcmped, | |
956 | + gen_op_fcmped_fcc1, | |
957 | + gen_op_fcmped_fcc2, | |
958 | + gen_op_fcmped_fcc3, | |
959 | +}; | |
960 | + | |
946 | 961 | #endif |
947 | 962 | |
948 | 963 | static int gen_trap_ifnofpu(DisasContext * dc) |
... | ... | @@ -1289,6 +1304,7 @@ static void disas_sparc_insn(DisasContext * dc) |
1289 | 1304 | } else if (xop == 0x34) { /* FPU Operations */ |
1290 | 1305 | if (gen_trap_ifnofpu(dc)) |
1291 | 1306 | goto jmp_insn; |
1307 | + gen_op_clear_ieee_excp_and_FTT(); | |
1292 | 1308 | rs1 = GET_FIELD(insn, 13, 17); |
1293 | 1309 | rs2 = GET_FIELD(insn, 27, 31); |
1294 | 1310 | xop = GET_FIELD(insn, 18, 26); |
... | ... | @@ -1476,6 +1492,7 @@ static void disas_sparc_insn(DisasContext * dc) |
1476 | 1492 | #endif |
1477 | 1493 | if (gen_trap_ifnofpu(dc)) |
1478 | 1494 | goto jmp_insn; |
1495 | + gen_op_clear_ieee_excp_and_FTT(); | |
1479 | 1496 | rs1 = GET_FIELD(insn, 13, 17); |
1480 | 1497 | rs2 = GET_FIELD(insn, 27, 31); |
1481 | 1498 | xop = GET_FIELD(insn, 18, 26); |
... | ... | @@ -1653,18 +1670,18 @@ static void disas_sparc_insn(DisasContext * dc) |
1653 | 1670 | gen_op_load_fpr_FT0(rs1); |
1654 | 1671 | gen_op_load_fpr_FT1(rs2); |
1655 | 1672 | #ifdef TARGET_SPARC64 |
1656 | - gen_fcmps[rd & 3](); | |
1673 | + gen_fcmpes[rd & 3](); | |
1657 | 1674 | #else |
1658 | - gen_op_fcmps(); /* XXX should trap if qNaN or sNaN */ | |
1675 | + gen_op_fcmpes(); | |
1659 | 1676 | #endif |
1660 | 1677 | break; |
1661 | 1678 | case 0x56: /* fcmped, V9 %fcc */ |
1662 | 1679 | gen_op_load_fpr_DT0(DFPREG(rs1)); |
1663 | 1680 | gen_op_load_fpr_DT1(DFPREG(rs2)); |
1664 | 1681 | #ifdef TARGET_SPARC64 |
1665 | - gen_fcmpd[rd & 3](); | |
1682 | + gen_fcmped[rd & 3](); | |
1666 | 1683 | #else |
1667 | - gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN */ | |
1684 | + gen_op_fcmped(); | |
1668 | 1685 | #endif |
1669 | 1686 | break; |
1670 | 1687 | case 0x57: /* fcmpeq */ | ... | ... |