# binary-floating-point helper functions `bfp_*` and related functions as needed by c[ft]fpr* from PowerISA v3.1B Book I section 7.6.2.2 def reset_xflags(): vxsnan_flag <- 0 vximz_flag <- 0 vxidi_flag <- 0 vxisi_flag <- 0 vxzdz_flag <- 0 vxsqrt_flag <- 0 vxcvi_flag <- 0 vxvc_flag <- 0 ox_flag <- 0 ux_flag <- 0 xx_flag <- 0 zx_flag <- 0 def bfp_CONVERT_FROM_BFP64(x): # x is a binary floating-point value represented in # double-precision format. exponent <- x[1:11] fraction <- x[12:63] result <- BFPState() result.sign <- 0 result.exponent <- 0 result.significand <- 0 result.class.SNaN <- 0 result.class.QNaN <- 0 result.class.Infinity <- 0 result.class.Zero <- 0 result.class.Denormal <- 0 result.class.Normal <- 0 if (exponent = 2047) & (fraction[0] = 0) & (fraction != 0) then # x is a SNaN result.class.SNaN <- 1 result.sign <- x[0] result.significand[0] <- 0 result.significand[1:52] <- fraction else if (exponent = 2047) & (fraction[0] != 0) & (fraction != 0) then # x is a QNaN result.class.QNaN <- 1 result.sign <- x[0] result.significand[0] <- 0 result.significand[1:52] <- fraction else if (exponent = 2047) & (fraction = 0) then # is an Infinity result.class.Infinity <- 1 result.sign <- x[0] else if (exponent = 0) & (fraction = 0) then # x is a Zero result.class.Zero <- 1 result.sign <- x[0] else if (exponent = 0) & (fraction != 0) then # x is a Denormal result.class.Denormal <- 1 result.sign <- x[0] result.exponent <- -1022 result.significand[0] <- 0 result.significand[1:52] <- fraction do while result.significand[0] != 1 result.significand <- result.significand * 2 result.exponent <- result.exponent - 1 else result.class.Normal <- 1 result.sign <- x[0] result.exponent <- exponent # have to do the subtraction separately since SelectableInt won't # give negative results result.exponent <- result.exponent - 1023 result.significand[0] <- 1 result.significand[1:52] <- fraction return result def bfp_CONVERT_FROM_BFP32(x): # x is a floating-point value represented in single-precision format. exponent <- x[1:8] fraction <- x[9:31] result <- BFPState() result.sign <- 0 result.exponent <- 0 result.significand <- 0 result.class.SNaN <- 0 result.class.QNaN <- 0 result.class.Infinity <- 0 result.class.Zero <- 0 result.class.Denormal <- 0 result.class.Normal <- 0 if (exponent = 255) & (fraction[0] = 0) & (fraction != 0) then # x is a SNaN result.class.SNaN <- 1 result.sign <- x[0] result.significand[0] <- 0 result.significand[1:23] <- fraction else if (exponent = 255) & (fraction[0] != 0) & (fraction != 0) then # x is a QNaN result.class.QNaN <- 1 result.sign <- x[0] result.significand[0] <- 0 result.significand[1:23] <- fraction else if (exponent = 255) & (fraction = 0) then # is an Infinity result.class.Infinity <- 1 result.sign <- x[0] else if (exponent = 0) & (fraction = 0) then # x is a Zero result.class.Zero <- 1 result.sign <- x[0] else if (exponent = 0) & (fraction != 0) then # x is a Denormal result.class.Denormal <- 1 result.sign <- x[0] result.exponent <- -126 result.significand[0] <- 0 result.significand[1:23] <- fraction do while result.significand[0] != 1 result.significand <- result.significand * 2 result.exponent <- result.exponent - 1 else result.class.Normal <- 1 result.sign <- x[0] result.exponent <- exponent # have to do the subtraction separately since SelectableInt won't # give negative results result.exponent <- result.exponent - 127 result.significand[0] <- 1 result.significand[1:23] <- fraction return result def bfp_CONVERT_FROM_SI32(x): # x is an integer value represented in signed word integer format. result <- BFPState() result.sign <- 0 result.exponent <- 0 result.significand <- 0 result.class.SNaN <- 0 result.class.QNaN <- 0 result.class.Infinity <- 0 result.class.Zero <- 0 result.class.Denormal <- 0 result.class.Normal <- 0 if x = 0x0000_0000 then result.class.Zero <- 1 else result.class.Normal <- 1 result.sign <- x[0] result.exponent <- 32 result.significand[0:32] <- EXTS(x) if result.significand[0] = 1 then result.sign <- 1 result.significand[0:32] <- -result.significand[0:32] do while result.significand[0] = 0 result.significand <- result.significand * 2 result.exponent <- result.exponent - 1 return result def bfp_CONVERT_FROM_SI64(x): # x is an integer value represented in signed double-word integer # format. result <- BFPState() result.sign <- 0 result.exponent <- 0 result.significand <- 0 result.class.SNaN <- 0 result.class.QNaN <- 0 result.class.Infinity <- 0 result.class.Zero <- 0 result.class.Denormal <- 0 result.class.Normal <- 0 if x = 0x0000_0000_0000_0000 then result.class.Zero <- 1 else result.class.Normal <- 1 result.sign <- x[0] result.exponent <- 64 result.significand[0:64] <- EXTS(x) if result.significand[0] = 1 then result.sign <- 1 result.significand[0:64] <- -result.significand[0:64] do while result.significand[0] = 0 result.significand <- result.significand * 2 result.exponent <- result.exponent - 1 return result def bfp_CONVERT_FROM_SI128(x): # x is a 128-bit signed integer value. result <- BFPState() result.sign <- 0 result.exponent <- 0 result.significand <- 0 result.class.SNaN <- 0 result.class.QNaN <- 0 result.class.Infinity <- 0 result.class.Zero <- 0 result.class.Denormal <- 0 result.class.Normal <- 0 if x = 0x0000_0000_0000_0000_0000_0000_0000_0000 then result.class.Zero <- 1 else result.class.Normal <- 1 result.sign <- x[0] result.exponent <- 128 result.significand[0:128] <- EXTS(x) if result.significand[0] = 1 then result.sign <- 1 result.significand[0:128] <- -result.significand[0:128] do while result.significand[0] = 0 result.significand <- result.significand * 2 result.exponent <- result.exponent - 1 return result def bfp_CONVERT_FROM_UI32(x): # x is an integer value represented in unsigned word integer # format. result <- BFPState() result.sign <- 0 result.exponent <- 0 result.significand <- 0 result.class.SNaN <- 0 result.class.QNaN <- 0 result.class.Infinity <- 0 result.class.Zero <- 0 result.class.Denormal <- 0 result.class.Normal <- 0 if x = 0x0000_0000 then result.class.Zero <- 1 else result.class.Normal <- 1 result.sign <- 0 result.exponent <- 32 result.significand[0:32] <- 0b0 || x do while result.significand[0] = 0 result.significand <- result.significand * 2 result.exponent <- result.exponent - 1 return result def bfp_CONVERT_FROM_UI64(x): # x is an integer value represented in unsigned double-word integer # format. result <- BFPState() result.sign <- 0 result.exponent <- 0 result.significand <- 0 result.class.SNaN <- 0 result.class.QNaN <- 0 result.class.Infinity <- 0 result.class.Zero <- 0 result.class.Denormal <- 0 result.class.Normal <- 0 if x = 0x0000_0000_0000_0000 then result.class.Zero <- 1 else result.class.Normal <- 1 result.sign <- 0 result.exponent <- 64 result.significand[0:64] <- 0b0 || x do while result.significand[0] = 0 result.significand <- result.significand * 2 result.exponent <- result.exponent - 1 return result def bfp_CONVERT_FROM_UI128(x): # x is a 128-bit unsigned integer value. result <- BFPState() result.sign <- 0 result.exponent <- 0 result.significand <- 0 result.class.SNaN <- 0 result.class.QNaN <- 0 result.class.Infinity <- 0 result.class.Zero <- 0 result.class.Denormal <- 0 result.class.Normal <- 0 if x = 0x0000_0000_0000_0000_0000_0000_0000_0000 then result.class.Zero <- 1 else result.class.Normal <- 1 result.sign <- 0 result.exponent <- 128 result.significand[0:128] <- 0b0 || x do while result.significand[0] = 0 result.significand <- result.significand * 2 result.exponent <- result.exponent - 1 return result def bfp_ROUND_TO_INTEGER(rmode, x): # x is a binary floating-point value that is represented in the # binary floating-point working format and has # unbounded exponent range and significand precision. if IsSNaN(x) then vxsnan_flag <- 1 if IsNaN(x) & ¬IsSNaN(x) then return x if IsSNaN(x) then result <- x result.class.SNaN <- 0 result.class.QNaN <- 1 return result if IsInf(x) | IsZero(x) then return x result <- x result.class.Denormal <- 0 result.class.Normal <- 0 exact <- 0b0 halfway <- 0b0 more_than_halfway <- 0b0 even <- 0b0 if result.exponent < -1 then # all values have magnitude < 0.5 result.significand <- 0 result.exponent <- 0 even <- 0b1 else if result.exponent = -1 then if result.significand[0] = 1 then result.significand[0] <- 0 if result.significand = 0 then halfway <- 0b1 else more_than_halfway <- 0b1 result.significand <- 0 result.exponent <- 0 even <- 0b1 else result.significand <- 0 int_part <- x.significand[0:x.exponent] result.significand[0:x.exponent] <- int_part even <- ¬int_part[x.exponent] temp <- x.significand temp[0:x.exponent] <- 0 if temp = 0 then exact <- 0b1 if temp[x.exponent + 1] = 1 then temp[x.exponent + 1] <- 0 if temp = 0 then halfway <- 0b1 else more_than_halfway <- 0b1 if rmode = 0b000 then # Round to Nearest Even round_up <- (¬even & halfway) | more_than_halfway if rmode = 0b001 then # Round towards Zero round_up <- 0b0 if rmode = 0b010 then # Round towards +Infinity round_up <- (x.sign = 0) & ¬exact if rmode = 0b011 then # Round towards -Infinity round_up <- (x.sign = 1) & ¬exact if rmode = 0b100 then # Round to Nearest Away round_up <- halfway | more_than_halfway if round_up then inc_flag <- 1 temp <- BFPState() temp.significand <- 0 temp.significand[result.exponent] <- 1 result.significand <- result.significand + temp.significand if result.significand >= 2 then result.significand <- truediv(result.significand, 2) result.exponent <- result.exponent + 1 else inc_flag <- 0 # TODO: does the spec specify this? if result.significand = 0 then result.class.Zero <- 1 else result.class.Normal <- 1 if ¬bfp_COMPARE_EQ(result, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? return result def bfp_ROUND_TO_INTEGER_NEAR_EVEN(x): return bfp_ROUND_TO_INTEGER(0b000, x) def bfp_ROUND_TO_INTEGER_TRUNC(x): return bfp_ROUND_TO_INTEGER(0b001, x) def bfp_ROUND_TO_INTEGER_CEIL(x): return bfp_ROUND_TO_INTEGER(0b010, x) def bfp_ROUND_TO_INTEGER_FLOOR(x): return bfp_ROUND_TO_INTEGER(0b011, x) def bfp_ROUND_TO_INTEGER_NEAR_AWAY(x): return bfp_ROUND_TO_INTEGER(0b100, x) def bfp_COMPARE_EQ(x, y): # x is a binary floating-point value represented in the # binary floating-point working format. # y is a binary floating-point value represented in the # binary floating-point working format. if IsNaN(x) | IsNaN(y) then return 0b0 if IsZero(x) & IsZero(y) then return 0b1 if IsInf(x) & IsInf(y) then return x.sign = y.sign if IsInf(x) | IsInf(y) then return 0b0 if IsZero(x) | IsZero(y) then return 0b0 if x.sign != y.sign then return 0b0 if x.exponent > 0 then xs <- x.significand * pow(2, x.exponent) else xs <- truediv(x.significand, pow(2, -x.exponent)) if y.exponent > 0 then ys <- y.significand * pow(2, y.exponent) else ys <- truediv(y.significand, pow(2, -y.exponent)) return xs = ys def bfp_COMPARE_GT(x, y): # x is a binary floating-point value represented in the # binary floating-point working format. # y is a binary floating-point value represented in the # binary floating-point working format. if IsNaN(x) | IsNaN(y) then return 0b0 if IsZero(x) & IsZero(y) then return 0b0 if IsInf(x) & IsInf(y) then return ¬IsNeg(x) & IsNeg(y) if IsInf(x) then return ¬IsNeg(x) if IsInf(y) then return IsNeg(y) if IsZero(x) then return IsNeg(y) if IsZero(y) then return ¬IsNeg(x) if x.sign != y.sign then return IsNeg(y) if x.exponent > 0 then xs <- x.significand * pow(2, x.exponent) else xs <- truediv(x.significand, pow(2, -x.exponent)) if y.exponent > 0 then ys <- y.significand * pow(2, y.exponent) else ys <- truediv(y.significand, pow(2, -y.exponent)) if x.sign = 1 then return xs < ys return xs > ys def bfp_COMPARE_LT(x, y): # x is a binary floating-point value represented in the # binary floating-point working format. # y is a binary floating-point value represented in the # binary floating-point working format. if IsNaN(x) | IsNaN(y) then return 0b0 if IsZero(x) & IsZero(y) then return 0b0 if IsInf(x) & IsInf(y) then return IsNeg(x) & ¬IsNeg(y) if IsInf(x) then return IsNeg(x) if IsInf(y) then return ¬IsNeg(y) if IsZero(x) then return ¬IsNeg(y) if IsZero(y) then return IsNeg(x) if x.sign != y.sign then return IsNeg(x) if x.exponent > 0 then xs <- x.significand * pow(2, x.exponent) else xs <- truediv(x.significand, pow(2, -x.exponent)) if y.exponent > 0 then ys <- y.significand * pow(2, y.exponent) else ys <- truediv(y.significand, pow(2, -y.exponent)) if x.sign = 1 then return xs > ys return xs < ys def bfp_ABSOLUTE(x): # x is a binary floating-point value represented in the # binary floating-point working format. result <- x result.sign <- 0 return result def si32_CONVERT_FROM_BFP(x): # x is an integer value represented in the # binary floating-point working format. if IsNaN(x) then vxcvi_flag <- 1 if IsSNaN(x) then vxsnan_flag <- 1 return 0x8000_0000 else temp_xx <- xx_flag temp_inc <- inc_flag rnd <- bfp_ROUND_TO_INTEGER_TRUNC(x) # TODO: does the spec say these are preserved? xx_flag <- temp_xx inc_flag <- temp_inc exponent <- rnd.exponent significand <- rnd.significand si32max <- bfp_CONVERT_FROM_SI32(0b0 || [1] * 31) si32min <- bfp_CONVERT_FROM_SI32(0b1 || [0] * 31) if bfp_COMPARE_GT(rnd, si32max) then vxcvi_flag <- 1 return 0x7FFF_FFFF if bfp_COMPARE_LT(rnd, si32min) then vxcvi_flag <- 1 return 0x8000_0000 else if ¬bfp_COMPARE_EQ(rnd, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? inc_flag <- 0 # TODO: spec says this is logical shift right: significand <- significand[0:31] / pow(2, 31 - exponent) if IsNeg(rnd) then significand <- -significand return significand[0:31] def si64_CONVERT_FROM_BFP(x): # x is an integer value represented in the # binary floating-point working format. if IsNaN(x) then vxcvi_flag <- 1 if IsSNaN(x) then vxsnan_flag <- 1 return 0x8000_0000_0000_0000 else temp_xx <- xx_flag temp_inc <- inc_flag rnd <- bfp_ROUND_TO_INTEGER_TRUNC(x) # TODO: does the spec say these are preserved? xx_flag <- temp_xx inc_flag <- temp_inc exponent <- rnd.exponent significand <- rnd.significand si64max <- bfp_CONVERT_FROM_SI64(0b0 || [1] * 63) si64min <- bfp_CONVERT_FROM_SI64(0b1 || [0] * 63) if bfp_COMPARE_GT(rnd, si64max) then vxcvi_flag <- 1 return 0x7FFF_FFFF_FFFF_FFFF if bfp_COMPARE_LT(rnd, si64min) then vxcvi_flag <- 1 return 0x8000_0000_0000_0000 else if ¬bfp_COMPARE_EQ(rnd, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? inc_flag <- 0 # TODO: spec says this is logical shift right: significand <- significand[0:63] / pow(2, 63 - exponent) if IsNeg(rnd) then significand <- -significand return significand[0:63] def si128_CONVERT_FROM_BFP(x): # x is an integer value represented in the # binary floating-point working format. if IsNaN(x) then vxcvi_flag <- 1 if IsSNaN(x) then vxsnan_flag <- 1 return 0x8000_0000_0000_0000_0000_0000_0000_0000 else temp_xx <- xx_flag temp_inc <- inc_flag rnd <- bfp_ROUND_TO_INTEGER_TRUNC(x) # TODO: does the spec say these are preserved? xx_flag <- temp_xx inc_flag <- temp_inc exponent <- rnd.exponent significand <- rnd.significand si128max <- bfp_CONVERT_FROM_SI128(0b0 || [1] * 127) si128min <- bfp_CONVERT_FROM_SI128(0b1 || [0] * 127) if bfp_COMPARE_GT(rnd, si128max) then vxcvi_flag <- 1 return 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF if bfp_COMPARE_LT(rnd, si128min) then vxcvi_flag <- 1 return 0x8000_0000_0000_0000_0000_0000_0000_0000 else if ¬bfp_COMPARE_EQ(rnd, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? inc_flag <- 0 # TODO: spec says this is logical shift right: significand <- significand[0:127] / pow(2, 127 - exponent) if IsNeg(rnd) then significand <- -significand return significand[0:127] def ui32_CONVERT_FROM_BFP(x): # x is an integer value represented in the # binary floating-point working format. if IsNaN(x) then vxcvi_flag <- 1 if IsSNaN(x) then vxsnan_flag <- 1 return 0x0000_0000 else temp_xx <- xx_flag temp_inc <- inc_flag rnd <- bfp_ROUND_TO_INTEGER_TRUNC(x) # TODO: does the spec say these are preserved? xx_flag <- temp_xx inc_flag <- temp_inc exponent <- rnd.exponent significand <- rnd.significand ui32max <- bfp_CONVERT_FROM_UI32([1] * 32) if bfp_COMPARE_GT(rnd, ui32max) then vxcvi_flag <- 1 return 0xFFFF_FFFF if IsNeg(rnd) then vxcvi_flag <- 1 return 0x0000_0000 else if ¬bfp_COMPARE_EQ(rnd, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? inc_flag <- 0 # TODO: spec says this is logical shift right: significand <- significand[0:31] / pow(2, 31 - exponent) return significand[0:31] def ui64_CONVERT_FROM_BFP(x): # x is an integer value represented in the # binary floating-point working format. if IsNaN(x) then vxcvi_flag <- 1 if IsSNaN(x) then vxsnan_flag <- 1 return 0x0000_0000_0000_0000 else temp_xx <- xx_flag temp_inc <- inc_flag rnd <- bfp_ROUND_TO_INTEGER_TRUNC(x) # TODO: does the spec say these are preserved? xx_flag <- temp_xx inc_flag <- temp_inc exponent <- rnd.exponent significand <- rnd.significand ui64max <- bfp_CONVERT_FROM_UI64([1] * 64) if bfp_COMPARE_GT(rnd, ui64max) then vxcvi_flag <- 1 return 0xFFFF_FFFF_FFFF_FFFF if IsNeg(rnd) then vxcvi_flag <- 1 return 0x0000_0000_0000_0000 else if ¬bfp_COMPARE_EQ(rnd, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? inc_flag <- 0 # TODO: spec says this is logical shift right: significand <- significand[0:63] / pow(2, 63 - exponent) return significand[0:63] def ui128_CONVERT_FROM_BFP(x): # x is an integer value represented in the # binary floating-point working format. if IsNaN(x) then vxcvi_flag <- 1 if IsSNaN(x) then vxsnan_flag <- 1 return 0x0000_0000_0000_0000_0000_0000_0000_0000 else temp_xx <- xx_flag temp_inc <- inc_flag rnd <- bfp_ROUND_TO_INTEGER_TRUNC(x) # TODO: does the spec say these are preserved? xx_flag <- temp_xx inc_flag <- temp_inc exponent <- rnd.exponent significand <- rnd.significand ui128max <- bfp_CONVERT_FROM_UI128([1] * 128) if bfp_COMPARE_GT(rnd, ui128max) then vxcvi_flag <- 1 return 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF if IsNeg(rnd) then vxcvi_flag <- 1 return 0x0000_0000_0000_0000_0000_0000_0000_0000 else if ¬bfp_COMPARE_EQ(rnd, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? inc_flag <- 0 # TODO: spec says this is logical shift right: significand <- significand[0:127] / pow(2, 127 - exponent) return significand[0:127] def bfp64_CONVERT_FROM_BFP(x): # x is a floating-point value represented in the binary floating-point # working format. result <- [0] * 64 if x.class.QNaN = 1 then result[0] <- x.sign result[1:11] <- 0b111_1111_1111 result[12:63] <- x.significand[1:52] else if x.class.Infinity = 1 then result[0] <- x.sign result[1:11] <- 0b111_1111_1111 result[12:63] <- 0 else if x.class.Zero = 1 then result[0] <- x.sign result[1:63] <- 0 else if (x.exponent < -1022) & (FPSCR.UE = 0) then result[0] <- x.sign sh_cnt <- -1022 - x.exponent result[1:11] <- 0b000_0000_0000 # TODO: spec says this is shift right result[12:63] <- x.significand[1:52] / pow(2, sh_cnt) else if (x.exponent < -1022) & (FPSCR.UE = 1) then result[0:63] <- undefined(0) # TODO: which undefined value to use? else if (x.exponent > 1023) & (FPSCR.OE = 1) then result[0:63] <- undefined(0) # TODO: which undefined value to use? else result[0] <- x.sign result[1:11] <- x.exponent + 1023 result[12:63] <- x.significand[1:52] return result def bfp32_CONVERT_FROM_BFP(x): # x is a floating-point value represented in the binary floating-point # working format. result <- [0] * 32 if x.class.QNaN = 1 then result[0] <- x.sign result[1:8] <- 0b1111_1111 result[9:31] <- x.significand[1:23] else if x.class.Infinity = 1 then result[0] <- x.sign result[1:9] <- 0b1111_1111 result[9:31] <- 0 else if x.class.Zero = 1 then result[0] <- x.sign result[1:31] <- 0 else if (x.exponent < -126) & (FPSCR.UE = 0) then result[0] <- x.sign sh_cnt <- -126 - x.exponent result[1:8] <- 0b0000_0000 # TODO: spec says this is shift right result[9:31] <- x.significand[1:23] / pow(2, sh_cnt) else if (x.exponent < -126) & (FPSCR.UE = 1) then result[0:31] <- undefined(0) # TODO: which undefined value to use? else if (x.exponent > 127) & (FPSCR.OE = 1) then result[0:31] <- undefined(0) # TODO: which undefined value to use? else result[0] <- x.sign result[1:8] <- x.exponent + 127 result[9:31] <- x.significand[1:23] return result def bfp_ROUND_TO_BFP64(ro, rmode, x): # x is a normalized binary floating-point value that is represented in # the binary floating-point working format and has unbounded exponent # range and significand precision. # ro is a 1-bit unsigned integer and rmode is a 2-bit unsigned integer, # together specifying one of five rounding modes to be used in # rounding x. # # ro=0 rmode=0b00 Round to Nearest Even # ro=0 rmode=0b01 Round towards Zero # ro=0 rmode=0b10 Round towards +Infinity # ro=0 rmode=0b11 Round towards -Infinity # ro=1 Round to Odd # # Return the value x rounded to double-precision under control of the # specified rounding mode. if x.class.QNaN then return x if x.class.Infinity then return x if x.class.Zero then return x if bfp_COMPARE_LT(bfp_ABSOLUTE(x), bfp_NMIN_BFP64()) then if FPSCR.UE=0 then x <- bfp_DENORM(-1022, x) if (ro=0) & (rmode=0b00) then r <- bfp_ROUND_NEAR_EVEN(53, x) if (ro=0) & (rmode=0b01) then r <- bfp_ROUND_TRUNC(53, x) if (ro=0) & (rmode=0b10) then r <- bfp_ROUND_CEIL(53, x) if (ro=0) & (rmode=0b11) then r <- bfp_ROUND_FLOOR(53, x) if ro=1 then r <- bfp_ROUND_ODD(53, x) ux_flag <- xx_flag return r else x.exponent <- x.exponent + 1536 ux_flag <- 1 if (ro=0) & (rmode=0b00) then r <- bfp_ROUND_NEAR_EVEN(53, x) if (ro=0) & (rmode=0b01) then r <- bfp_ROUND_TRUNC(53, x) if (ro=0) & (rmode=0b10) then r <- bfp_ROUND_CEIL(53, x) if (ro=0) & (rmode=0b11) then r <- bfp_ROUND_FLOOR(53, x) if ro=1 then r <- bfp_ROUND_ODD(53, x) if bfp_COMPARE_GT(bfp_ABSOLUTE(r), bfp_NMAX_BFP64()) then if FPSCR.OE=0 then if (ro=0) & (rmode=0b00) then r <- x.sign ? bfp_INFINITY() : bfp_INFINITY() if (ro=0) & (rmode=0b01) then r <- x.sign ? bfp_NMAX_BFP64() : bfp_NMAX_BFP64() if (ro=0) & (rmode=0b10) then r <- x.sign ? bfp_NMAX_BFP64() : bfp_INFINITY() if (ro=0) & (rmode=0b11) then r <- x.sign ? bfp_INFINITY() : bfp_NMAX_BFP64() if ro=1 then r <- x.sign ? bfp_NMAX_BFP64() : bfp_NMAX_BFP64() r.sign <- x.sign ox_flag <- 0b1 xx_flag <- 0b1 inc_flag <- undefined(0) # TODO: which undefined value to use? return r else r.exponent <- r.exponent - 1536 ox_flag <- 1 return r def bfp_ROUND_TO_BFP32(rmode,x): # x is a normalized binary floating-point value that is represented in # the binary floating-point working format and has unbounded exponent # range and significand precision. # # rmode is a 2-bit integer value specifying one of four rounding modes. # # rmode=0b00 Round to Nearest Even # rmode=0b01 Round towards Zero # rmode=0b10 Round towards +Infinity # rmode=0b11 Round towards - Infinity # # If x is a QNaN, Infinity, or Zero, return x. Otherwise, if x is an # SNaN, set vxsnan_flag to 1 and return the corresponding QNaN # representation of x. Otherwise, return the value x rounded to # single-precision format’s exponent range and significand precision # represented in the floating-point working format using the rounding # mode specified by rmode. if x.class.SNaN then vxsnan_flag <- 1 return bfp_QUIET(x) if x.class.QNaN then return x if x.class.Infinity then return x if x.class.Zero then return x if bfp_COMPARE_LT(bfp_ABSOLUTE(x), bfp_NMIN_BFP32()) then x <- bfp_DENORM(-126,x) if rmode = 0b00 then r <- bfp_ROUND_NEAR_EVEN(24, x) if rmode = 0b01 then r <- bfp_ROUND_TRUNC(24, x) if rmode = 0b10 then r <- bfp_ROUND_CEIL(24, x) if rmode = 0b11 then r <- bfp_ROUND_FLOOR(24, x) if FPSCR.UE = 0 then ux_flag <- xx_flag return r else x.exponent <- x.exponent + 192 ux_flag <- 0b1 if rmode = 0b00 then r <- bfp_ROUND_NEAR_EVEN(24, x) if rmode = 0b01 then r <- bfp_ROUND_TRUNC(24, x) if rmode = 0b10 then r <- bfp_ROUND_CEIL(24, x) if rmode = 0b11 then r <- bfp_ROUND_FLOOR(24, x) if bfp_COMPARE_GT(bfp_ABSOLUTE(r), bfp_NMAX_BFP32()) then if FPSCR.OE = 0 then if rmode=0b00 then r <- x.sign ? bfp_INFINITY() : bfp_INFINITY() if rmode=0b01 then r <- x.sign ? bfp_NMAX_BFP32() : bfp_NMAX_BFP32() if rmode=0b10 then r <- x.sign ? bfp_NMAX_BFP32() : bfp_INFINITY() if rmode=0b11 then r <- x.sign ? bfp_INFINITY() : bfp_NMAX_BFP32() r.sign <- x.sign ox_flag <- 0b1 xx_flag <- 0b1 inc_flag <- undefined(0) # TODO: which undefined value to use? return r else r.exponent <- r.exponent - 192 ox_flag <- 0b1 return r def bfp_INFINITY(): # The value +Infinity represented in the binary floating-point working # format. r <- BFPState() r.class.Infinity <- 1 return r def bfp_NMAX_BFP32(): # Return the largest finite single-precision floating-point value # (i.e., 2^128 - 2^(128-24)) in the binary floating-point working # format. return bfp_CONVERT_FROM_BFP32(0x7F7F_FFFF) def bfp_NMAX_BFP64(): # Return the largest finite double-precision floating-point value # (i.e., 2^1024 - 2^(1024-53)) in the binary floating-point working # format. return bfp_CONVERT_FROM_BFP64(0x7FEF_FFFF_FFFF_FFFF) def bfp_NMIN_BFP32(): # Return the smallest positive normalized single-precision # floating-point value, 2^-126, represented in the binary # floating-point working format. return bfp_CONVERT_FROM_BFP32(0x0080_0000) def bfp_NMIN_BFP64(): # Return the smallest positive normalized double-precision # floating-point value, 2^-1022, represented in the binary # floating-point working format. return bfp_CONVERT_FROM_BFP64(0x0010_0000_0000_0000) def bfp_ROUND_HELPER(p, ro, rmode, x): # not part of the PowerISA v3.1B specification. # helper function for the bfp_ROUND_* functions. # doesn't set inc_flag or xx_flag. # # x is a binary floating-point value that is represented in the binary # floating-point working format and has unbounded exponent range and # significand precision. x must be rounded as presented, without # prenormalization. # # p is an integer value specifying the precision (i.e., number of bits) # the significand is rounded to. # # ro is a 1-bit unsigned integer and rmode is a 3-bit unsigned integer, # together specifying one of six rounding modes to be used in # rounding x. # # ro=0 rmode=0b000 Round to Nearest Even # ro=0 rmode=0b001 Round towards Zero # ro=0 rmode=0b010 Round towards +Infinity # ro=0 rmode=0b011 Round towards -Infinity # ro=0 rmode=0b100 Round to Nearest Away # ro=1 Round to Odd if IsInf(x) | IsNaN(x) | IsZero(x) then inc_flag <- 0 # TODO: does the spec specify this? xx_flag <- 0 # TODO: does the spec specify this? return x result <- x result.significand <- 0 result.significand[0:p - 1] <- x.significand[0:p - 1] exact <- x.significand = result.significand halfway <- 0b0 more_than_half <- 0b0 if x.significand[p] then t <- x t.significand <- 0 t.significand[0:p] <- x.significand[0:p] if t.significand = x.significand then halfway <- 0b1 else more_than_half <- 0b1 even <- ¬result.significand[p - 1] if (ro=0) & (rmode=0b000) then # Round to Nearest Even round_up <- (halfway & ¬even) | more_than_half if (ro=0) & (rmode=0b001) then # Round towards Zero round_up <- 0b0 if (ro=0) & (rmode=0b010) then # Round towards +Infinity round_up <- (x.sign = 0) & ¬exact if (ro=0) & (rmode=0b011) then # Round towards -Infinity round_up <- (x.sign = 1) & ¬exact if (ro=0) & (rmode=0b100) then # Round to Nearest Away round_up <- halfway | more_than_half if ro=1 then # Round to Odd round_up <- ¬exact & even if round_up then result.significand[0:p-1] <- result.significand[0:p-1] + 1 if result.significand[0:p-1] = 0 then result.significand[0] <- 1 result.exponent <- result.exponent + 1 if result.significand != 0 then do while result.significand[0] != 1 result.significand <- result.significand * 2 result.exponent <- result.exponent - 1 result.class.Normal <- 1 result.class.Denormal <- 0 result.class.Zero <- 0 else result.class.Normal <- 0 result.class.Denormal <- 0 result.class.Zero <- 1 return result def bfp_ROUND_NEAR_EVEN(p, x): # x is a binary floating-point value that is represented in the binary # floating-point working format and has unbounded exponent range and # significand precision. x must be rounded as presented, without # prenormalization. # # p is an integer value specifying the precision (i.e., number of bits) # the significand is rounded to. result <- bfp_ROUND_HELPER(p, 0b0, 0b000, x) if bfp_COMPARE_GT(bfp_ABSOLUTE(result), bfp_ABSOLUTE(x)) then inc_flag <- 1 else inc_flag <- 0 # TODO: does the spec specify this? if ¬bfp_COMPARE_EQ(result, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? return result def bfp_ROUND_TRUNC(p, x): # x is a binary floating-point value that is represented in the binary # floating-point working format and has unbounded exponent range and # significand precision. x must be rounded as presented, without # prenormalization. # # p is an integer value specifying the precision (i.e., number of bits) # the significand is rounded to. result <- bfp_ROUND_HELPER(p, 0b0, 0b001, x) if bfp_COMPARE_GT(bfp_ABSOLUTE(result), bfp_ABSOLUTE(x)) then inc_flag <- 1 else inc_flag <- 0 # TODO: does the spec specify this? if ¬bfp_COMPARE_EQ(result, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? return result def bfp_ROUND_CEIL(p, x): # x is a binary floating-point value that is represented in the binary # floating-point working format and has unbounded exponent range and # significand precision. x must be rounded as presented, without # prenormalization. # # p is an integer value specifying the precision (i.e., number of bits) # the significand is rounded to. result <- bfp_ROUND_HELPER(p, 0b0, 0b010, x) if bfp_COMPARE_GT(bfp_ABSOLUTE(result), bfp_ABSOLUTE(x)) then inc_flag <- 1 else inc_flag <- 0 # TODO: does the spec specify this? if ¬bfp_COMPARE_EQ(result, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? return result def bfp_ROUND_FLOOR(p, x): # x is a binary floating-point value that is represented in the binary # floating-point working format and has unbounded exponent range and # significand precision. x must be rounded as presented, without # prenormalization. # # p is an integer value specifying the precision (i.e., number of bits) # the significand is rounded to. result <- bfp_ROUND_HELPER(p, 0b0, 0b011, x) if bfp_COMPARE_GT(bfp_ABSOLUTE(result), bfp_ABSOLUTE(x)) then inc_flag <- 1 else inc_flag <- 0 # TODO: does the spec specify this? if ¬bfp_COMPARE_EQ(result, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? return result def bfp_ROUND_NEAR_AWAY(p, x): # not part of the PowerISA v3.1B specification. # # x is a binary floating-point value that is represented in the binary # floating-point working format and has unbounded exponent range and # significand precision. x must be rounded as presented, without # prenormalization. # # p is an integer value specifying the precision (i.e., number of bits) # the significand is rounded to. result <- bfp_ROUND_HELPER(p, 0b0, 0b100, x) if bfp_COMPARE_GT(bfp_ABSOLUTE(result), bfp_ABSOLUTE(x)) then inc_flag <- 1 else inc_flag <- 0 # TODO: does the spec specify this? if ¬bfp_COMPARE_EQ(result, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? return result def bfp_ROUND_ODD(p, x): # x is a binary floating-point value that is represented in the binary # floating-point working format and has unbounded exponent range and # significand precision. x must be rounded as presented, without # prenormalization. # # p is an integer value specifying the precision (i.e., number of bits) # the significand is rounded to. result <- bfp_ROUND_HELPER(p, 0b1, 0b000, x) if bfp_COMPARE_GT(bfp_ABSOLUTE(result), bfp_ABSOLUTE(x)) then inc_flag <- 1 else inc_flag <- 0 # TODO: does the spec specify this? if ¬bfp_COMPARE_EQ(result, x) then xx_flag <- 1 else xx_flag <- 0 # TODO: does the spec specify this? return result def fprf_CLASS_BFP64(x): # x is a floating-point value represented in double-precision format. # # Return the 5-bit code that specifies the sign and class of x. v <- bfp_CONVERT_FROM_BFP64(x) if v.class.QNaN then return 0b10001 if (v.sign = 1) & v.class.Infinity then return 0b01001 if (v.sign = 0) & v.class.Infinity then return 0b00101 if (v.sign = 1) & v.class.Zero then return 0b10010 if (v.sign = 0) & v.class.Zero then return 0b00010 if (v.sign = 1) & v.class.Denormal then return 0b11000 if (v.sign = 0) & v.class.Denormal then return 0b10100 if (v.sign = 1) & v.class.Normal then return 0b01000 if (v.sign = 0) & v.class.Normal then return 0b00100 def fprf_CLASS_BFP32(x): # x is a floating-point value represented in single-precision format. # # Return the 5-bit code that specifies the sign and class of x. v <- bfp_CONVERT_FROM_BFP32(x) if v.class.QNaN then return 0b10001 if (v.sign = 1) & v.class.Infinity then return 0b01001 if (v.sign = 0) & v.class.Infinity then return 0b00101 if (v.sign = 1) & v.class.Zero then return 0b10010 if (v.sign = 0) & v.class.Zero then return 0b00010 if (v.sign = 1) & v.class.Denormal then return 0b11000 if (v.sign = 0) & v.class.Denormal then return 0b10100 if (v.sign = 1) & v.class.Normal then return 0b01000 if (v.sign = 0) & v.class.Normal then return 0b00100