Add FPMAX module
authorMichael Nolan <mtnolan2640@gmail.com>
Tue, 28 Jan 2020 16:32:40 +0000 (11:32 -0500)
committerMichael Nolan <mtnolan2640@gmail.com>
Tue, 28 Jan 2020 19:53:47 +0000 (14:53 -0500)
src/ieee754/fpmax/fpmax.py [new file with mode: 0644]
src/ieee754/fpmax/pipeline.py [new file with mode: 0644]
src/ieee754/fpmax/test/test_fpmax_pipe.py [new file with mode: 0644]

diff --git a/src/ieee754/fpmax/fpmax.py b/src/ieee754/fpmax/fpmax.py
new file mode 100644 (file)
index 0000000..1987d8e
--- /dev/null
@@ -0,0 +1,68 @@
+# IEEE Floating Point Conversion, FSGNJ
+# Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+# Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
+
+
+from nmigen import Module, Signal, Cat, Mux
+
+from nmutil.pipemodbase import PipeModBase
+from ieee754.fpcommon.basedata import FPBaseData
+from ieee754.fpcommon.packdata import FPPackData
+from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord
+
+
+class FPMAXPipeMod(PipeModBase):
+    """ FP Sign injection - replaces operand A's sign bit with one
+        generated from operand B
+
+        self.ctx.i.op & 0x3 == 0x0 : Copy sign bit from operand B
+        self.ctx.i.op & 0x3 == 0x1 : Copy inverted sign bit from operand B
+        self.ctx.i.op & 0x3 == 0x2 : Sign bit is A's sign XOR B's sign
+    """
+    def __init__(self, in_pspec):
+        self.in_pspec = in_pspec
+        super().__init__(in_pspec, "fpmax")
+
+    def ispec(self):
+        return FPBaseData(self.in_pspec)
+
+    def ospec(self):
+        return FPPackData(self.in_pspec)
+
+    def elaborate(self, platform):
+        m = Module()
+
+        # useful clarity variables
+        comb = m.d.comb
+        width = self.pspec.width
+        opcode = self.i.ctx.op
+        z1 = self.o.z
+
+        a1 = FPNumBaseRecord(width, False)
+        b1 = FPNumBaseRecord(width, False)
+        m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
+        m.submodules.sc_decode_b = b1 = FPNumDecode(None, b1)
+
+        m.d.comb += [a1.v.eq(self.i.a),
+                     b1.v.eq(self.i.b)]
+
+        has_nan = Signal()
+        comb += has_nan.eq(a1.is_nan | b1.is_nan)
+        with m.If(has_nan):
+            comb += z1.eq(Mux(a1.is_nan, self.i.b, self.i.a))
+        with m.Else():
+            with m.If(a1.s != b1.s):
+                
+                comb += z1.eq(Mux(a1.s, self.i.b, self.i.a))
+            with m.Else():
+                gt = Signal()
+                sign = Signal()
+                comb += sign.eq(a1.s)
+                comb += gt.eq(a1.v > b1.v)
+                comb += z1.eq(Mux(gt ^ sign, self.i.a, self.i.b))
+                              
+
+        # copy the context (muxid, operator)
+        comb += self.o.ctx.eq(self.i.ctx)
+
+        return m
diff --git a/src/ieee754/fpmax/pipeline.py b/src/ieee754/fpmax/pipeline.py
new file mode 100644 (file)
index 0000000..aca2d08
--- /dev/null
@@ -0,0 +1,56 @@
+"""IEEE754 Floating Point Conversion
+
+Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
+
+"""
+
+from nmutil.singlepipe import ControlBase
+from nmutil.concurrentunit import ReservationStations, num_bits
+
+from ieee754.pipeline import PipelineSpec, DynamicPipe
+
+from ieee754.fpmax.fpmax import FPMAXPipeMod
+
+
+class FPMAXStage(DynamicPipe):
+    """ FPConversion and De-norm
+    """
+
+    def __init__(self, in_pspec):
+        stage = FPMAXPipeMod(in_pspec)
+        in_pspec.stage = stage
+        super().__init__(in_pspec)
+
+
+class FPMAXBasePipe(ControlBase):
+    def __init__(self, pspec):
+        ControlBase.__init__(self)
+        self.pipe1 = FPMAXStage(pspec)
+        self._eqs = self.connect([self.pipe1, ])
+
+    def elaborate(self, platform):
+        m = ControlBase.elaborate(self, platform)
+        m.submodules.fpmax = self.pipe1
+        m.d.comb += self._eqs
+        return m
+
+
+class FPMAXMuxInOut(ReservationStations):
+    """ Reservation-Station version of FPCVT pipeline.
+
+        * fan-in on inputs (an array of FPBaseData: a,b,mid)
+        * converter pipeline (alu)
+        * fan-out on outputs (an array of FPPackData: z,mid)
+
+        Fan-in and Fan-out are combinatorial.
+    """
+
+    def __init__(self, in_width, num_rows, op_wid=1):
+        self.op_wid = op_wid
+        self.id_wid = num_bits(num_rows)
+
+        self.in_pspec = PipelineSpec(in_width, self.id_wid, self.op_wid)
+
+        self.alu = FPMAXBasePipe(self.in_pspec)
+        ReservationStations.__init__(self, num_rows)
diff --git a/src/ieee754/fpmax/test/test_fpmax_pipe.py b/src/ieee754/fpmax/test/test_fpmax_pipe.py
new file mode 100644 (file)
index 0000000..65823f3
--- /dev/null
@@ -0,0 +1,32 @@
+""" test of FPCVTMuxInOut
+"""
+
+from ieee754.fpmax.pipeline import (FPMAXMuxInOut)
+from ieee754.fpcommon.test.fpmux import runfp
+
+from sfpy import Float16, Float32, Float64
+import math
+
+def fpmax_f32_max(a, b):
+    
+    if math.isnan(a) or math.isnan(b):
+        if math.isnan(a) and math.isnan(b):
+            return Float32(float('nan'))
+        else:
+            return b if math.isnan(a) else a
+                    
+    if a > b:
+        return a
+    else:
+        return b
+
+
+def test_fpmax_f32_max():
+    dut = FPMAXMuxInOut(32, 4)
+    runfp(dut, 32, "test_fpmax_f32_max", Float32, fpmax_f32_max,
+          n_vals=100, opcode=0x0)
+
+
+if __name__ == '__main__':
+    for i in range(50):
+        test_fpmax_f32_max()