aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/dfp_helper.c
diff options
context:
space:
mode:
authorTom Musta <tommusta@gmail.com>2014-04-21 15:55:18 -0500
committerAlexander Graf <agraf@suse.de>2014-06-16 13:24:32 +0200
commit013c3ac070497b2577ae3be444928963e7ac5ab5 (patch)
treef686d13bdb422c52b1ec5accd1c9e678f2128774 /target-ppc/dfp_helper.c
parent7796676fddc9f6b035c6a9fd872258b53c7d8644 (diff)
target-ppc: Introduce DFP Encode BCD to DPD
Add emulation of the PowerPC Decimal Floating Point Encode Binary Coded Decimal to Densely Packed Decimal instructions denbcd[q][.]. Signed-off-by: Tom Musta <tommusta@gmail.com> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'target-ppc/dfp_helper.c')
-rw-r--r--target-ppc/dfp_helper.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/target-ppc/dfp_helper.c b/target-ppc/dfp_helper.c
index df40da7ca9..c6c104b739 100644
--- a/target-ppc/dfp_helper.c
+++ b/target-ppc/dfp_helper.c
@@ -1049,3 +1049,75 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \
DFP_HELPER_DEDPD(ddedpd, 64)
DFP_HELPER_DEDPD(ddedpdq, 128)
+
+static inline uint8_t dfp_get_bcd_digit_64(uint64_t *t, unsigned n)
+{
+ return *t >> ((n << 2) & 63) & 15;
+}
+
+static inline uint8_t dfp_get_bcd_digit_128(uint64_t *t, unsigned n)
+{
+ return t[(n & 0x10) ? HI_IDX : LO_IDX] >> ((n << 2) & 63) & 15;
+}
+
+#define DFP_HELPER_ENBCD(op, size) \
+void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \
+{ \
+ struct PPC_DFP dfp; \
+ uint8_t digits[32]; \
+ int n = 0, offset = 0, sgn = 0, nonzero = 0; \
+ \
+ dfp_prepare_decimal##size(&dfp, 0, b, env); \
+ \
+ decNumberZero(&dfp.t); \
+ \
+ if (s) { \
+ uint8_t sgnNibble = dfp_get_bcd_digit_##size(dfp.b64, offset++); \
+ switch (sgnNibble) { \
+ case 0xD: \
+ case 0xB: \
+ sgn = 1; \
+ break; \
+ case 0xC: \
+ case 0xF: \
+ case 0xA: \
+ case 0xE: \
+ sgn = 0; \
+ break; \
+ default: \
+ dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \
+ return; \
+ } \
+ } \
+ \
+ while (offset < (size)/4) { \
+ n++; \
+ digits[(size)/4-n] = dfp_get_bcd_digit_##size(dfp.b64, offset++); \
+ if (digits[(size)/4-n] > 10) { \
+ dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \
+ return; \
+ } else { \
+ nonzero |= (digits[(size)/4-n] > 0); \
+ } \
+ } \
+ \
+ if (nonzero) { \
+ decNumberSetBCD(&dfp.t, digits+((size)/4)-n, n); \
+ } \
+ \
+ if (s && sgn) { \
+ dfp.t.bits |= DECNEG; \
+ } \
+ decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \
+ &dfp.context); \
+ dfp_set_FPRF_from_FRT(&dfp); \
+ if ((size) == 64) { \
+ t[0] = dfp.t64[0]; \
+ } else if ((size) == 128) { \
+ t[0] = dfp.t64[HI_IDX]; \
+ t[1] = dfp.t64[LO_IDX]; \
+ } \
+}
+
+DFP_HELPER_ENBCD(denbcd, 64)
+DFP_HELPER_ENBCD(denbcdq, 128)