switch to exact version of cython
[ieee754fpu.git] / src / ieee754 / fpadd / align.py
index 171365ef476a60bf1bd41fb163215e08ee5c6b56..d565e6e4b9907c66e0f59df4f3a0f210cad4de21 100644 (file)
@@ -1,37 +1,23 @@
-# IEEE Floating Point Adder (Single Precision)
-# Copyright (C) Jonathan P Dawson 2013
-# 2013-12-12
+"""IEEE754 Floating Point Library
 
-from nmigen import Module, Signal, Elaboratable
+Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+
+"""
+
+from nmigen import Module, Signal, Mux
 from nmigen.cli import main, verilog
 
-from ieee754.fpcommon.fpbase import FPNumOut, FPNumIn, FPNumBase
+from nmutil.pipemodbase import PipeModBase
 from ieee754.fpcommon.fpbase import FPNumBaseRecord
 from ieee754.fpcommon.fpbase import MultiShiftRMerge
-from ieee754.fpcommon.fpbase import FPState
 from ieee754.fpcommon.denorm import FPSCData
-from ieee754.fpcommon.getop import FPBaseData
-
-
-class FPNumIn2Ops:
-
-    def __init__(self, width, pspec):
-        self.a = FPNumBaseRecord(width)
-        self.b = FPNumBaseRecord(width)
-        self.z = FPNumBaseRecord(width, False)
-        self.out_do_z = Signal(reset_less=True)
-        self.oz = Signal(width, reset_less=True)
-        self.ctx = FPBaseData(width, pspec)
-        self.mid = self.ctx.mid
+from ieee754.fpcommon.getop import FPPipeContext
+from ieee754.fpcommon.pscdata import FPSCData
 
-    def eq(self, i):
-        return [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz),
-                self.a.eq(i.a), self.b.eq(i.b), self.ctx.eq(i.ctx)]
-
-
-
-class FPAddAlignMultiMod(FPState):
 
+class FPAddAlignMultiMod:
+    """Module to do mantissa alignment shift in multiple cycles
+    """
     def __init__(self, width):
         self.in_a = FPNumBaseRecord(width)
         self.in_b = FPNumBaseRecord(width)
@@ -40,84 +26,38 @@ class FPAddAlignMultiMod(FPState):
         self.exp_eq = Signal(reset_less=True)
 
     def elaborate(self, platform):
-        # This one however (single-cycle) will do the shift
-        # in one go.
-
         m = Module()
-
-        #m.submodules.align_in_a = self.in_a
-        #m.submodules.align_in_b = self.in_b
-        #m.submodules.align_out_a = self.out_a
-        #m.submodules.align_out_b = self.out_b
-
-        # NOTE: this does *not* do single-cycle multi-shifting,
-        #       it *STAYS* in the align state until exponents match
+        comb = m.d.comb
 
         # exponent of a greater than b: shift b down
-        m.d.comb += self.exp_eq.eq(0)
-        m.d.comb += self.out_a.eq(self.in_a)
-        m.d.comb += self.out_b.eq(self.in_b)
+        comb += self.exp_eq.eq(0)
+        comb += self.out_a.eq(self.in_a)
+        comb += self.out_b.eq(self.in_b)
         agtb = Signal(reset_less=True)
         altb = Signal(reset_less=True)
-        m.d.comb += agtb.eq(self.in_a.e > self.in_b.e)
-        m.d.comb += altb.eq(self.in_a.e < self.in_b.e)
+        comb += agtb.eq(self.in_a.e > self.in_b.e)
+        comb += altb.eq(self.in_a.e < self.in_b.e)
         with m.If(agtb):
-            m.d.comb += self.out_b.shift_down(self.in_b)
+            comb += self.out_b.shift_down(self.in_b)
         # exponent of b greater than a: shift a down
         with m.Elif(altb):
-            m.d.comb += self.out_a.shift_down(self.in_a)
+            comb += self.out_a.shift_down(self.in_a)
         # exponents equal: move to next stage.
         with m.Else():
-            m.d.comb += self.exp_eq.eq(1)
+            comb += self.exp_eq.eq(1)
         return m
 
 
-class FPAddAlignMulti(FPState):
-
-    def __init__(self, width, pspec):
-        FPState.__init__(self, "align")
-        self.mod = FPAddAlignMultiMod(width, pspec)
-        self.out_a = FPNumBaseRecord(width)
-        self.out_b = FPNumBaseRecord(width)
-        self.exp_eq = Signal(reset_less=True)
-
-    def setup(self, m, in_a, in_b):
-        """ links module to inputs and outputs
-        """
-        m.submodules.align = self.mod
-        m.d.comb += self.mod.in_a.eq(in_a)
-        m.d.comb += self.mod.in_b.eq(in_b)
-        m.d.comb += self.exp_eq.eq(self.mod.exp_eq)
-        m.d.sync += self.out_a.eq(self.mod.out_a)
-        m.d.sync += self.out_b.eq(self.mod.out_b)
+class FPAddAlignSingleMod(PipeModBase):
 
-    def action(self, m):
-        with m.If(self.exp_eq):
-            m.next = "add_0"
-
-
-class FPAddAlignSingleMod(Elaboratable):
-
-    def __init__(self, width, pspec):
-        self.width = width
-        self.pspec = pspec
-        self.i = self.ispec()
-        self.o = self.ospec()
+    def __init__(self, pspec):
+        super().__init__(pspec, "align")
 
     def ispec(self):
-        return FPSCData(self.width, self.pspec, True)
+        return FPSCData(self.pspec, True)
 
     def ospec(self):
-        return FPNumIn2Ops(self.width, self.pspec)
-
-    def process(self, i):
-        return self.o
-
-    def setup(self, m, i):
-        """ links module to inputs and outputs
-        """
-        m.submodules.align = self
-        m.d.comb += self.i.eq(i)
+        return FPSCData(self.pspec, True)
 
     def elaborate(self, platform):
         """ Aligns A against B or B against A, depending on which has the
@@ -126,24 +66,27 @@ class FPAddAlignSingleMod(Elaboratable):
 
             the shifter used here is quite expensive in terms of gates.
             Mux A or B in (and out) into temporaries, as only one of them
-            needs to be aligned against the other
+            needs to be aligned against the other.
+
+            code is therefore slightly complex because after testing which
+            exponent is greater, a and b get mux-routed into the multi-shifter
+            and so does the output.
         """
         m = Module()
+        comb = m.d.comb
 
-        #m.submodules.align_in_a = self.i.a
-        #m.submodules.align_in_b = self.i.b
-        #m.submodules.align_out_a = self.o.a
-        #m.submodules.align_out_b = self.o.b
+        ai = self.i.a
+        bi = self.i.b
+        width = self.pspec.width
+        espec = (len(ai.e), True)
 
         # temporary (muxed) input and output to be shifted
-        t_inp = FPNumBaseRecord(self.width)
-        t_out = FPNumBaseRecord(self.width)
-        espec = (len(self.i.a.e), True)
-        msr = MultiShiftRMerge(self.i.a.m_width, espec)
-        #m.submodules.align_t_in = t_inp
-        #m.submodules.align_t_out = t_out
+        t_inp = FPNumBaseRecord(width)
+        t_out = FPNumBaseRecord(width)
+        msr = MultiShiftRMerge(ai.m_width, espec)
         m.submodules.multishift_r = msr
 
+        # temporaries
         ediff = Signal(espec, reset_less=True)
         ediffr = Signal(espec, reset_less=True)
         tdiff = Signal(espec, reset_less=True)
@@ -151,64 +94,45 @@ class FPAddAlignSingleMod(Elaboratable):
         egz = Signal(reset_less=True)
 
         # connect multi-shifter to t_inp/out mantissa (and tdiff)
-        m.d.comb += msr.inp.eq(t_inp.m)
-        m.d.comb += msr.diff.eq(tdiff)
-        m.d.comb += t_out.m.eq(msr.m)
-        m.d.comb += t_out.e.eq(t_inp.e + tdiff)
-        m.d.comb += t_out.s.eq(t_inp.s)
-
-        m.d.comb += ediff.eq(self.i.a.e - self.i.b.e)
-        m.d.comb += ediffr.eq(self.i.b.e - self.i.a.e)
-        m.d.comb += elz.eq(self.i.a.e < self.i.b.e)
-        m.d.comb += egz.eq(self.i.a.e > self.i.b.e)
-
-        # default: A-exp == B-exp, A and B untouched (fall through)
-        m.d.comb += self.o.a.eq(self.i.a)
-        m.d.comb += self.o.b.eq(self.i.b)
-        # only one shifter (muxed)
-        #m.d.comb += t_out.shift_down_multi(tdiff, t_inp)
-        # exponent of a greater than b: shift b down
-        with m.If(~self.i.out_do_z):
-            with m.If(egz):
-                m.d.comb += [t_inp.eq(self.i.b),
-                             tdiff.eq(ediff),
-                             self.o.b.eq(t_out),
-                             self.o.b.s.eq(self.i.b.s), # whoops forgot sign
-                            ]
-            # exponent of b greater than a: shift a down
-            with m.Elif(elz):
-                m.d.comb += [t_inp.eq(self.i.a),
-                             tdiff.eq(ediffr),
-                             self.o.a.eq(t_out),
-                             self.o.a.s.eq(self.i.a.s), # whoops forgot sign
-                            ]
-
-        m.d.comb += self.o.ctx.eq(self.i.ctx)
-        m.d.comb += self.o.z.eq(self.i.z)
-        m.d.comb += self.o.out_do_z.eq(self.i.out_do_z)
-        m.d.comb += self.o.oz.eq(self.i.oz)
+        # (only one: input/output is muxed)
+        comb += msr.inp.eq(t_inp.m)
+        comb += msr.diff.eq(tdiff)
+        comb += t_out.m.eq(msr.m)
+        comb += t_out.e.eq(Mux(egz, ai.e, bi.e))
+        comb += t_out.s.eq(t_inp.s)
+
+        # work out exponent difference, set up mux-tests if a > b or b > a
+        comb += ediff.eq(ai.e - bi.e)   # a - b
+        comb += ediffr.eq(-ediff)                   # b - a
+        comb += elz.eq(ediffr > 0)     # ae < be
+        comb += egz.eq(ediff > 0)    # ae > be
+
+        # decide what to input into the multi-shifter
+        comb += [t_inp.s.eq(Mux(egz, bi.s, ai.s)), # a/b sign
+                 t_inp.m.eq(Mux(egz, bi.m, ai.m)), # a/b mantissa
+                 t_inp.e.eq(Mux(egz, bi.e, ai.e)), # a/b exponent
+                 tdiff.eq(Mux(egz, ediff, ediffr)),
+                ]
+
+        # now decide where (if) to route the *output* of the multi-shifter
+
+        # if a exponent greater, route mshifted-out to b? otherwise just b
+        comb += [self.o.b.e.eq(Mux(egz, t_out.e, bi.e)), # exponent
+                 self.o.b.m.eq(Mux(egz, t_out.m, bi.m)), # mantissa
+                 self.o.b.s.eq(bi.s),                    # sign as-is
+        ]
+        # if b exponent greater, route mshifted-out to a? otherwise just a
+        comb += [self.o.a.e.eq(Mux(elz, t_out.e, ai.e)), # exponent
+                 self.o.a.m.eq(Mux(elz, t_out.m, ai.m)), # mantissa
+                 self.o.a.s.eq(ai.s),                    # sign as-is
+        ]
+
+        # pass context through
+        comb += self.o.ctx.eq(self.i.ctx)
+        comb += self.o.z.eq(self.i.z)
+        comb += self.o.out_do_z.eq(self.i.out_do_z)
+        comb += self.o.oz.eq(self.i.oz)
+        comb += self.o.rm.eq(self.i.rm)
 
         return m
 
-
-class FPAddAlignSingle(FPState):
-
-    def __init__(self, width, pspec):
-        FPState.__init__(self, "align")
-        self.mod = FPAddAlignSingleMod(width, pspec)
-        self.out_a = FPNumIn(None, width)
-        self.out_b = FPNumIn(None, width)
-
-    def setup(self, m, i):
-        """ links module to inputs and outputs
-        """
-        self.mod.setup(m, i)
-
-        # NOTE: could be done as comb
-        m.d.sync += self.out_a.eq(self.mod.out_a)
-        m.d.sync += self.out_b.eq(self.mod.out_b)
-
-    def action(self, m):
-        m.next = "add_0"
-
-