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 */ | ... | ... |