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