diff --git a/qemu-tech.texi b/qemu-tech.texi index 77bda8637e29964390369fb3ccb812600ffc3769..ca913caf697ccb729c5834587913fb531a8b1230 100644 --- a/qemu-tech.texi +++ b/qemu-tech.texi @@ -181,9 +181,6 @@ Current QEMU limitations: @itemize -@item Tagged add/subtract instructions are not supported, but they are -probably not used. - @item IPC syscalls are missing. @item 128-bit floating point operations are not supported, though none of the diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 5c4593ac63363cbcf7eaab12430952a0e9845825..60189a6096a8c41c140ef756e07569ac7ca1b8a0 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -37,6 +37,7 @@ #define TT_WIN_UNF 0x06 #define TT_FP_EXCP 0x08 #define TT_DFAULT 0x09 +#define TT_TOVF 0x0a #define TT_EXTINT 0x10 #define TT_DIV_ZERO 0x2a #define TT_TRAP 0x80 @@ -47,6 +48,7 @@ #define TT_PRIV_INSN 0x11 #define TT_NFPU_INSN 0x20 #define TT_FP_EXCP 0x21 +#define TT_TOVF 0x23 #define TT_CLRWIN 0x24 #define TT_DIV_ZERO 0x28 #define TT_DFAULT 0x30 diff --git a/target-sparc/op.c b/target-sparc/op.c index 9e16a29a43527ac09f9ec50563ecfd1cf7c214df..5c6e5391d9ec80173e58e3a431e64f3d55de6fb8 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -472,6 +472,96 @@ void OPPROTO op_addx_T1_T0_cc(void) FORCE_RET(); } +void OPPROTO op_tadd_T1_T0_cc(void) +{ + target_ulong src1; + + src1 = T0; + T0 += T1; + env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + env->psr |= PSR_CARRY; + if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; + if ((src1 & 0x03) || (T1 & 0x03)) + env->psr |= PSR_OVF; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; + if (T0 < src1) + env->xcc |= PSR_CARRY; + if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63)) + env->xcc |= PSR_OVF; +#else + if (!T0) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if (T0 < src1) + env->psr |= PSR_CARRY; + if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31)) + env->psr |= PSR_OVF; + if ((src1 & 0x03) || (T1 & 0x03)) + env->psr |= PSR_OVF; +#endif + FORCE_RET(); +} + +void OPPROTO op_tadd_T1_T0_ccTV(void) +{ + target_ulong src1; + + if ((T0 & 0x03) || (T1 & 0x03)) + raise_exception(TT_TOVF); + + src1 = T0; + T0 += T1; + +#ifdef TARGET_SPARC64 + if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) & + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + raise_exception(TT_TOVF); +#else + if ((src1 & 0x03) || (T1 & 0x03)) + raise_exception(TT_TOVF); +#endif + + env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if ((T0 & 0xffffffff) < (src1 & 0xffffffff)) + env->psr |= PSR_CARRY; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; + if (T0 < src1) + env->xcc |= PSR_CARRY; +#else + if (!T0) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if (T0 < src1) + env->psr |= PSR_CARRY; +#endif + FORCE_RET(); +} + void OPPROTO op_sub_T1_T0(void) { T0 -= T1; @@ -582,6 +672,96 @@ void OPPROTO op_subx_T1_T0_cc(void) FORCE_RET(); } +void OPPROTO op_tsub_T1_T0_cc(void) +{ + target_ulong src1; + + src1 = T0; + T0 -= T1; + env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) + env->psr |= PSR_CARRY; + if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + env->psr |= PSR_OVF; + if ((src1 & 0x03) || (T1 & 0x03)) + env->psr |= PSR_OVF; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; + if (src1 < T1) + env->xcc |= PSR_CARRY; + if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63)) + env->xcc |= PSR_OVF; +#else + if (!T0) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if (src1 < T1) + env->psr |= PSR_CARRY; + if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) + env->psr |= PSR_OVF; + if ((src1 & 0x03) || (T1 & 0x03)) + env->psr |= PSR_OVF; +#endif + FORCE_RET(); +} + +void OPPROTO op_tsub_T1_T0_ccTV(void) +{ + target_ulong src1; + + if ((T0 & 0x03) || (T1 & 0x03)) + raise_exception(TT_TOVF); + + src1 = T0; + T0 -= T1; + +#ifdef TARGET_SPARC64 + if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) & + ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31)) + raise_exception(TT_TOVF); +#else + if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31)) + raise_exception(TT_TOVF); +#endif + + env->psr = 0; +#ifdef TARGET_SPARC64 + if (!(T0 & 0xffffffff)) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if ((src1 & 0xffffffff) < (T1 & 0xffffffff)) + env->psr |= PSR_CARRY; + + env->xcc = 0; + if (!T0) + env->xcc |= PSR_ZERO; + if ((int64_t) T0 < 0) + env->xcc |= PSR_NEG; + if (src1 < T1) + env->xcc |= PSR_CARRY; +#else + if (!T0) + env->psr |= PSR_ZERO; + if ((int32_t) T0 < 0) + env->psr |= PSR_NEG; + if (src1 < T1) + env->psr |= PSR_CARRY; +#endif + FORCE_RET(); +} + void OPPROTO op_and_T1_T0(void) { T0 &= T1; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 74a0a2cb8966b7166ee91bc477505f20fd72f630..7486c277bb0a0b3f6b8a6478a77b6d3becbc494b 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -27,7 +27,6 @@ Optimize synthetic instructions Optional alignment check 128-bit float - Tagged add/sub */ #include @@ -1833,10 +1832,21 @@ static void disas_sparc_insn(DisasContext * dc) } else { switch (xop) { case 0x20: /* taddcc */ + gen_op_tadd_T1_T0_cc(); + gen_movl_T0_reg(rd); + break; case 0x21: /* tsubcc */ + gen_op_tsub_T1_T0_cc(); + gen_movl_T0_reg(rd); + break; case 0x22: /* taddcctv */ + gen_op_tadd_T1_T0_ccTV(); + gen_movl_T0_reg(rd); + break; case 0x23: /* tsubcctv */ - goto illegal_insn; + gen_op_tsub_T1_T0_ccTV(); + gen_movl_T0_reg(rd); + break; case 0x24: /* mulscc */ gen_op_mulscc_T1_T0(); gen_movl_T0_reg(rd);