power_fields: allow comparing references
[openpower-isa.git] / src / openpower / decoder / helpers.py
index 97a7d8ae4377ed45a115c08e0d27bcc8914a0383..a81c3f09f75d112e592b86f3f47da8f2786f0b6c 100644 (file)
@@ -1,4 +1,6 @@
 import unittest
+import struct
+import sys
 from openpower.decoder.selectable_int import (SelectableInt, onebit,
                                               selectconcat)
 from nmutil.divmod import trunc_divs, trunc_rems
@@ -7,6 +9,9 @@ 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.util import log
+import math
+
 trunc_div = floordiv
 trunc_rem = mod
 DIVS = trunc_divs
@@ -15,9 +20,19 @@ MODS = trunc_rems
 """
 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)
@@ -26,7 +41,7 @@ def exts(value, bits):
 def EXTS(value):
     """ extends sign bit out from current MSB to all 256 bits
     """
-    print ("EXTS", value, type(value))
+    log("EXTS", value, type(value))
     assert isinstance(value, SelectableInt)
     return SelectableInt(exts(value.value, value.bits) & ((1 << 256)-1), 256)
 
@@ -53,7 +68,7 @@ def MULS(a, b):
     a_s = a.value & (1 << (a.bits-1)) != 0
     b_s = b.value & (1 << (b.bits-1)) != 0
     result = abs(a) * abs(b)
-    print("MULS", result, a_s, b_s)
+    log("MULS", result, a_s, b_s)
     if a_s == b_s:
         return result
     return -result
@@ -74,6 +89,14 @@ def rotl(value, bits, wordlen):
     return ((value << bits) | (value >> (wordlen-bits))) & mask
 
 
+def SHL64(value, bits, wordlen=64):
+    if isinstance(bits, SelectableInt):
+        bits = bits.value
+    mask = (1 << wordlen) - 1
+    bits = bits & (wordlen - 1)
+    return SelectableInt((value << bits) & mask, 64)
+
+
 def ROTL64(value, bits):
     return rotl(value, bits, 64)
 
@@ -85,6 +108,7 @@ def ROTL32(value, bits):
         value = SelectableInt(value.value, 64)
     return rotl(value | (value << 32), bits, 64)
 
+
 def MASK32(x, y):
     if isinstance(x, SelectableInt):
         x = x.value
@@ -92,6 +116,7 @@ def MASK32(x, y):
         y = y.value
     return MASK(x+32, y+32)
 
+
 def MASK(x, y):
     if isinstance(x, SelectableInt):
         x = x.value
@@ -149,43 +174,199 @@ def undefined(v):
     """
     return v
 
-def DOUBLE(WORD):
-    """convert incoming WORD to double.  v3.0B p140 section 4.6.2
+
+def SINGLE(FRS):
+    """convert incoming FRS into 32-bit word.  v3.0B p144 section 4.6.3
+    """
+    # result - WORD - start off all zeros
+    WORD = SelectableInt(0, 32)
+
+    e = FRS[1:12]
+    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)
+
+    return WORD
+
+# XXX NOTE: these are very quick hacked functions for utterly basic
+# FP support
+
+
+def signinv(res, sign):
+    if sign == 1:
+        return res
+    if sign == 0:
+        return 0.0
+    if sign == -1:
+        return -res
+
+
+def fp64toselectable(frt):
+    """convert FP number to 64 bit SelectableInt
     """
-    # result, FRT, start off all zeros
-    FRT = SelectableInt(0, 64)
-    z1 = SelectableInt(0, 1)
-    z29 = SelectableInt(0, 29)
-    # Normalized Operand
-    if WORD[1:9] > 0 and WORD[1:9] < 255:
-        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 WORD[1:9] == 0 and WORD[9:32] != 0:
-        sign = WORD[0]
-        exp = -126
-        frac[0:53] = selectconcat(z1, WORD[9:32], z29)
-        # normalize the operand
-        while frac[0] == 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 WORD[1:9] == 255 or WORD[1:32] == 0:
-        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)
-
-    return FRT
+    b = struct.pack(">d", frt)
+    val = int.from_bytes(b, byteorder='big', signed=False)
+    return SelectableInt(val, 64)
+
+
+class ISAFPHelpers:
+
+    def FPSIN32(self, FRB):
+        #FRB = DOUBLE(SINGLE(FRB))
+        result = math.sin(float(FRB))
+        cvt = fp64toselectable(result)
+        cvt = self.DOUBLE2SINGLE(cvt)
+        log("FPSIN32", FRB, float(FRB), "=", result, cvt)
+        return cvt
+
+    def FPCOS32(self, FRB):
+        #FRB = DOUBLE(SINGLE(FRB))
+        result = math.cos(float(FRB))
+        cvt = fp64toselectable(result)
+        cvt = self.DOUBLE2SINGLE(cvt)
+        log("FPCOS32", FRB, float(FRB), "=", result, cvt)
+        return cvt
+
+    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)
+    return cvt
+
+
+def FPSUB64(FRA, FRB):
+    result = float(FRA) - float(FRB)
+    cvt = fp64toselectable(result)
+    log("FPSUB64", FRA, FRB, result, cvt)
+    return cvt
+
+
+def FPMUL64(FRA, FRB, sign=1):
+    result = signinv(float(FRA) * float(FRB), sign)
+    cvt = fp64toselectable(result)
+    log("FPMUL64", FRA, FRB, result, cvt, sign)
+    return cvt
+
+
+def FPDIV64(FRA, FRB, sign=1):
+    result = signinv(float(FRA) / float(FRB), sign)
+    cvt = fp64toselectable(result)
+    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
 
 
 # For these tests I tried to find power instructions that would let me
@@ -255,6 +436,12 @@ class HelperTests(unittest.TestCase):
         # extswsli reg, 3, 0
         self.assertHex(EXTS64(value_c), 0xffffffff80000000)
 
+    def test_FPADD32(self):
+        value_a = SelectableInt(0x4014000000000000, 64)  # 5.0
+        value_b = SelectableInt(0x403B4CCCCCCCCCCD, 64)  # 27.3
+        result = FPADD32(value_a, value_b)
+        self.assertHex(0x4040266666666666, result)
+
     def assertHex(self, a, b):
         a_val = a
         if isinstance(a, SelectableInt):
@@ -266,6 +453,45 @@ class HelperTests(unittest.TestCase):
         return self.assertEqual(a, b, msg)
 
 
+class ISACallerHelper:
+    def __init__(self, XLEN):
+        self.__XLEN = XLEN
+
+    @property
+    def XLEN(self):
+        return self.__XLEN
+
+    def XLCASTS(self, value):
+        return SelectableInt(exts(value.value, self.XLEN), self.XLEN)
+
+    def XLCASTU(self, value):
+        # SelectableInt already takes care of masking out the bits
+        return SelectableInt(value.value, self.XLEN)
+
+    def EXTSXL(self, value, bits):
+        return SelectableInt(exts(value.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
+        """
+        FPSCR = {
+            'UE': SelectableInt(0, 1),
+            'OE': SelectableInt(0, 1),
+            'RN': SelectableInt(0, 2),  # round to nearest, ties to even
+            'XX': SelectableInt(0, 1),
+        }
+        FRT, FPSCR = self.FRSP(FRS, FPSCR)
+        return FRT
+
+    def __getattr__(self, attr):
+        try:
+            return globals()[attr]
+        except KeyError:
+            raise AttributeError(attr)
+
+
 if __name__ == '__main__':
-    print(SelectableInt.__bases__)
+    log(SelectableInt.__bases__)
     unittest.main()