import unittest
import struct
+import sys
from openpower.decoder.selectable_int import (SelectableInt, onebit,
- selectconcat)
+ selectconcat, FieldSelectableInt)
+from openpower.decoder.selectable_int import EFFECTIVELY_UNLIMITED as EU
from nmutil.divmod import trunc_divs, trunc_rems
-from operator import floordiv, mod
+from operator import floordiv, mod, truediv # truediv used by bfp_* functions
from openpower.decoder.selectable_int import selectltu as ltu
from openpower.decoder.selectable_int import selectgtu as gtu
from openpower.decoder.selectable_int import check_extsign
+from openpower.fpscr import FPSCRState
+from openpower.xer import XERState
+from openpower.decoder.isa.svshape import SVSHAPE
+from openpower.decoder.isa.svstate import SVP64State
+from openpower.decoder.fp_working_format import (
+ BFPState, SelectableMSB0Fraction)
from openpower.util import log
+import math
trunc_div = floordiv
trunc_rem = mod
"""
Links:
* https://bugs.libre-soc.org/show_bug.cgi?id=324 - add trunc_div and trunc_rem
+* https://bugs.libre-soc.org/show_bug.cgi?id=671#c38 - RANGE (and bugfixes)
"""
+def RANGE(start, end):
+ if start > end:
+ # reverse direction
+ # auto-subtract-one (sigh) due to python range
+ return range(start, end-1, -1)
+ # auto-add-one (sigh) due to python range
+ return range(start, end+1)
+
+
def exts(value, bits):
sign = 1 << (bits - 1)
return (value & (sign - 1)) - (value & sign)
def EXTS(value):
- """ extends sign bit out from current MSB to all 256 bits
+ """ extends sign bit out from current MSB to MAX limit bits
"""
- log ("EXTS", value, type(value))
+ log("EXTS", value, type(value))
assert isinstance(value, SelectableInt)
- return SelectableInt(exts(value.value, value.bits) & ((1 << 256)-1), 256)
+ return SelectableInt(exts(value.value, value.bits) & ((1 << EU)-1), EU)
+
+
+def EXTZ(value):
+ """ zero extend to EFFECTIVELY_UNLIMITED bits
+ """
+ if isinstance(value, SelectableInt):
+ value = value.value
+ return SelectableInt(value & ((1 << EU) - 1), EU)
def EXTS64(value):
return SelectableInt(exts(value.value, value.bits) & ((1 << 128)-1), 128)
+def copy_assign_rhs(inp):
+ """ implicitly added function call to all assignment RHSes.
+ This copies the passed-in value so later assignments to parts of the
+ LHS don't modify the RHS if it's a SelectableInt.
+
+ Example:
+ ```
+ # this needs to copy the SelectableInt instance in RA
+ # not just assign a reference to it to A
+ A <- RA
+ A[0] <- 1 # if the copy wasn't performed, we just modified RA too!
+ ```
+ """
+ if isinstance(inp, (str, int)):
+ return inp
+ if isinstance(inp, FPSCRState):
+ return FPSCRState(inp)
+ if isinstance(inp, XERState):
+ return XERState(inp)
+ if isinstance(inp, SVSHAPE):
+ return SVSHAPE(inp)
+ if isinstance(inp, SVP64State):
+ return SVP64State(inp)
+ if isinstance(inp, (SelectableInt, FieldSelectableInt)):
+ return SelectableInt(inp)
+ if isinstance(inp, BFPState):
+ return BFPState(inp)
+ if isinstance(inp, SelectableMSB0Fraction):
+ return SelectableMSB0Fraction(inp)
+ if isinstance(inp, tuple):
+ return tuple(map(copy_assign_rhs, inp))
+ if isinstance(inp, dict):
+ return {copy_assign_rhs(k): copy_assign_rhs(v) for k, v in inp.items()}
+ raise TypeError("tried to assign an unsupported type in pseudo-code",
+ repr(type(inp)))
+
+
# signed version of MUL
def MULS(a, b):
if isinstance(b, int):
return ((value << bits) | (value >> (wordlen-bits))) & mask
-def ROTL64(value, bits):
- return rotl(value, bits, 64)
-
-
-def ROTL32(value, bits):
+def SHL64(value, bits, wordlen=64):
if isinstance(bits, SelectableInt):
bits = bits.value
- if isinstance(value, SelectableInt):
- value = SelectableInt(value.value, 64)
- return rotl(value | (value << 32), bits, 64)
-
-def MASK32(x, y):
- if isinstance(x, SelectableInt):
- x = x.value
- if isinstance(y, SelectableInt):
- y = y.value
- return MASK(x+32, y+32)
-
-def MASK(x, y):
- if isinstance(x, SelectableInt):
- x = x.value
- if isinstance(y, SelectableInt):
- y = y.value
- if x < y:
- x = 64-x
- y = 63-y
- mask_a = ((1 << x) - 1) & ((1 << 64) - 1)
- mask_b = ((1 << y) - 1) & ((1 << 64) - 1)
- elif x == y:
- return 1 << (63-x)
- else:
- x = 64-x
- y = 63-y
- mask_a = ((1 << x) - 1) & ((1 << 64) - 1)
- mask_b = (~((1 << y) - 1)) & ((1 << 64) - 1)
- return mask_a ^ mask_b
+ mask = (1 << wordlen) - 1
+ bits = bits & (wordlen - 1)
+ return SelectableInt((value << bits) & mask, 64)
def ne(a, b):
"""
return v
-def DOUBLE(WORD):
- """convert incoming WORD to double. v3.0B p140 section 4.6.2
- """
- # result, FRT, start off all zeros
- log ("WORD", WORD)
- FRT = SelectableInt(0, 64)
- z1 = SelectableInt(0, 1)
- z29 = SelectableInt(0, 29)
- e = WORD[1:9]
- m = WORD[9:32]
- s = WORD[0]
- log ("word s e m", s, e, m)
-
- # Normalized Operand
- if e.value > 0 and e.value < 255:
- log ("normalised")
- FRT[0:2] = WORD[0:2]
- FRT[2] = ~WORD[1]
- FRT[3] = ~WORD[1]
- FRT[4] = ~WORD[1]
- FRT[5:64] = selectconcat(WORD[2:32], z29)
-
- # Denormalized Operand
- if e.value == 0 and m.value != 0:
- log ("denormalised")
- sign = WORD[0]
- exp = -126
- frac = selectconcat(z1, WORD[9:32], z29)
- # normalize the operand
- while frac[0].value == 0:
- frac[0:53] = selectconcat(frac[1:53], z1)
- exp = exp - 1
- FRT[0] = sign
- FRT[1:12] = exp + 1023
- FRT[12:64] = frac[1:53]
-
- # Zero / Infinity / NaN
- if e.value == 255 or WORD[1:32].value == 0:
- log ("z/inf/nan")
- FRT[0:2] = WORD[0:2]
- FRT[2] = WORD[1]
- FRT[3] = WORD[1]
- FRT[4] = WORD[1]
- FRT[5:64] = selectconcat(WORD[2:32], z29)
-
- log ("Double s e m", FRT[0].value, FRT[1:12].value-1023,
- FRT[12:64].value)
-
- return FRT
-
def SINGLE(FRS):
"""convert incoming FRS into 32-bit word. v3.0B p144 section 4.6.3
m = FRS[12:64]
s = FRS[0]
- log ("SINGLE", FRS)
- log ("s e m", s.value, e.value, m.value)
-
- #No Denormalization Required (includes Zero / Infinity / NaN)
- if e.value > 896 or FRS[1:64].value == 0:
- log("nodenorm", FRS[0:2].value, hex(FRS[5:35].value))
- WORD[0:2] = FRS[0:2]
- WORD[2:32] = FRS[5:35]
-
- #Denormalization Required
- if e.value >= 874 and e.value <= 896:
- sign = FRS[0]
- exp = e.value - 1023
- frac = selectconcat(SelectableInt(1, 1), FRS[12:64])
- log("exp, fract", exp, hex(frac.value))
- # denormalize operand
- while exp < -126:
- frac[0:53] = selectconcat(SelectableInt(0, 1), frac[0:52])
- exp = exp + 1
- WORD[0] = sign
- WORD[1:9] = SelectableInt(0, 8)
- WORD[9:32] = frac[1:24]
- #else WORD = undefined # return zeros
-
- log ("WORD", WORD)
+ log("SINGLE", FRS)
+ log("s e m", s.value, e.value, m.value)
+
+ # No Denormalization Required (includes Zero / Infinity / NaN)
+ if e.value > 896 or FRS[1:64].value == 0:
+ log("nodenorm", FRS[0:2].value, hex(FRS[5:35].value))
+ WORD[0:2] = FRS[0:2]
+ WORD[2:32] = FRS[5:35]
+
+ # Denormalization Required
+ if e.value >= 874 and e.value <= 896:
+ sign = FRS[0]
+ exp = e.value - 1023
+ frac = selectconcat(SelectableInt(1, 1), FRS[12:64])
+ log("exp, fract", exp, hex(frac.value))
+ # denormalize operand
+ while exp < -126:
+ frac[0:53] = selectconcat(SelectableInt(0, 1), frac[0:52])
+ exp = exp + 1
+ WORD[0] = sign
+ WORD[1:9] = SelectableInt(0, 8)
+ WORD[9:32] = frac[1:24]
+ # else WORD = undefined # return zeros
+
+ log("WORD", WORD)
return WORD
# XXX NOTE: these are very quick hacked functions for utterly basic
# FP support
-def fp64toselectable(frt):
+
+def signinv(res, sign):
+ if sign == 1:
+ return res
+ if sign == 0:
+ return 0.0
+ if sign == -1:
+ return -res
+
+
+def fp32toselectable(flt):
+ """convert FP number to 32 bit SelectableInt
+ """
+ b = struct.pack("<f", flt)
+ val = int.from_bytes(b, byteorder='little', signed=False)
+ return SelectableInt(val, 32)
+
+
+def fp64toselectable(flt):
"""convert FP number to 64 bit SelectableInt
"""
- b = struct.pack(">d", frt)
- val = int.from_bytes(b, byteorder='big', signed=False)
+ b = struct.pack("<d", flt)
+ val = int.from_bytes(b, byteorder='little', signed=False)
return SelectableInt(val, 64)
-def FPADD32(FRA, FRB):
- from openpower.decoder.isafunctions.double2single import DOUBLE2SINGLE
- #return FPADD64(FRA, FRB)
- #FRA = DOUBLE(SINGLE(FRA))
- #FRB = DOUBLE(SINGLE(FRB))
- result = float(FRA) + float(FRB)
- cvt = fp64toselectable(result)
- cvt = DOUBLE2SINGLE(cvt)
- log ("FPADD32", FRA, FRB, result, cvt)
- return cvt
+def _minmag(a, b):
+ if abs(a) < abs(b):
+ return a
+ if abs(a) > abs(b):
+ return b
+ return min(a, b)
-def FPSUB32(FRA, FRB):
- from openpower.decoder.isafunctions.double2single import DOUBLE2SINGLE
- #return FPSUB64(FRA, FRB)
- #FRA = DOUBLE(SINGLE(FRA))
- #FRB = DOUBLE(SINGLE(FRB))
- result = float(FRA) - float(FRB)
- cvt = fp64toselectable(result)
- cvt = DOUBLE2SINGLE(cvt)
- log ("FPSUB32", FRA, FRB, result, cvt)
- return cvt
+def _maxmag(a, b):
+ if abs(a) < abs(b):
+ return b
+ if abs(a) > abs(b):
+ return a
+ return max(a, b)
-def FPMUL32(FRA, FRB):
- from openpower.decoder.isafunctions.double2single import DOUBLE2SINGLE
- #return FPMUL64(FRA, FRB)
- #FRA = DOUBLE(SINGLE(FRA))
- #FRB = DOUBLE(SINGLE(FRB))
- result = float(FRA) * float(FRB)
- log ("FPMUL32", FRA, FRB, float(FRA), float(FRB), result)
- cvt = fp64toselectable(result)
- cvt = DOUBLE2SINGLE(cvt)
- log (" cvt", cvt)
- return cvt
+class ISAFPHelpers:
+ # bfp32/64_OP naming mirrors that in the Power ISA spec.
+ def bfp64_ATAN2PI(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.atan2(float(a), float(b)) / math.pi)
-def FPMULADD32(FRA, FRB, FRC, sign):
- from openpower.decoder.isafunctions.double2single import DOUBLE2SINGLE
- #return FPMUL64(FRA, FRB)
- #FRA = DOUBLE(SINGLE(FRA))
- #FRB = DOUBLE(SINGLE(FRB))
- if sign == 1:
- result = float(FRA) * float(FRB) + float(FRC)
- elif sign == -1:
- result = float(FRA) * float(FRB) - float(FRC)
- elif sign == 0:
- result = float(FRA) * float(FRB)
- log ("FPMULADD32", FRA, FRB, FRC,
- float(FRA), float(FRB), float(FRC),
- result)
- cvt = fp64toselectable(result)
- cvt = DOUBLE2SINGLE(cvt)
- log (" cvt", cvt)
- return cvt
+ def bfp32_ATAN2PI(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.atan2(float(a), float(b)) / math.pi)
+ def bfp64_ATAN2(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.atan2(float(a), float(b)))
-def FPDIV32(FRA, FRB):
- from openpower.decoder.isafunctions.double2single import DOUBLE2SINGLE
- #return FPDIV64(FRA, FRB)
- #FRA = DOUBLE(SINGLE(FRA))
- #FRB = DOUBLE(SINGLE(FRB))
- result = float(FRA) / float(FRB)
- cvt = fp64toselectable(result)
- cvt = DOUBLE2SINGLE(cvt)
- log ("FPDIV32", FRA, FRB, result, cvt)
- return cvt
+ def bfp32_ATAN2(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.atan2(float(a), float(b)))
+
+ def bfp64_HYPOT(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.hypot(float(a), float(b)))
+
+ def bfp32_HYPOT(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.hypot(float(a), float(b)))
+
+ def bfp64_MINNUM08(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(min(float(a), float(b)))
+
+ def bfp32_MINNUM08(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(min(float(a), float(b)))
+
+ def bfp64_MIN19(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(min(float(a), float(b)))
+
+ def bfp32_MIN19(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(min(float(a), float(b)))
+
+ def bfp64_MINNUM19(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(min(float(a), float(b)))
+
+ def bfp32_MINNUM19(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(min(float(a), float(b)))
+
+ def bfp64_MINC(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(min(float(a), float(b)))
+
+ def bfp32_MINC(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(min(float(a), float(b)))
+
+ def bfp64_MAXNUM08(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(max(float(a), float(b)))
+
+ def bfp32_MAXNUM08(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(max(float(a), float(b)))
+
+ def bfp64_MAX19(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(max(float(a), float(b)))
+
+ def bfp32_MAX19(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(max(float(a), float(b)))
+
+ def bfp64_MAXNUM19(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(max(float(a), float(b)))
+
+ def bfp32_MAXNUM19(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(max(float(a), float(b)))
+
+ def bfp64_MAXC(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(max(float(a), float(b)))
+
+ def bfp32_MAXC(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(max(float(a), float(b)))
+
+ def bfp64_MINMAGNUM08(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(_minmag(float(a), float(b)))
+
+ def bfp32_MINMAGNUM08(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(_minmag(float(a), float(b)))
+
+ def bfp64_MAXMAGNUM08(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(_maxmag(float(a), float(b)))
+
+ def bfp32_MAXMAGNUM08(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(_maxmag(float(a), float(b)))
+
+ def bfp64_MOD(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.fmod(float(a), float(b)))
+
+ def bfp32_MOD(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.fmod(float(a), float(b)))
+
+ def bfp64_MINMAG19(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(_minmag(float(a), float(b)))
+
+ def bfp32_MINMAG19(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(_minmag(float(a), float(b)))
+
+ def bfp64_MAXMAG19(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(_maxmag(float(a), float(b)))
+
+ def bfp32_MAXMAG19(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(_maxmag(float(a), float(b)))
+
+ def bfp64_MINMAGNUM19(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(_minmag(float(a), float(b)))
+
+ def bfp32_MINMAGNUM19(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(_minmag(float(a), float(b)))
+
+ def bfp64_MAXMAGNUM19(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(_maxmag(float(a), float(b)))
+
+ def bfp32_MAXMAGNUM19(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(_maxmag(float(a), float(b)))
+
+ def bfp64_REMAINDER(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.remainder(float(a), float(b)))
+
+ def bfp32_REMAINDER(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.remainder(float(a), float(b)))
+
+ def bfp64_POWR(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(pow(float(a), float(b)))
+
+ def bfp32_POWR(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(pow(float(a), float(b)))
+
+ def bfp64_POW(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(pow(float(a), float(b)))
+
+ def bfp32_POW(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(pow(float(a), float(b)))
+
+ def bfp64_MINMAGC(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(_minmag(float(a), float(b)))
+
+ def bfp32_MINMAGC(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(_minmag(float(a), float(b)))
+
+ def bfp64_MAXMAGC(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(_maxmag(float(a), float(b)))
+
+ def bfp32_MAXMAGC(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(_maxmag(float(a), float(b)))
+
+ def bfp64_POWN(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(pow(float(a), int(b)))
+
+ def bfp32_POWN(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(pow(float(a), int(b)))
+
+ def bfp64_ROOTN(self, a, b):
+ # FIXME: use proper implementation
+ return fp64toselectable(pow(float(a), 1 / int(b)))
+
+ def bfp32_ROOTN(self, a, b):
+ # FIXME: use proper implementation
+ return fp32toselectable(pow(float(a), 1 / int(b)))
+
+ def bfp64_CBRT(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(pow(float(v), 1 / 3))
+
+ def bfp32_CBRT(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(pow(float(v), 1 / 3))
+
+ def bfp64_SINPI(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.sin(float(v) * math.pi))
+
+ def bfp32_SINPI(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.sin(float(v) * math.pi))
+
+ def bfp64_ASINPI(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.asin(float(v)) / math.pi)
+
+ def bfp32_ASINPI(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.asin(float(v)) / math.pi)
+
+ def bfp64_COSPI(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.cos(float(v) * math.pi))
+
+ def bfp32_COSPI(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.cos(float(v) * math.pi))
+
+ def bfp64_TANPI(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.tan(float(v) * math.pi))
+
+ def bfp32_TANPI(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.tan(float(v) * math.pi))
+
+ def bfp64_ACOSPI(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.acos(float(v)) / math.pi)
+
+ def bfp32_ACOSPI(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.acos(float(v)) / math.pi)
+
+ def bfp64_ATANPI(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.atan(float(v)) / math.pi)
+
+ def bfp32_ATANPI(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.atan(float(v)) / math.pi)
+
+ def bfp64_RSQRT(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(1 / math.sqrt(float(v)))
+
+ def bfp32_RSQRT(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(1 / math.sqrt(float(v)))
+
+ def bfp64_SIN(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.sin(float(v)))
+
+ def bfp32_SIN(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.sin(float(v)))
+
+ def bfp64_ASIN(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.asin(float(v)))
+
+ def bfp32_ASIN(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.asin(float(v)))
+
+ def bfp64_COS(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.cos(float(v)))
+
+ def bfp32_COS(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.cos(float(v)))
+
+ def bfp64_TAN(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.tan(float(v)))
+
+ def bfp32_TAN(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.tan(float(v)))
+
+ def bfp64_ACOS(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.acos(float(v)))
+
+ def bfp32_ACOS(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.acos(float(v)))
+
+ def bfp64_ATAN(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.atan(float(v)))
+
+ def bfp32_ATAN(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.atan(float(v)))
+
+ def bfp64_RECIP(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(1 / float(v))
+
+ def bfp32_RECIP(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(1 / float(v))
+
+ def bfp64_SINH(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.sinh(float(v)))
+
+ def bfp32_SINH(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.sinh(float(v)))
+
+ def bfp64_ASINH(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.asinh(float(v)))
+
+ def bfp32_ASINH(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.asinh(float(v)))
+
+ def bfp64_COSH(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.cosh(float(v)))
+
+ def bfp32_COSH(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.cosh(float(v)))
+
+ def bfp64_TANH(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.tanh(float(v)))
+
+ def bfp32_TANH(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.tanh(float(v)))
+
+ def bfp64_ACOSH(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.acosh(float(v)))
+
+ def bfp32_ACOSH(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.acosh(float(v)))
+
+ def bfp64_ATANH(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.atanh(float(v)))
+
+ def bfp32_ATANH(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.atanh(float(v)))
+
+ def bfp64_EXP2M1(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(pow(2, float(v)) - 1)
+
+ def bfp32_EXP2M1(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(pow(2, float(v)) - 1)
+
+ def bfp64_LOG2P1(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.log2(float(v) + 1))
+
+ def bfp32_LOG2P1(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.log2(float(v) + 1))
+
+ def bfp64_EXPM1(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.expm1(float(v)))
+
+ def bfp32_EXPM1(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.expm1(float(v)))
+
+ def bfp64_LOGP1(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.log1p(float(v)))
+
+ def bfp32_LOGP1(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.log1p(float(v)))
+
+ def bfp64_EXP10M1(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(pow(10, float(v)) - 1)
+
+ def bfp32_EXP10M1(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(pow(10, float(v)) - 1)
+
+ def bfp64_LOG10P1(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.log10(float(v) + 1))
+
+ def bfp32_LOG10P1(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.log10(float(v) + 1))
+
+ def bfp64_EXP2(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(pow(2, float(v)))
+
+ def bfp32_EXP2(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(pow(2, float(v)))
+
+ def bfp64_LOG2(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.log2(float(v)))
+
+ def bfp32_LOG2(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.log2(float(v)))
+
+ def bfp64_EXP(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.exp(float(v)))
+
+ def bfp32_EXP(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.exp(float(v)))
+
+ def bfp64_LOG(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.log(float(v)))
+
+ def bfp32_LOG(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.log(float(v)))
+
+ def bfp64_EXP10(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(pow(10, float(v)))
+
+ def bfp32_EXP10(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(pow(10, float(v)))
+
+ def bfp64_LOG10(self, v):
+ # FIXME: use proper implementation
+ return fp64toselectable(math.log10(float(v)))
+
+ def bfp32_LOG10(self, v):
+ # FIXME: use proper implementation
+ return fp32toselectable(math.log10(float(v)))
+
+ def FPADD32(self, FRA, FRB):
+ # return FPADD64(FRA, FRB)
+ #FRA = DOUBLE(SINGLE(FRA))
+ #FRB = DOUBLE(SINGLE(FRB))
+ result = float(FRA) + float(FRB)
+ cvt = fp64toselectable(result)
+ cvt = self.DOUBLE2SINGLE(cvt)
+ log("FPADD32", FRA, FRB, float(FRA), "+", float(FRB), "=", result, cvt)
+ return cvt
+
+ def FPSUB32(self, FRA, FRB):
+ # return FPSUB64(FRA, FRB)
+ #FRA = DOUBLE(SINGLE(FRA))
+ #FRB = DOUBLE(SINGLE(FRB))
+ result = float(FRA) - float(FRB)
+ cvt = fp64toselectable(result)
+ cvt = self.DOUBLE2SINGLE(cvt)
+ log("FPSUB32", FRA, FRB, float(FRA), "-", float(FRB), "=", result, cvt)
+ return cvt
+
+ def FPMUL32(self, FRA, FRB, sign=1):
+ # return FPMUL64(FRA, FRB)
+ FRA = self.DOUBLE(SINGLE(FRA))
+ FRB = self.DOUBLE(SINGLE(FRB))
+ result = signinv(float(FRA) * float(FRB), sign)
+ log("FPMUL32", FRA, FRB, float(FRA), float(FRB), result, sign)
+ cvt = fp64toselectable(result)
+ cvt = self.DOUBLE2SINGLE(cvt)
+ log(" cvt", cvt)
+ return cvt
+
+ def FPMULADD32(self, FRA, FRC, FRB, mulsign, addsign):
+ # return FPMUL64(FRA, FRB)
+ #FRA = DOUBLE(SINGLE(FRA))
+ #FRB = DOUBLE(SINGLE(FRB))
+ if addsign == 1:
+ if mulsign == 1:
+ result = float(FRA) * float(FRC) + float(FRB) # fmadds
+ elif mulsign == -1:
+ result = -(float(FRA) * float(FRC) - float(FRB)) # fnmsubs
+ elif addsign == -1:
+ if mulsign == 1:
+ result = float(FRA) * float(FRC) - float(FRB) # fmsubs
+ elif mulsign == -1:
+ result = -(float(FRA) * float(FRC) + float(FRB)) # fnmadds
+ elif addsign == 0:
+ result = 0.0
+ log("FPMULADD32 FRA FRC FRB", FRA, FRC, FRB)
+ log(" FRA", float(FRA))
+ log(" FRC", float(FRC))
+ log(" FRB", float(FRB))
+ log(" (FRA*FRC)+FRB=", mulsign, addsign, result)
+ cvt = fp64toselectable(result)
+ cvt = self.DOUBLE2SINGLE(cvt)
+ log(" cvt", cvt)
+ return cvt
+
+ def FPDIV32(self, FRA, FRB, sign=1):
+ # return FPDIV64(FRA, FRB)
+ #FRA = DOUBLE(SINGLE(FRA))
+ #FRB = DOUBLE(SINGLE(FRB))
+ result = signinv(float(FRA) / float(FRB), sign)
+ cvt = fp64toselectable(result)
+ cvt = self.DOUBLE2SINGLE(cvt)
+ log("FPDIV32", FRA, FRB, result, cvt)
+ return cvt
def FPADD64(FRA, FRB):
result = float(FRA) + float(FRB)
cvt = fp64toselectable(result)
- log ("FPADD64", FRA, FRB, result, cvt)
+ log("FPADD64", FRA, FRB, result, cvt)
return cvt
def FPSUB64(FRA, FRB):
result = float(FRA) - float(FRB)
cvt = fp64toselectable(result)
- log ("FPSUB64", FRA, FRB, result, cvt)
+ log("FPSUB64", FRA, FRB, result, cvt)
return cvt
-def FPMUL64(FRA, FRB):
- result = float(FRA) * float(FRB)
+def FPMUL64(FRA, FRB, sign=1):
+ result = signinv(float(FRA) * float(FRB), sign)
cvt = fp64toselectable(result)
- log ("FPMUL64", FRA, FRB, result, cvt)
+ log("FPMUL64", FRA, FRB, result, cvt, sign)
return cvt
-def FPDIV64(FRA, FRB):
- result = float(FRA) / float(FRB)
+def FPDIV64(FRA, FRB, sign=1):
+ result = signinv(float(FRA) / float(FRB), sign)
cvt = fp64toselectable(result)
- log ("FPDIV64", FRA, FRB, result, cvt)
+ log("FPDIV64", FRA, FRB, result, cvt, sign)
return cvt
+def bitrev(val, VL):
+ """Returns the integer whose value is the reverse of the lowest
+ 'width' bits of the integer 'val'
+ """
+ result = 0
+ width = VL.bit_length()-1
+ for _ in range(width):
+ result = (result << 1) | (val & 1)
+ val >>= 1
+ return result
+
+
+def log2(val):
+ """return the base-2 logarithm of `val`. Only works for powers of 2."""
+ if isinstance(val, SelectableInt):
+ val = val.value
+ retval = val.bit_length() - 1
+ assert val == 2 ** retval, "value is not a power of 2"
+ return retval
+
+
+# BFP classification predicates
+# these need to be implemented in python because they work with multiple
+# input types
+def IsInf(v):
+ if isinstance(v, BFPState):
+ return onebit(v.class_.Infinity)
+ # TODO: implement for SelectableInt/int
+ raise NotImplementedError("not yet implemented for non-BFPState values")
+
+
+def IsNaN(v):
+ if isinstance(v, BFPState):
+ return onebit(v.class_.SNaN or v.class_.QNaN)
+ # TODO: implement for SelectableInt/int
+ raise NotImplementedError("not yet implemented for non-BFPState values")
+
+
+def IsNeg(v):
+ if isinstance(v, BFPState):
+ if v.class_.SNaN or v.class_.QNaN or v.class_.Zero:
+ return onebit(0)
+ return onebit(v.sign)
+ # TODO: implement for SelectableInt/int
+ raise NotImplementedError("not yet implemented for non-BFPState values")
+
+
+def IsSNaN(v):
+ if isinstance(v, BFPState):
+ return onebit(v.class_.SNaN)
+ # TODO: implement for SelectableInt/int
+ raise NotImplementedError("not yet implemented for non-BFPState values")
+
+
+def IsZero(v):
+ if isinstance(v, BFPState):
+ return onebit(v.class_.Zero)
+ # TODO: implement for SelectableInt/int
+ raise NotImplementedError("not yet implemented for non-BFPState values")
+
+
+def SetFX(fpscr, field):
+ assert isinstance(fpscr, FPSCRState), "SetFX only works on FPSCR fields"
+ if eq(getattr(fpscr, field), SelectableInt(0, 1)):
+ setattr(fpscr, field, SelectableInt(1, 1))
+ fpscr.FX = SelectableInt(1, 1)
+
+
+class ISACallerHelper:
+ def __init__(self, XLEN, FPSCR):
+ self.__XLEN = XLEN
+ if FPSCR is None:
+ FPSCR = FPSCRState()
+ self.__FPSCR = FPSCR
+
+ @property
+ def XLEN(self):
+ return self.__XLEN
+
+ @property
+ def FPSCR(self):
+ return self.__FPSCR
+
+ def EXTZXL(self, value, bits=None):
+ if bits is None:
+ bits = self.XLEN
+ elif isinstance(bits, SelectableInt):
+ bits = bits.value
+ if isinstance(value, SelectableInt):
+ value = value.value
+ return SelectableInt(value & ((1 << bits) - 1), self.XLEN)
+
+ def EXTSXL(self, value, bits=None):
+ if isinstance(value, SelectableInt):
+ value = value.value
+ if bits is None:
+ bits = self.XLEN
+ elif isinstance(bits, SelectableInt):
+ bits = bits.value
+ return SelectableInt(exts(value, bits), self.XLEN)
+
+ def DOUBLE2SINGLE(self, FRS):
+ """ DOUBLE2SINGLE has been renamed to FRSP since it is the
+ implementation of the frsp instruction.
+ use SINGLE() or FRSP() instead, or just use struct.pack/unpack
+ """
+ return self.FRSP(FRS)
+
+ def ROTL32(self, value, bits):
+ if isinstance(bits, SelectableInt):
+ bits = bits.value
+ if isinstance(value, SelectableInt):
+ value = SelectableInt(value.value, self.XLEN)
+ value = value | (value << (self.XLEN//2))
+ value = rotl(value, bits, self.XLEN)
+ return value
+
+ def ROTL128(self, value, bits):
+ return rotl(value, bits, self.XLEN*2)
+
+ def ROTL64(self, value, bits):
+ return rotl(value, bits, self.XLEN)
+
+ def MASK32(self, x, y):
+ if isinstance(x, SelectableInt):
+ x = x.value
+ if isinstance(y, SelectableInt):
+ y = y.value
+ return self.MASK(x+(self.XLEN//2), y+(self.XLEN//2))
+
+ def MASK(self, x, y, lim=None):
+ if lim is None:
+ lim = self.XLEN
+ if isinstance(x, SelectableInt):
+ x = x.value
+ if isinstance(y, SelectableInt):
+ y = y.value
+ if x < y:
+ x = lim-x
+ y = (lim-1)-y
+ mask_a = ((1 << x) - 1) & ((1 << lim) - 1)
+ mask_b = ((1 << y) - 1) & ((1 << lim) - 1)
+ elif x == y:
+ return 1 << ((lim-1)-x)
+ else:
+ x = lim-x
+ y = (lim-1)-y
+ mask_a = ((1 << x) - 1) & ((1 << lim) - 1)
+ mask_b = (~((1 << y) - 1)) & ((1 << lim) - 1)
+ return mask_a ^ mask_b
+
+ def __getattr__(self, attr):
+ """workaround for getting function out of the global namespace
+ within this module, as a way to get functions being transitioned
+ to Helper classes within ISACaller (and therefore pseudocode)
+ """
+ try:
+ return globals()[attr]
+ except KeyError:
+ raise AttributeError(attr)
+
+
# For these tests I tried to find power instructions that would let me
# isolate each of these helper operations. So for instance, when I was
# testing the MASK() function, I chose rlwinm and rldicl because if I
# set the shift equal to 0 and passed in a value of all ones, the
# result I got would be exactly the same as the output of MASK()
+class HelperTests(unittest.TestCase, ISACallerHelper):
+ def __init__(self, *args, **kwargs):
+ # TODO: dynamic (64/32/16/8)
+ ISACallerHelper.__init__(self, 64, FPSCR=None)
+ unittest.TestCase.__init__(self, *args, **kwargs)
-class HelperTests(unittest.TestCase):
def test_MASK(self):
# Verified using rlwinm, rldicl, rldicr in qemu
# li 1, -1
# rlwinm reg, 1, 0, 5, 15
- self.assertHex(MASK(5+32, 15+32), 0x7ff0000)
+ self.assertHex(self.MASK(5+32, 15+32), 0x7ff0000)
# rlwinm reg, 1, 0, 15, 5
- self.assertHex(MASK(15+32, 5+32), 0xfffffffffc01ffff)
- self.assertHex(MASK(30+32, 2+32), 0xffffffffe0000003)
+ self.assertHex(self.MASK(15+32, 5+32), 0xfffffffffc01ffff)
+ self.assertHex(self.MASK(30+32, 2+32), 0xffffffffe0000003)
# rldicl reg, 1, 0, 37
- self.assertHex(MASK(37, 63), 0x7ffffff)
- self.assertHex(MASK(10, 63), 0x3fffffffffffff)
- self.assertHex(MASK(58, 63), 0x3f)
+ self.assertHex(self.MASK(37, 63), 0x7ffffff)
+ self.assertHex(self.MASK(10, 63), 0x3fffffffffffff)
+ self.assertHex(self.MASK(58, 63), 0x3f)
# rldicr reg, 1, 0, 37
- self.assertHex(MASK(0, 37), 0xfffffffffc000000)
- self.assertHex(MASK(0, 10), 0xffe0000000000000)
- self.assertHex(MASK(0, 58), 0xffffffffffffffe0)
+ self.assertHex(self.MASK(0, 37), 0xfffffffffc000000)
+ self.assertHex(self.MASK(0, 10), 0xffe0000000000000)
+ self.assertHex(self.MASK(0, 58), 0xffffffffffffffe0)
# li 2, 5
# slw 1, 1, 2
- self.assertHex(MASK(32, 63-5), 0xffffffe0)
+ self.assertHex(self.MASK(32, 63-5), 0xffffffe0)
- self.assertHex(MASK(32, 33), 0xc0000000)
- self.assertHex(MASK(32, 32), 0x80000000)
- self.assertHex(MASK(33, 33), 0x40000000)
+ self.assertHex(self.MASK(32, 33), 0xc0000000)
+ self.assertHex(self.MASK(32, 32), 0x80000000)
+ self.assertHex(self.MASK(33, 33), 0x40000000)
def test_ROTL64(self):
# r1 = 0xdeadbeef12345678
value = 0xdeadbeef12345678
# rldicl reg, 1, 10, 0
- self.assertHex(ROTL64(value, 10), 0xb6fbbc48d159e37a)
+ self.assertHex(self.ROTL64(value, 10), 0xb6fbbc48d159e37a)
# rldicl reg, 1, 35, 0
- self.assertHex(ROTL64(value, 35), 0x91a2b3c6f56df778)
- self.assertHex(ROTL64(value, 58), 0xe37ab6fbbc48d159)
- self.assertHex(ROTL64(value, 22), 0xbbc48d159e37ab6f)
+ self.assertHex(self.ROTL64(value, 35), 0x91a2b3c6f56df778)
+ self.assertHex(self.ROTL64(value, 58), 0xe37ab6fbbc48d159)
+ self.assertHex(self.ROTL64(value, 22), 0xbbc48d159e37ab6f)
def test_ROTL32(self):
# r1 = 0xdeadbeef
- value = 0xdeadbeef
+ value = SelectableInt(0xdeadbeef, self.XLEN)
# rlwinm reg, 1, 10, 0, 31
- self.assertHex(ROTL32(value, 10), 0xb6fbbf7a)
+ self.assertHex(self.ROTL32(value, 10), 0xb6fbbf7a)
# rlwinm reg, 1, 17, 0, 31
- self.assertHex(ROTL32(value, 17), 0x7ddfbd5b)
- self.assertHex(ROTL32(value, 25), 0xdfbd5b7d)
- self.assertHex(ROTL32(value, 30), 0xf7ab6fbb)
+ self.assertHex(self.ROTL32(value, 17), 0x7ddfbd5b)
+ self.assertHex(self.ROTL32(value, 25), 0xdfbd5b7d)
+ self.assertHex(self.ROTL32(value, 30), 0xf7ab6fbb)
def test_EXTS64(self):
value_a = SelectableInt(0xdeadbeef, 32) # r1
value_c = SelectableInt(0x80000000, 32) # r3
# extswsli reg, 1, 0
- self.assertHex(EXTS64(value_a), 0xffffffffdeadbeef)
+ self.assertHex(self.EXTS64(value_a), 0xffffffffdeadbeef)
# extswsli reg, 2, 0
- self.assertHex(EXTS64(value_b), SelectableInt(value_b.value, 64))
+ self.assertHex(self.EXTS64(value_b), SelectableInt(value_b.value, 64))
# extswsli reg, 3, 0
- self.assertHex(EXTS64(value_c), 0xffffffff80000000)
+ self.assertHex(self.EXTS64(value_c), 0xffffffff80000000)
def test_FPADD32(self):
value_a = SelectableInt(0x4014000000000000, 64) # 5.0
return self.assertEqual(a, b, msg)
+
if __name__ == '__main__':
log(SelectableInt.__bases__)
unittest.main()