add dual alignment on e/m in fpmul
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 14 Jul 2019 06:25:48 +0000 (07:25 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 14 Jul 2019 06:25:48 +0000 (07:25 +0100)
src/ieee754/fpmul/align.py [new file with mode: 0644]
src/ieee754/fpmul/specialcases.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
+
+
index cd45701819af4ee63b3c1f3a11dd63510db5c0a4..43fc1810dfc17a28082634cd1a8327a422bd3ee8 100644 (file)
@@ -10,6 +10,7 @@ from nmutil.singlepipe import SimpleHandshake, StageChain
 from ieee754.fpcommon.fpbase import FPState, FPID
 from ieee754.fpcommon.getop import FPADDBaseData
 from ieee754.fpcommon.denorm import (FPSCData, FPAddDeNormMod)
+from ieee754.fpmul.align import FPAlignModSingle
 
 
 class FPMulSpecialCasesMod(Elaboratable):
@@ -148,8 +149,9 @@ class FPMulSpecialCasesDeNorm(FPState, SimpleHandshake):
         """
         smod = FPMulSpecialCasesMod(self.pspec)
         dmod = FPAddDeNormMod(self.pspec, False)
+        amod = FPAlignModSingle(self.pspec, False)
 
-        chain = StageChain([smod, dmod])
+        chain = StageChain([smod, dmod, amod])
         chain.setup(m, i)
 
         # only needed for break-out (early-out)