cleanup and add a new common class, FPModBase
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 31 Jul 2019 11:39:44 +0000 (12:39 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 31 Jul 2019 11:39:44 +0000 (12:39 +0100)
src/ieee754/fpadd/add0.py
src/ieee754/fpadd/add1.py
src/ieee754/fpadd/align.py
src/ieee754/fpadd/specialcases.py
src/ieee754/fpcommon/modbase.py [new file with mode: 0644]

index 6ad76c3d9bdcd71e9625cc79e69214eb89a48b28..0c1820e8efb1d144665d1d1a4ef32156d1dabc22 100644 (file)
@@ -4,9 +4,11 @@ Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
 
 """
 
-from nmigen import Module, Signal, Cat, Elaboratable
+from nmigen import Module, Signal, Cat
 from nmigen.cli import main, verilog
 
+from ieee754.fpcommon.modbase import FPModBase
+
 from ieee754.fpcommon.fpbase import FPNumBase, FPNumBaseRecord
 from ieee754.fpcommon.denorm import FPSCData
 from ieee754.fpcommon.getop import FPPipeContext
@@ -28,12 +30,10 @@ class FPAddStage0Data:
                 self.tot.eq(i.tot), self.ctx.eq(i.ctx)]
 
 
-class FPAddStage0Mod(Elaboratable):
+class FPAddStage0Mod(FPModBase):
 
     def __init__(self, pspec):
-        self.pspec = pspec
-        self.i = self.ispec()
-        self.o = self.ospec()
+        super().__init__(pspec, "add0")
 
     def ispec(self):
         return FPSCData(self.pspec, True)
@@ -41,15 +41,6 @@ class FPAddStage0Mod(Elaboratable):
     def ospec(self):
         return FPAddStage0Data(self.pspec)
 
-    def process(self, i):
-        return self.o
-
-    def setup(self, m, i):
-        """ links module to inputs and outputs
-        """
-        m.submodules.add0 = self
-        m.d.comb += self.i.eq(i)
-
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
index 15ca3c5ee6c02c1471b099dbcba8fcc1d2b2ac0f..6b51e1e2ea9f8a9ba3773be0936a3c98a498bc1a 100644 (file)
@@ -8,19 +8,18 @@ from nmigen import Module, Signal, Elaboratable
 from nmigen.cli import main, verilog
 from math import log
 
+from ieee754.fpcommon.modbase import FPModBase
 from ieee754.fpcommon.postcalc import FPAddStage1Data
 from ieee754.fpadd.add0 import FPAddStage0Data
 
 
-class FPAddStage1Mod(Elaboratable):
+class FPAddStage1Mod(FPModBase):
     """ Second stage of add: preparation for normalisation.
         detects when tot sum is too big (tot[27] is kinda a carry bit)
     """
 
     def __init__(self, pspec):
-        self.pspec = pspec
-        self.i = self.ispec()
-        self.o = self.ospec()
+        super().__init__(pspec, "add1")
 
     def ispec(self):
         return FPAddStage0Data(self.pspec)
@@ -28,15 +27,6 @@ class FPAddStage1Mod(Elaboratable):
     def ospec(self):
         return FPAddStage1Data(self.pspec)
 
-    def process(self, i):
-        return self.o
-
-    def setup(self, m, i):
-        """ links module to inputs and outputs
-        """
-        m.submodules.add1 = self
-        m.d.comb += self.i.eq(i)
-
     def elaborate(self, platform):
         m = Module()
         comb = m.d.comb
index c8405af149c636742c1e41979464bf6a6e0aa62d..bd1b4c062843835bf1e213ba466a0ff36d68be10 100644 (file)
@@ -2,10 +2,10 @@
 # Copyright (C) Jonathan P Dawson 2013
 # 2013-12-12
 
-from nmigen import Module, Signal, Elaboratable
+from nmigen import Module, Signal
 from nmigen.cli import main, verilog
 
-from ieee754.fpcommon.fpbase import FPNumOut, FPNumIn, FPNumBase
+from ieee754.fpcommon.modbase import FPModBase
 from ieee754.fpcommon.fpbase import FPNumBaseRecord
 from ieee754.fpcommon.fpbase import MultiShiftRMerge
 from ieee754.fpcommon.denorm import FPSCData
@@ -71,12 +71,10 @@ class FPAddAlignMultiMod:
         return m
 
 
-class FPAddAlignSingleMod(Elaboratable):
+class FPAddAlignSingleMod(FPModBase):
 
     def __init__(self, pspec):
-        self.pspec = pspec
-        self.i = self.ispec()
-        self.o = self.ospec()
+        super().__init__(pspec, "align")
 
     def ispec(self):
         return FPSCData(self.pspec, True)
@@ -84,15 +82,6 @@ class FPAddAlignSingleMod(Elaboratable):
     def ospec(self):
         return FPNumIn2Ops(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)
-
     def elaborate(self, platform):
         """ Aligns A against B or B against A, depending on which has the
             greater exponent.  This is done in a *single* cycle using
index 33b1811afcf225e0fe9611d87141f132b5f7d043..13d4c18220b66a4f7765a85c4fdc30c6e753b169 100644 (file)
@@ -2,10 +2,11 @@
 # Copyright (C) Jonathan P Dawson 2013
 # 2013-12-12
 
-from nmigen import Module, Signal, Cat, Const, Elaboratable
+from nmigen import Module, Signal, Cat, Const
 from nmigen.cli import main, verilog
 from math import log
 
+from ieee754.fpcommon.modbase import FPModBase
 from ieee754.fpcommon.fpbase import FPNumDecode
 from nmutil.singlepipe import StageChain
 from ieee754.pipeline import DynamicPipe
@@ -15,16 +16,14 @@ from ieee754.fpcommon.getop import FPADDBaseData
 from ieee754.fpcommon.denorm import (FPSCData, FPAddDeNormMod)
 
 
-class FPAddSpecialCasesMod(Elaboratable):
+class FPAddSpecialCasesMod(FPModBase):
     """ special cases: NaNs, infs, zeros, denormalised
         NOTE: some of these are unique to add.  see "Special Operations"
         https://steve.hollasch.net/cgindex/coding/ieeefloat.html
     """
 
     def __init__(self, pspec):
-        self.pspec = pspec
-        self.i = self.ispec()
-        self.o = self.ospec()
+        super().__init__(pspec, "specialcases")
 
     def ispec(self):
         return FPADDBaseData(self.pspec)
@@ -32,19 +31,9 @@ class FPAddSpecialCasesMod(Elaboratable):
     def ospec(self):
         return FPSCData(self.pspec, True)
 
-    def setup(self, m, i):
-        """ links module to inputs and outputs
-        """
-        m.submodules.specialcases = self
-        m.d.comb += self.i.eq(i)
-
-    def process(self, i):
-        return self.o
-
     def elaborate(self, platform):
         m = Module()
-
-        #m.submodules.sc_out_z = self.o.z
+        comb = m.d.comb
 
         # decode: XXX really should move to separate stage
         width = self.pspec.width
@@ -52,96 +41,92 @@ class FPAddSpecialCasesMod(Elaboratable):
         b1 = FPNumBaseRecord(width)
         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),
+        comb += [a1.v.eq(self.i.a),
                      b1.v.eq(self.i.b),
                      self.o.a.eq(a1),
                      self.o.b.eq(b1)
                     ]
 
+        # temporaries used below
         s_nomatch = Signal(reset_less=True)
-        m.d.comb += s_nomatch.eq(a1.s != b1.s)
-
         m_match = Signal(reset_less=True)
-        m.d.comb += m_match.eq(a1.m == b1.m)
-
         e_match = Signal(reset_less=True)
-        m.d.comb += e_match.eq(a1.e == b1.e)
-
         aeqmb = Signal(reset_less=True)
-        m.d.comb += aeqmb.eq(s_nomatch & m_match & e_match)
-
         abz = Signal(reset_less=True)
-        m.d.comb += abz.eq(a1.is_zero & b1.is_zero)
-
         abnan = Signal(reset_less=True)
-        m.d.comb += abnan.eq(a1.is_nan | b1.is_nan)
-
         bexp128s = Signal(reset_less=True)
-        m.d.comb += bexp128s.eq(b1.exp_128 & s_nomatch)
+
+        comb += s_nomatch.eq(a1.s != b1.s)
+        comb += m_match.eq(a1.m == b1.m)
+        comb += e_match.eq(a1.e == b1.e)
+        comb += aeqmb.eq(s_nomatch & m_match & e_match)
+        comb += abz.eq(a1.is_zero & b1.is_zero)
+        comb += abnan.eq(a1.is_nan | b1.is_nan)
+        comb += bexp128s.eq(b1.exp_128 & s_nomatch)
 
         # default bypass
-        m.d.comb += self.o.out_do_z.eq(1)
+        comb += self.o.out_do_z.eq(1)
 
         # if a is NaN or b is NaN return NaN
         with m.If(abnan):
-            m.d.comb += self.o.z.nan(0)
+            comb += self.o.z.nan(0)
 
         # XXX WEIRDNESS for FP16 non-canonical NaN handling
         # under review
 
         ## if a is zero and b is NaN return -b
         #with m.If(a.is_zero & (a.s==0) & b.is_nan):
-        #    m.d.comb += self.o.out_do_z.eq(1)
-        #    m.d.comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
+        #    comb += self.o.out_do_z.eq(1)
+        #    comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
 
         ## if b is zero and a is NaN return -a
         #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
-        #    m.d.comb += self.o.out_do_z.eq(1)
-        #    m.d.comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
+        #    comb += self.o.out_do_z.eq(1)
+        #    comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
 
         ## if a is -zero and b is NaN return -b
         #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
-        #    m.d.comb += self.o.out_do_z.eq(1)
-        #    m.d.comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
+        #    comb += self.o.out_do_z.eq(1)
+        #    comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
 
         ## if b is -zero and a is NaN return -a
         #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
-        #    m.d.comb += self.o.out_do_z.eq(1)
-        #    m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
+        #    comb += self.o.out_do_z.eq(1)
+        #    comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
 
         # if a is inf return inf (or NaN)
         with m.Elif(a1.is_inf):
-            m.d.comb += self.o.z.inf(a1.s)
+            comb += self.o.z.inf(a1.s)
             # if a is inf and signs don't match return NaN
             with m.If(bexp128s):
-                m.d.comb += self.o.z.nan(0)
+                comb += self.o.z.nan(0)
 
         # if b is inf return inf
         with m.Elif(b1.is_inf):
-            m.d.comb += self.o.z.inf(b1.s)
+            comb += self.o.z.inf(b1.s)
 
         # if a is zero and b zero return signed-a/b
         with m.Elif(abz):
-            m.d.comb += self.o.z.create(a1.s & b1.s, b1.e, b1.m[3:-1])
+            comb += self.o.z.create(a1.s & b1.s, b1.e, b1.m[3:-1])
 
         # if a is zero return b
         with m.Elif(a1.is_zero):
-            m.d.comb += self.o.z.create(b1.s, b1.e, b1.m[3:-1])
+            comb += self.o.z.create(b1.s, b1.e, b1.m[3:-1])
 
         # if b is zero return a
         with m.Elif(b1.is_zero):
-            m.d.comb += self.o.z.create(a1.s, a1.e, a1.m[3:-1])
+            comb += self.o.z.create(a1.s, a1.e, a1.m[3:-1])
 
         # if a equal to -b return zero (+ve zero)
         with m.Elif(aeqmb):
-            m.d.comb += self.o.z.zero(0)
+            comb += self.o.z.zero(0)
 
         # Denormalised Number checks next, so pass a/b data through
         with m.Else():
-            m.d.comb += self.o.out_do_z.eq(0)
+            comb += self.o.out_do_z.eq(0)
 
-        m.d.comb += self.o.oz.eq(self.o.z.v)
-        m.d.comb += self.o.ctx.eq(self.i.ctx)
+        comb += self.o.oz.eq(self.o.z.v)
+        comb += self.o.ctx.eq(self.i.ctx)
 
         return m
 
@@ -155,7 +140,6 @@ class FPAddSpecialCasesDeNorm(DynamicPipe):
     def __init__(self, pspec):
         self.pspec = pspec
         super().__init__(pspec)
-        self.out = self.ospec()
 
     def ispec(self):
         return FPADDBaseData(self.pspec) # SC ispec
diff --git a/src/ieee754/fpcommon/modbase.py b/src/ieee754/fpcommon/modbase.py
new file mode 100644 (file)
index 0000000..0daa6f6
--- /dev/null
@@ -0,0 +1,20 @@
+from nmigen import Elaboratable
+
+class FPModBase(Elaboratable):
+    """FPModBase: common code between nearly every pipeline module
+    """
+    def __init__(self, pspec, modname):
+        self.modname = modname
+        self.pspec = pspec
+        self.i = self.ispec()
+        self.o = self.ospec()
+
+    def process(self, i):
+        return self.o
+
+    def setup(self, m, i):
+        """ links module to inputs and outputs
+        """
+        setattr(m.submodules, self.modname, self)
+        m.d.comb += self.i.eq(i)
+