add dual alignment on e/m in fpmul
[ieee754fpu.git] / src / ieee754 / fpmul / align.py
diff --git a/src/ieee754/fpmul/align.py b/src/ieee754/fpmul/align.py
new file mode 100644 (file)
index 0000000..5bd0a3a
--- /dev/null
@@ -0,0 +1,108 @@
+# IEEE Floating Point Multiplier
+
+from nmigen import Module, Signal, Cat, Mux, Elaboratable
+from nmigen.lib.coding import PriorityEncoder
+from nmigen.cli import main, verilog
+from math import log
+
+from nmutil.singlepipe import (StageChain, SimpleHandshake)
+
+from ieee754.fpcommon.fpbase import (Overflow, OverflowMod,
+                                     FPNumBase, FPNumBaseRecord)
+from ieee754.fpcommon.fpbase import MultiShiftRMerge
+from ieee754.fpcommon.fpbase import FPState
+from ieee754.fpcommon.getop import FPPipeContext
+
+
+from ieee754.fpcommon.fpbase import FPState
+from ieee754.fpcommon.denorm import FPSCData
+from ieee754.fpcommon.postcalc import FPAddStage1Data
+
+
+class FPAlignModSingle(Elaboratable):
+
+    def __init__(self, pspec, e_extra=False):
+        self.pspec = pspec
+        self.e_extra = e_extra
+        self.i = self.ispec()
+        self.o = self.ospec()
+
+    def ispec(self):
+        return FPSCData(self.pspec, False)
+
+    def ospec(self):
+        return FPSCData(self.pspec, False)
+
+    def setup(self, m, i):
+        """ links module to inputs and outputs
+        """
+        m.submodules.align = self
+        m.d.comb += self.i.eq(i)
+
+    def process(self, i):
+        return self.o
+
+    def elaborate(self, platform):
+        m = Module()
+
+        mwid = self.o.z.m_width
+        pe_a = PriorityEncoder(mwid)
+        pe_b = PriorityEncoder(mwid)
+        m.submodules.norm_pe_a = pe_a
+        m.submodules.norm_pe_b = pe_b
+
+        self.o.a.m.name = "o_a_m"
+        self.o.b.m.name = "o_b_m"
+
+        m.submodules.norm1_insel_a = insel_a = FPNumBase(self.i.a)
+        m.submodules.norm1_insel_b = insel_b = FPNumBase(self.i.b)
+        insel_a.m.name = "i_a_m"
+        insel_b.m.name = "i_b_m"
+
+        # copy input to output (overridden below)
+        m.d.comb += self.o.eq(self.i)
+
+        # normalisation increase/decrease conditions
+        decrease_a = Signal(reset_less=True)
+        decrease_b = Signal(reset_less=True)
+        m.d.comb += decrease_a.eq(insel_a.m_msbzero)
+        m.d.comb += decrease_b.eq(insel_b.m_msbzero)
+
+        # ok this is near-identical to FPNorm.  TODO: modularise
+        with m.If(~self.i.out_do_z):
+            with m.If(decrease_a):
+                # *sigh* not entirely obvious: count leading zeros (clz)
+                # with a PriorityEncoder: to find from the MSB
+                # we reverse the order of the bits.
+                temp_a = Signal(mwid, reset_less=True)
+                clz_a = Signal((len(insel_a.e), True), reset_less=True)
+                m.d.comb += [
+                    pe_a.i.eq(insel_a.m[::-1]),      # inverted
+                    clz_a.eq(pe_a.o),                # count zeros from MSB down
+                    temp_a.eq((insel_a.m << clz_a)), # shift mantissa UP
+                    self.o.a.e.eq(insel_a.e - clz_a), # DECREASE exponent
+                    self.o.a.m.eq(temp_a),
+                ]
+
+            with m.If(decrease_b):
+                # *sigh* not entirely obvious: count leading zeros (clz)
+                # with a PriorityEncoder: to find from the MSB
+                # we reverse the order of the bits.
+                temp_b = Signal(mwid, reset_less=True)
+                clz_b = Signal((len(insel_b.e), True), reset_less=True)
+                m.d.comb += [
+                    pe_b.i.eq(insel_b.m[::-1]),      # inverted
+                    clz_b.eq(pe_b.o),                # count zeros from MSB down
+                    temp_b.eq((insel_b.m << clz_b)), # shift mantissa UP
+                    self.o.b.e.eq(insel_b.e - clz_b), # DECREASE exponent
+                    self.o.b.m.eq(temp_b),
+                ]
+
+        #m.d.comb += self.o.roundz.eq(of.roundz_out)
+        #m.d.comb += self.o.ctx.eq(self.i.ctx)
+        #m.d.comb += self.o.out_do_z.eq(self.i.out_do_z)
+        #m.d.comb += self.o.oz.eq(self.i.oz)
+
+        return m
+
+