Add basic test for fsignj pipe
authorMichael Nolan <mtnolan2640@gmail.com>
Sun, 26 Jan 2020 20:37:16 +0000 (15:37 -0500)
committerMichael Nolan <mtnolan2640@gmail.com>
Mon, 27 Jan 2020 02:28:53 +0000 (21:28 -0500)
This adds a bare bones unit test for the fsignj module, and fixes the
errors generated when trying to elaborate the module in the unit test

src/ieee754/fsgnj/fsgnj.py
src/ieee754/fsgnj/pipeline.py
src/ieee754/fsgnj/test/test_fsgnj_pipe.py [new file with mode: 0644]

index fa21d39fa17222125bd03b607844621405590785..4bb037345e9ca5ce203d45a5afb5047bac28ad02 100644 (file)
@@ -7,7 +7,7 @@ from nmigen.cli import main, verilog
 from nmutil.pipemodbase import PipeModBase
 from ieee754.fpcommon.basedata import FPBaseData
 from ieee754.fpcommon.postcalc import FPPostCalcData
-from ieee754.fpcommon.msbhigh import FPMSBHigh
+from ieee754.fpcommon.packdata import FPPackData
 
 from ieee754.fpcommon.fpbase import FPNumBaseRecord
 
@@ -27,7 +27,7 @@ class FSGNJPipeMod(PipeModBase):
         return FPBaseData(self.in_pspec)
 
     def ospec(self):
-        return FPBaseData(self.in_pspec)
+        return FPPackData(self.in_pspec)
 
     def elaborate(self, platform):
         m = Module()
@@ -38,95 +38,8 @@ class FSGNJPipeMod(PipeModBase):
         # decode: XXX really should move to separate stage
         z1 = self.o.z
         a = self.i.a
-        print("z1", z1.width, z1.rmw, z1.e_width, z1.e_start, z1.e_end)
-
-        me = self.in_pspec.width
-        mz = z1.rmw
-        ms = mz - me
-        print("ms-me", ms, me, mz)
-
-        # 3 extra bits for guard/round/sticky
-        msb = FPMSBHigh(me+3, z1.e_width)
-        m.submodules.norm_msb = msb
-
-        # signed or unsigned, use operator context
-        signed = Signal(reset_less=True)
-        comb += signed.eq(self.i.ctx.op[0])
-
-        # mantissa (one less bit if signed), and sign
-        mantissa = Signal(me, reset_less=True)
-        sign = Signal(reset_less=True)
-
-        # detect signed/unsigned.  key case: -ve numbers need inversion
-        # to +ve because the FP sign says if it's -ve or not.
-        comb += sign.eq(Mux(signed, a[-1], 0)) # sign in top bit of a
-        comb += mantissa.eq(Mux(signed,
-                                Mux(sign, -a,  # invert input if sign -ve
-                                           a), # leave as-is
-                                a))            # unsigned, use full a
-
-        # set input from full INT
-        comb += msb.m_in.eq(Cat(0, 0, 0, mantissa)) # g/r/s + input
-        comb += msb.e_in.eq(me)                     # exp = int width
-
-        # to do with FP16... not yet resolved why
-        alternative = ms < 0
-
-        if alternative:
-            comb += z1.e.eq(msb.e_out-1)
-            mmsb = msb.m_out[-mz-1:]
-            if mz == 16:
-                # larger int to smaller FP (uint32/64 -> fp16 most likely)
-                comb += z1.m[ms-1:].eq(mmsb)
-            else: # 32? XXX weirdness...
-                comb += z1.m.eq(mmsb)
-        else:
-            # smaller int to larger FP
-            comb += z1.e.eq(msb.e_out)
-            comb += z1.m[ms:].eq(msb.m_out[3:])
-
-        # XXX there is some weirdness involving the sign looping back
-        # see graphviz output
-        # http://bugs.libre-riscv.org/show_bug.cgi?id=135
-        comb += z1.s.eq(sign)
-        comb += z1.create(sign, z1.e, z1.m) # ... here
-
-        # note: post-normalisation actually appears to be capable of
-        # detecting overflow to infinity (FPPackMod).  so it's ok to
-        # drop the bits into the mantissa (with a fixed exponent),
-        # do some rounding (which might result in exceeding the
-        # range of the target FP by re-increasing the exponent),
-        # and basically *not* have to do any kind of range-checking
-        # here: just set up guard/round/sticky, drop the INT into the
-        # mantissa, and away we go.  XXX TODO: see if FPNormaliseMod
-        # is even necessary.  it probably isn't
-
-        # initialise rounding (but only activate if needed)
-        if alternative:
-            # larger int to smaller FP (uint32/64 -> fp16 most likely)
-            comb += self.o.of.guard.eq(msb.m_out[-mz-2])
-            comb += self.o.of.round_bit.eq(msb.m_out[-mz-3])
-            comb += self.o.of.sticky.eq(msb.m_out[:-mz-3].bool())
-            comb += self.o.of.m0.eq(msb.m_out[-mz-1])
-        else:
-            # smaller int to larger FP
-            comb += self.o.of.guard.eq(msb.m_out[2])
-            comb += self.o.of.round_bit.eq(msb.m_out[1])
-            comb += self.o.of.sticky.eq(msb.m_out[:1].bool())
-            comb += self.o.of.m0.eq(msb.m_out[3])
-
-        a_nonzero = Signal(reset_less=True)
-        comb += a_nonzero.eq(~a.bool())
-
-        # prepare zero
-        z_zero = FPNumBaseRecord(z1.width, False, name="z_zero")
-        comb += z_zero.zero(0)
-
-        # special cases?
-        comb += self.o.out_do_z.eq(a_nonzero)
-
-        # detect zero
-        comb += self.o.oz.eq(Mux(a_nonzero, z1.v, z_zero.v))
+
+        comb += z1.eq(a)
 
         # copy the context (muxid, operator)
         comb += self.o.ctx.eq(self.i.ctx)
index a6e717e8cd8f925b8f7b11053f69b8368f42d283..f9e803fed4e69cec05693d0907b2103e6392196b 100644 (file)
@@ -16,15 +16,6 @@ from ieee754.pipeline import PipelineSpec, DynamicPipe
 from ieee754.fsgnj.fsgnj import FSGNJPipeMod
 
 
-# not used, yet
-# from nmigen import Signal
-class SignedOp:
-    def __init__(self):
-        self.signed = Signal(reset_less=True)
-
-    def eq(self, i):
-        return [self.signed.eq(i)]
-
 
 class FSGNJStage(DynamicPipe):
     """ FPConversion and De-norm
diff --git a/src/ieee754/fsgnj/test/test_fsgnj_pipe.py b/src/ieee754/fsgnj/test/test_fsgnj_pipe.py
new file mode 100644 (file)
index 0000000..d75d30d
--- /dev/null
@@ -0,0 +1,27 @@
+""" test of FPCVTMuxInOut
+"""
+
+from ieee754.fsgnj.pipeline import (FSGNJMuxInOut)
+from ieee754.fpcommon.test.fpmux import runfp
+
+import sfpy
+from sfpy import Float64, Float32, Float16
+
+
+
+######################
+# signed int to fp
+######################
+
+def fsgnj_abs(x):
+    return x.__abs__()
+
+def test_fsgnj_abs():
+    dut = FSGNJMuxInOut(32, 4)
+    runfp(dut, 32, "test_fsgnj_abs", Float32, fsgnj_abs,
+                True, n_vals=10, opcode=0x0)
+
+
+if __name__ == '__main__':
+    for i in range(200):
+        test_fsgnj_abs()