move ids to member variable
[ieee754fpu.git] / src / add / nmigen_add_experiment.py
index 02a9ba15938c7bd428fbd19a4f133756cc00ba62..d829e0ec1a114695695bdacf68df314df52d6861 100644 (file)
@@ -7,7 +7,7 @@ from nmigen.lib.coding import PriorityEncoder
 from nmigen.cli import main, verilog
 
 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPNumBase
 from nmigen.cli import main, verilog
 
 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPNumBase
-from fpbase import MultiShiftRMerge
+from fpbase import MultiShiftRMerge, Trigger
 #from fpbase import FPNumShiftMultiRight
 
 class FPState(FPBase):
 #from fpbase import FPNumShiftMultiRight
 
 class FPState(FPBase):
@@ -28,17 +28,17 @@ class FPState(FPBase):
 class FPGetOpMod:
     def __init__(self, width):
         self.in_op = FPOp(width)
 class FPGetOpMod:
     def __init__(self, width):
         self.in_op = FPOp(width)
-        self.out_op = FPNumIn(self.in_op, width)
+        self.out_op = Signal(width)
         self.out_decode = Signal(reset_less=True)
 
     def elaborate(self, platform):
         m = Module()
         m.d.comb += self.out_decode.eq((self.in_op.ack) & (self.in_op.stb))
         self.out_decode = Signal(reset_less=True)
 
     def elaborate(self, platform):
         m = Module()
         m.d.comb += self.out_decode.eq((self.in_op.ack) & (self.in_op.stb))
-        #m.submodules.get_op_in = self.in_op
-        m.submodules.get_op_out = self.out_op
+        m.submodules.get_op_in = self.in_op
+        #m.submodules.get_op_out = self.out_op
         with m.If(self.out_decode):
             m.d.comb += [
         with m.If(self.out_decode):
             m.d.comb += [
-                self.out_op.decode(self.in_op.v),
+                self.out_op.eq(self.in_op.v),
             ]
         return m
 
             ]
         return m
 
@@ -52,7 +52,7 @@ class FPGetOp(FPState):
         self.out_state = out_state
         self.mod = FPGetOpMod(width)
         self.in_op = in_op
         self.out_state = out_state
         self.mod = FPGetOpMod(width)
         self.in_op = in_op
-        self.out_op = FPNumIn(in_op, width)
+        self.out_op = Signal(width)
         self.out_decode = Signal(reset_less=True)
 
     def setup(self, m, in_op):
         self.out_decode = Signal(reset_less=True)
 
     def setup(self, m, in_op):
@@ -60,7 +60,7 @@ class FPGetOp(FPState):
         """
         setattr(m.submodules, self.state_from, self.mod)
         m.d.comb += self.mod.in_op.copy(in_op)
         """
         setattr(m.submodules, self.state_from, self.mod)
         m.d.comb += self.mod.in_op.copy(in_op)
-        m.d.comb += self.out_op.v.eq(self.mod.out_op.v)
+        #m.d.comb += self.out_op.eq(self.mod.out_op)
         m.d.comb += self.out_decode.eq(self.mod.out_decode)
 
     def action(self, m):
         m.d.comb += self.out_decode.eq(self.mod.out_decode)
 
     def action(self, m):
@@ -68,23 +68,72 @@ class FPGetOp(FPState):
             m.next = self.out_state
             m.d.sync += [
                 self.in_op.ack.eq(0),
             m.next = self.out_state
             m.d.sync += [
                 self.in_op.ack.eq(0),
-                self.out_op.copy(self.mod.out_op)
+                self.out_op.eq(self.mod.out_op)
             ]
         with m.Else():
             m.d.sync += self.in_op.ack.eq(1)
 
 
             ]
         with m.Else():
             m.d.sync += self.in_op.ack.eq(1)
 
 
-class FPGetOpB(FPState):
-    """ gets operand b
+class FPGet2OpMod(Trigger):
+    def __init__(self, width):
+        Trigger.__init__(self)
+        self.in_op1 = Signal(width, reset_less=True)
+        self.in_op2 = Signal(width, reset_less=True)
+        self.out_op1 = FPNumIn(None, width)
+        self.out_op2 = FPNumIn(None, width)
+
+    def elaborate(self, platform):
+        m = Trigger.elaborate(self, platform)
+        #m.submodules.get_op_in = self.in_op
+        m.submodules.get_op1_out = self.out_op1
+        m.submodules.get_op2_out = self.out_op2
+        with m.If(self.trigger):
+            m.d.comb += [
+                self.out_op1.decode(self.in_op1),
+                self.out_op2.decode(self.in_op2),
+            ]
+        return m
+
+
+class FPGet2Op(FPState):
+    """ gets operands
     """
 
     """
 
-    def __init__(self, in_b, width):
-        FPState.__init__(self, "get_b")
-        self.in_b = in_b
-        self.b = FPNumIn(self.in_b, width)
+    def __init__(self, in_state, out_state, in_op1, in_op2, width):
+        FPState.__init__(self, in_state)
+        self.out_state = out_state
+        self.mod = FPGet2OpMod(width)
+        self.in_op1 = in_op1
+        self.in_op2 = in_op2
+        self.out_op1 = FPNumIn(None, width)
+        self.out_op2 = FPNumIn(None, width)
+        self.in_stb = Signal(reset_less=True)
+        self.out_ack = Signal(reset_less=True)
+        self.out_decode = Signal(reset_less=True)
+
+    def setup(self, m, in_op1, in_op2, in_stb, in_ack):
+        """ links module to inputs and outputs
+        """
+        m.submodules.get_ops = self.mod
+        m.d.comb += self.mod.in_op1.eq(in_op1)
+        m.d.comb += self.mod.in_op2.eq(in_op2)
+        m.d.comb += self.mod.stb.eq(in_stb)
+        m.d.comb += self.out_ack.eq(self.mod.ack)
+        m.d.comb += self.out_decode.eq(self.mod.trigger)
+        m.d.comb += in_ack.eq(self.mod.ack)
 
     def action(self, m):
 
     def action(self, m):
-        self.get_op(m, self.in_b, self.b, "special_cases")
+        with m.If(self.out_decode):
+            m.next = self.out_state
+            m.d.sync += [
+                self.mod.ack.eq(0),
+                #self.out_op1.v.eq(self.mod.out_op1.v),
+                #self.out_op2.v.eq(self.mod.out_op2.v),
+                self.out_op1.copy(self.mod.out_op1),
+                self.out_op2.copy(self.mod.out_op2)
+            ]
+        with m.Else():
+            m.d.sync += self.mod.ack.eq(1)
 
 
 class FPAddSpecialCasesMod:
 
 
 class FPAddSpecialCasesMod:
@@ -99,12 +148,12 @@ class FPAddSpecialCasesMod:
         self.out_z = FPNumOut(width, False)
         self.out_do_z = Signal(reset_less=True)
 
         self.out_z = FPNumOut(width, False)
         self.out_do_z = Signal(reset_less=True)
 
-    def setup(self, m, in_a, in_b, out_z, out_do_z):
+    def setup(self, m, in_a, in_b, out_do_z):
         """ links module to inputs and outputs
         """
         """ links module to inputs and outputs
         """
+        m.submodules.specialcases = self
         m.d.comb += self.in_a.copy(in_a)
         m.d.comb += self.in_b.copy(in_b)
         m.d.comb += self.in_a.copy(in_a)
         m.d.comb += self.in_b.copy(in_b)
-        #m.d.comb += out_z.v.eq(self.out_z.v)
         m.d.comb += out_do_z.eq(self.out_do_z)
 
     def elaborate(self, platform):
         m.d.comb += out_do_z.eq(self.out_do_z)
 
     def elaborate(self, platform):
@@ -192,19 +241,43 @@ class FPAddSpecialCasesMod:
         return m
 
 
         return m
 
 
-class FPAddSpecialCases(FPState):
+class FPID:
+    def __init__(self, id_wid):
+        self.id_wid = id_wid
+        if self.id_wid:
+            self.in_mid = Signal(id_wid, reset_less=True)
+            self.out_mid = Signal(id_wid, reset_less=True)
+        else:
+            self.in_mid = None
+            self.out_mid = None
+
+    def idsync(self, m):
+        if self.id_wid is not None:
+            m.d.sync += self.out_mid.eq(self.in_mid)
+
+
+class FPAddSpecialCases(FPState, FPID):
     """ 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
     """
 
     """ 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, width):
+    def __init__(self, width, id_wid):
         FPState.__init__(self, "special_cases")
         FPState.__init__(self, "special_cases")
+        FPID.__init__(self, id_wid)
         self.mod = FPAddSpecialCasesMod(width)
         self.out_z = FPNumOut(width, False)
         self.out_do_z = Signal(reset_less=True)
 
         self.mod = FPAddSpecialCasesMod(width)
         self.out_z = FPNumOut(width, False)
         self.out_do_z = Signal(reset_less=True)
 
+    def setup(self, m, in_a, in_b, in_mid):
+        """ links module to inputs and outputs
+        """
+        self.mod.setup(m, in_a, in_b, self.out_do_z)
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
+
     def action(self, m):
     def action(self, m):
+        self.idsync(m)
         with m.If(self.out_do_z):
             m.d.sync += self.out_z.v.eq(self.mod.out_z.v) # only take the output
             m.next = "put_z"
         with m.If(self.out_do_z):
             m.d.sync += self.out_z.v.eq(self.mod.out_z.v) # only take the output
             m.next = "put_z"
@@ -212,6 +285,42 @@ class FPAddSpecialCases(FPState):
             m.next = "denormalise"
 
 
             m.next = "denormalise"
 
 
+class FPAddSpecialCasesDeNorm(FPState, FPID):
+    """ 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, width, id_wid):
+        FPState.__init__(self, "special_cases")
+        FPID.__init__(self, id_wid)
+        self.smod = FPAddSpecialCasesMod(width)
+        self.out_z = FPNumOut(width, False)
+        self.out_do_z = Signal(reset_less=True)
+
+        self.dmod = FPAddDeNormMod(width)
+        self.out_a = FPNumBase(width)
+        self.out_b = FPNumBase(width)
+
+    def setup(self, m, in_a, in_b, in_mid):
+        """ links module to inputs and outputs
+        """
+        self.smod.setup(m, in_a, in_b, self.out_do_z)
+        self.dmod.setup(m, in_a, in_b)
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
+
+    def action(self, m):
+        self.idsync(m)
+        with m.If(self.out_do_z):
+            m.d.sync += self.out_z.v.eq(self.smod.out_z.v) # only take output
+            m.next = "put_z"
+        with m.Else():
+            m.next = "align"
+            m.d.sync += self.out_a.copy(self.dmod.out_a)
+            m.d.sync += self.out_b.copy(self.dmod.out_b)
+
+
 class FPAddDeNormMod(FPState):
 
     def __init__(self, width):
 class FPAddDeNormMod(FPState):
 
     def __init__(self, width):
@@ -220,6 +329,13 @@ class FPAddDeNormMod(FPState):
         self.out_a = FPNumBase(width)
         self.out_b = FPNumBase(width)
 
         self.out_a = FPNumBase(width)
         self.out_b = FPNumBase(width)
 
+    def setup(self, m, in_a, in_b):
+        """ links module to inputs and outputs
+        """
+        m.submodules.denormalise = self
+        m.d.comb += self.in_a.copy(in_a)
+        m.d.comb += self.in_b.copy(in_b)
+
     def elaborate(self, platform):
         m = Module()
         m.submodules.denorm_in_a = self.in_a
     def elaborate(self, platform):
         m = Module()
         m.submodules.denorm_in_a = self.in_a
@@ -242,22 +358,24 @@ class FPAddDeNormMod(FPState):
         return m
 
 
         return m
 
 
-class FPAddDeNorm(FPState):
+class FPAddDeNorm(FPState, FPID):
 
 
-    def __init__(self, width):
+    def __init__(self, width, id_wid):
         FPState.__init__(self, "denormalise")
         FPState.__init__(self, "denormalise")
+        FPID.__init__(self, id_wid)
         self.mod = FPAddDeNormMod(width)
         self.out_a = FPNumBase(width)
         self.out_b = FPNumBase(width)
 
         self.mod = FPAddDeNormMod(width)
         self.out_a = FPNumBase(width)
         self.out_b = FPNumBase(width)
 
-    def setup(self, m, in_a, in_b):
+    def setup(self, m, in_a, in_b, in_mid):
         """ links module to inputs and outputs
         """
         """ links module to inputs and outputs
         """
-        m.submodules.denormalise = self.mod
-        m.d.comb += self.mod.in_a.copy(in_a)
-        m.d.comb += self.mod.in_b.copy(in_b)
+        self.mod.setup(m, in_a, in_b)
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
 
     def action(self, m):
 
     def action(self, m):
+        self.idsync(m)
         # Denormalised Number checks
         m.next = "align"
         m.d.sync += self.out_a.copy(self.mod.out_a)
         # Denormalised Number checks
         m.next = "align"
         m.d.sync += self.out_a.copy(self.mod.out_a)
@@ -306,16 +424,17 @@ class FPAddAlignMultiMod(FPState):
         return m
 
 
         return m
 
 
-class FPAddAlignMulti(FPState):
+class FPAddAlignMulti(FPState, FPID):
 
 
-    def __init__(self, width):
+    def __init__(self, width, id_wid):
+        FPID.__init__(self, id_wid)
         FPState.__init__(self, "align")
         self.mod = FPAddAlignMultiMod(width)
         self.out_a = FPNumIn(None, width)
         self.out_b = FPNumIn(None, width)
         self.exp_eq = Signal(reset_less=True)
 
         FPState.__init__(self, "align")
         self.mod = FPAddAlignMultiMod(width)
         self.out_a = FPNumIn(None, width)
         self.out_b = FPNumIn(None, width)
         self.exp_eq = Signal(reset_less=True)
 
-    def setup(self, m, in_a, in_b):
+    def setup(self, m, in_a, in_b, in_mid):
         """ links module to inputs and outputs
         """
         m.submodules.align = self.mod
         """ links module to inputs and outputs
         """
         m.submodules.align = self.mod
@@ -324,8 +443,11 @@ class FPAddAlignMulti(FPState):
         #m.d.comb += self.out_a.copy(self.mod.out_a)
         #m.d.comb += self.out_b.copy(self.mod.out_b)
         m.d.comb += self.exp_eq.eq(self.mod.exp_eq)
         #m.d.comb += self.out_a.copy(self.mod.out_a)
         #m.d.comb += self.out_b.copy(self.mod.out_b)
         m.d.comb += self.exp_eq.eq(self.mod.exp_eq)
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
 
     def action(self, m):
 
     def action(self, m):
+        self.idsync(m)
         m.d.sync += self.out_a.copy(self.mod.out_a)
         m.d.sync += self.out_b.copy(self.mod.out_b)
         with m.If(self.exp_eq):
         m.d.sync += self.out_a.copy(self.mod.out_a)
         m.d.sync += self.out_b.copy(self.mod.out_b)
         with m.If(self.exp_eq):
@@ -341,6 +463,13 @@ class FPAddAlignSingleMod:
         self.out_a = FPNumIn(None, width)
         self.out_b = FPNumIn(None, width)
 
         self.out_a = FPNumIn(None, width)
         self.out_b = FPNumIn(None, width)
 
+    def setup(self, m, in_a, in_b):
+        """ links module to inputs and outputs
+        """
+        m.submodules.align = self
+        m.d.comb += self.in_a.copy(in_a)
+        m.d.comb += self.in_b.copy(in_b)
+
     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
     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
@@ -406,28 +535,71 @@ class FPAddAlignSingleMod:
         return m
 
 
         return m
 
 
-class FPAddAlignSingle(FPState):
+class FPAddAlignSingle(FPState, FPID):
 
 
-    def __init__(self, width):
+    def __init__(self, width, id_wid):
         FPState.__init__(self, "align")
         FPState.__init__(self, "align")
+        FPID.__init__(self, id_wid)
         self.mod = FPAddAlignSingleMod(width)
         self.out_a = FPNumIn(None, width)
         self.out_b = FPNumIn(None, width)
 
         self.mod = FPAddAlignSingleMod(width)
         self.out_a = FPNumIn(None, width)
         self.out_b = FPNumIn(None, width)
 
-    def setup(self, m, in_a, in_b):
+    def setup(self, m, in_a, in_b, in_mid):
         """ links module to inputs and outputs
         """
         """ links module to inputs and outputs
         """
-        m.submodules.align = self.mod
-        m.d.comb += self.mod.in_a.copy(in_a)
-        m.d.comb += self.mod.in_b.copy(in_b)
+        self.mod.setup(m, in_a, in_b)
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
 
     def action(self, m):
 
     def action(self, m):
+        self.idsync(m)
         # NOTE: could be done as comb
         m.d.sync += self.out_a.copy(self.mod.out_a)
         m.d.sync += self.out_b.copy(self.mod.out_b)
         m.next = "add_0"
 
 
         # NOTE: could be done as comb
         m.d.sync += self.out_a.copy(self.mod.out_a)
         m.d.sync += self.out_b.copy(self.mod.out_b)
         m.next = "add_0"
 
 
+class FPAddAlignSingleAdd(FPState, FPID):
+
+    def __init__(self, width, id_wid):
+        FPState.__init__(self, "align")
+        FPID.__init__(self, id_wid)
+        self.mod = FPAddAlignSingleMod(width)
+        self.out_a = FPNumIn(None, width)
+        self.out_b = FPNumIn(None, width)
+
+        self.a0mod = FPAddStage0Mod(width)
+        self.a0_out_z = FPNumBase(width, False)
+        self.out_tot = Signal(self.a0_out_z.m_width + 4, reset_less=True)
+        self.a0_out_z = FPNumBase(width, False)
+
+        self.a1mod = FPAddStage1Mod(width)
+        self.out_z = FPNumBase(width, False)
+        self.out_of = Overflow()
+
+    def setup(self, m, in_a, in_b, in_mid):
+        """ links module to inputs and outputs
+        """
+        self.mod.setup(m, in_a, in_b)
+        m.d.comb += self.out_a.copy(self.mod.out_a)
+        m.d.comb += self.out_b.copy(self.mod.out_b)
+
+        self.a0mod.setup(m, self.out_a, self.out_b)
+        m.d.comb += self.a0_out_z.copy(self.a0mod.out_z)
+        m.d.comb += self.out_tot.eq(self.a0mod.out_tot)
+
+        self.a1mod.setup(m, self.out_tot, self.a0_out_z)
+
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
+
+    def action(self, m):
+        self.idsync(m)
+        m.d.sync += self.out_of.copy(self.a1mod.out_of)
+        m.d.sync += self.out_z.copy(self.a1mod.out_z)
+        m.next = "normalise_1"
+
+
 class FPAddStage0Mod:
 
     def __init__(self, width):
 class FPAddStage0Mod:
 
     def __init__(self, width):
@@ -437,6 +609,13 @@ class FPAddStage0Mod:
         self.out_z = FPNumBase(width, False)
         self.out_tot = Signal(self.out_z.m_width + 4, reset_less=True)
 
         self.out_z = FPNumBase(width, False)
         self.out_tot = Signal(self.out_z.m_width + 4, reset_less=True)
 
+    def setup(self, m, in_a, in_b):
+        """ links module to inputs and outputs
+        """
+        m.submodules.add0 = self
+        m.d.comb += self.in_a.copy(in_a)
+        m.d.comb += self.in_b.copy(in_b)
+
     def elaborate(self, platform):
         m = Module()
         m.submodules.add0_in_a = self.in_a
     def elaborate(self, platform):
         m = Module()
         m.submodules.add0_in_a = self.in_a
@@ -476,31 +655,32 @@ class FPAddStage0Mod:
         return m
 
 
         return m
 
 
-class FPAddStage0(FPState):
+class FPAddStage0(FPState, FPID):
     """ First stage of add.  covers same-sign (add) and subtract
         special-casing when mantissas are greater or equal, to
         give greatest accuracy.
     """
 
     """ First stage of add.  covers same-sign (add) and subtract
         special-casing when mantissas are greater or equal, to
         give greatest accuracy.
     """
 
-    def __init__(self, width):
+    def __init__(self, width, id_wid):
         FPState.__init__(self, "add_0")
         FPState.__init__(self, "add_0")
+        FPID.__init__(self, id_wid)
         self.mod = FPAddStage0Mod(width)
         self.out_z = FPNumBase(width, False)
         self.out_tot = Signal(self.out_z.m_width + 4, reset_less=True)
 
         self.mod = FPAddStage0Mod(width)
         self.out_z = FPNumBase(width, False)
         self.out_tot = Signal(self.out_z.m_width + 4, reset_less=True)
 
-    def setup(self, m, in_a, in_b):
+    def setup(self, m, in_a, in_b, in_mid):
         """ links module to inputs and outputs
         """
         """ links module to inputs and outputs
         """
-        m.submodules.add0 = self.mod
-
-        m.d.comb += self.mod.in_a.copy(in_a)
-        m.d.comb += self.mod.in_b.copy(in_b)
+        self.mod.setup(m, in_a, in_b)
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
 
     def action(self, m):
 
     def action(self, m):
-        m.next = "add_1"
+        self.idsync(m)
         # NOTE: these could be done as combinatorial (merge add0+add1)
         m.d.sync += self.out_z.copy(self.mod.out_z)
         m.d.sync += self.out_tot.eq(self.mod.out_tot)
         # NOTE: these could be done as combinatorial (merge add0+add1)
         m.d.sync += self.out_z.copy(self.mod.out_z)
         m.d.sync += self.out_tot.eq(self.mod.out_tot)
+        m.next = "add_1"
 
 
 class FPAddStage1Mod(FPState):
 
 
 class FPAddStage1Mod(FPState):
@@ -515,6 +695,15 @@ class FPAddStage1Mod(FPState):
         self.out_z = FPNumBase(width, False)
         self.out_of = Overflow()
 
         self.out_z = FPNumBase(width, False)
         self.out_of = Overflow()
 
+    def setup(self, m, in_tot, in_z):
+        """ links module to inputs and outputs
+        """
+        m.submodules.add1 = self
+        m.submodules.add1_out_overflow = self.out_of
+
+        m.d.comb += self.in_z.copy(in_z)
+        m.d.comb += self.in_tot.eq(in_tot)
+
     def elaborate(self, platform):
         m = Module()
         #m.submodules.norm1_in_overflow = self.in_of
     def elaborate(self, platform):
         m = Module()
         #m.submodules.norm1_in_overflow = self.in_of
@@ -544,27 +733,28 @@ class FPAddStage1Mod(FPState):
         return m
 
 
         return m
 
 
-class FPAddStage1(FPState):
+class FPAddStage1(FPState, FPID):
 
 
-    def __init__(self, width):
+    def __init__(self, width, id_wid):
         FPState.__init__(self, "add_1")
         FPState.__init__(self, "add_1")
+        FPID.__init__(self, id_wid)
         self.mod = FPAddStage1Mod(width)
         self.out_z = FPNumBase(width, False)
         self.out_of = Overflow()
         self.norm_stb = Signal()
 
         self.mod = FPAddStage1Mod(width)
         self.out_z = FPNumBase(width, False)
         self.out_of = Overflow()
         self.norm_stb = Signal()
 
-    def setup(self, m, in_tot, in_z):
+    def setup(self, m, in_tot, in_z, in_mid):
         """ links module to inputs and outputs
         """
         """ links module to inputs and outputs
         """
-        m.submodules.add1 = self.mod
-
-        m.d.comb += self.mod.in_z.copy(in_z)
-        m.d.comb += self.mod.in_tot.eq(in_tot)
+        self.mod.setup(m, in_tot, in_z)
 
         m.d.sync += self.norm_stb.eq(0) # sets to zero when not in add1 state
 
 
         m.d.sync += self.norm_stb.eq(0) # sets to zero when not in add1 state
 
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
+
     def action(self, m):
     def action(self, m):
-        m.submodules.add1_out_overflow = self.out_of
+        self.idsync(m)
         m.d.sync += self.out_of.copy(self.mod.out_of)
         m.d.sync += self.out_z.copy(self.mod.out_z)
         m.d.sync += self.norm_stb.eq(1)
         m.d.sync += self.out_of.copy(self.mod.out_of)
         m.d.sync += self.out_z.copy(self.mod.out_z)
         m.d.sync += self.norm_stb.eq(1)
@@ -575,15 +765,22 @@ class FPNorm1ModSingle:
 
     def __init__(self, width):
         self.width = width
 
     def __init__(self, width):
         self.width = width
-        self.in_select = Signal(reset_less=True)
         self.out_norm = Signal(reset_less=True)
         self.in_z = FPNumBase(width, False)
         self.in_of = Overflow()
         self.out_norm = Signal(reset_less=True)
         self.in_z = FPNumBase(width, False)
         self.in_of = Overflow()
-        self.temp_z = FPNumBase(width, False)
-        self.temp_of = Overflow()
         self.out_z = FPNumBase(width, False)
         self.out_of = Overflow()
 
         self.out_z = FPNumBase(width, False)
         self.out_of = Overflow()
 
+    def setup(self, m, in_z, in_of, out_z):
+        """ links module to inputs and outputs
+        """
+        m.submodules.normalise_1 = self
+
+        m.d.comb += self.in_z.copy(in_z)
+        m.d.comb += self.in_of.copy(in_of)
+
+        m.d.comb += out_z.copy(self.out_z)
+
     def elaborate(self, platform):
         m = Module()
 
     def elaborate(self, platform):
         m = Module()
 
@@ -593,8 +790,6 @@ class FPNorm1ModSingle:
 
         m.submodules.norm1_out_z = self.out_z
         m.submodules.norm1_out_overflow = self.out_of
 
         m.submodules.norm1_out_z = self.out_z
         m.submodules.norm1_out_overflow = self.out_of
-        m.submodules.norm1_temp_z = self.temp_z
-        m.submodules.norm1_temp_of = self.temp_of
         m.submodules.norm1_in_z = self.in_z
         m.submodules.norm1_in_overflow = self.in_of
 
         m.submodules.norm1_in_z = self.in_z
         m.submodules.norm1_in_overflow = self.in_of
 
@@ -608,13 +803,8 @@ class FPNorm1ModSingle:
         msr = MultiShiftRMerge(mwid, espec)
         m.submodules.multishift_r = msr
 
         msr = MultiShiftRMerge(mwid, espec)
         m.submodules.multishift_r = msr
 
-        # select which of temp or in z/of to use
-        with m.If(self.in_select):
-            m.d.comb += in_z.copy(self.in_z)
-            m.d.comb += in_of.copy(self.in_of)
-        with m.Else():
-            m.d.comb += in_z.copy(self.temp_z)
-            m.d.comb += in_of.copy(self.temp_of)
+        m.d.comb += in_z.copy(self.in_z)
+        m.d.comb += in_of.copy(self.in_of)
         # initialise out from in (overridden below)
         m.d.comb += self.out_z.copy(in_z)
         m.d.comb += self.out_of.copy(in_of)
         # initialise out from in (overridden below)
         m.d.comb += self.out_z.copy(in_z)
         m.d.comb += self.out_of.copy(in_of)
@@ -623,7 +813,6 @@ class FPNorm1ModSingle:
         increase = Signal(reset_less=True)
         m.d.comb += decrease.eq(in_z.m_msbzero & in_z.exp_gt_n126)
         m.d.comb += increase.eq(in_z.exp_lt_n126)
         increase = Signal(reset_less=True)
         m.d.comb += decrease.eq(in_z.m_msbzero & in_z.exp_gt_n126)
         m.d.comb += increase.eq(in_z.exp_lt_n126)
-        m.d.comb += self.out_norm.eq(0) # loop-end condition
         # decrease exponent
         with m.If(decrease):
             # *sigh* not entirely obvious: count leading zeros (clz)
         # decrease exponent
         with m.If(decrease):
             # *sigh* not entirely obvious: count leading zeros (clz)
@@ -739,14 +928,36 @@ class FPNorm1ModMulti:
         return m
 
 
         return m
 
 
-class FPNorm1(FPState):
+class FPNorm1Single(FPState, FPID):
 
 
-    def __init__(self, width, single_cycle=True):
+    def __init__(self, width, id_wid, single_cycle=True):
+        FPID.__init__(self, id_wid)
         FPState.__init__(self, "normalise_1")
         FPState.__init__(self, "normalise_1")
-        if single_cycle:
-            self.mod = FPNorm1ModSingle(width)
-        else:
-            self.mod = FPNorm1ModMulti(width)
+        self.mod = FPNorm1ModSingle(width)
+        self.out_norm = Signal(reset_less=True)
+        self.out_z = FPNumBase(width)
+        self.out_roundz = Signal(reset_less=True)
+
+    def setup(self, m, in_z, in_of, in_mid):
+        """ links module to inputs and outputs
+        """
+        self.mod.setup(m, in_z, in_of, self.out_z)
+
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
+
+    def action(self, m):
+        self.idsync(m)
+        m.d.sync += self.out_roundz.eq(self.mod.out_of.roundz)
+        m.next = "round"
+
+
+class FPNorm1Multi(FPState, FPID):
+
+    def __init__(self, width, id_wid):
+        FPID.__init__(self, id_wid)
+        FPState.__init__(self, "normalise_1")
+        self.mod = FPNorm1ModMulti(width)
         self.stb = Signal(reset_less=True)
         self.ack = Signal(reset=0, reset_less=True)
         self.out_norm = Signal(reset_less=True)
         self.stb = Signal(reset_less=True)
         self.ack = Signal(reset=0, reset_less=True)
         self.out_norm = Signal(reset_less=True)
@@ -756,26 +967,21 @@ class FPNorm1(FPState):
         self.out_z = FPNumBase(width)
         self.out_roundz = Signal(reset_less=True)
 
         self.out_z = FPNumBase(width)
         self.out_roundz = Signal(reset_less=True)
 
-    def setup(self, m, in_z, in_of, norm_stb):
+    def setup(self, m, in_z, in_of, norm_stb, in_mid):
         """ links module to inputs and outputs
         """
         """ links module to inputs and outputs
         """
-        m.submodules.normalise_1 = self.mod
-
-        m.d.comb += self.mod.in_z.copy(in_z)
-        m.d.comb += self.mod.in_of.copy(in_of)
-
-        m.d.comb += self.mod.in_select.eq(self.in_accept)
-        m.d.comb += self.mod.temp_z.copy(self.temp_z)
-        m.d.comb += self.mod.temp_of.copy(self.temp_of)
-
-        m.d.comb += self.out_z.copy(self.mod.out_z)
-        m.d.comb += self.out_norm.eq(self.mod.out_norm)
+        self.mod.setup(m, in_z, in_of, norm_stb,
+                       self.in_accept, self.temp_z, self.temp_of,
+                       self.out_z, self.out_norm)
 
         m.d.comb += self.stb.eq(norm_stb)
         m.d.sync += self.ack.eq(0) # sets to zero when not in normalise_1 state
 
 
         m.d.comb += self.stb.eq(norm_stb)
         m.d.sync += self.ack.eq(0) # sets to zero when not in normalise_1 state
 
-    def action(self, m):
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
 
 
+    def action(self, m):
+        self.idsync(m)
         m.d.comb += self.in_accept.eq((~self.ack) & (self.stb))
         m.d.sync += self.temp_of.copy(self.mod.out_of)
         m.d.sync += self.temp_z.copy(self.out_z)
         m.d.comb += self.in_accept.eq((~self.ack) & (self.stb))
         m.d.sync += self.temp_of.copy(self.mod.out_of)
         m.d.sync += self.temp_z.copy(self.out_z)
@@ -793,6 +999,51 @@ class FPNorm1(FPState):
             m.d.sync += self.out_roundz.eq(self.mod.out_of.roundz)
 
 
             m.d.sync += self.out_roundz.eq(self.mod.out_of.roundz)
 
 
+class FPNormToPack(FPState, FPID):
+
+    def __init__(self, width, id_wid):
+        FPID.__init__(self, id_wid)
+        FPState.__init__(self, "normalise_1")
+        self.width = width
+
+    def setup(self, m, in_z, in_of, in_mid):
+        """ links module to inputs and outputs
+        """
+
+        # Normalisation (chained to input in_z+in_of)
+        nmod = FPNorm1ModSingle(self.width)
+        n_out_z = FPNumBase(self.width)
+        n_out_roundz = Signal(reset_less=True)
+        nmod.setup(m, in_z, in_of, n_out_z)
+
+        # Rounding (chained to normalisation)
+        rmod = FPRoundMod(self.width)
+        r_out_z = FPNumBase(self.width)
+        rmod.setup(m, n_out_z, n_out_roundz)
+        m.d.comb += n_out_roundz.eq(nmod.out_of.roundz)
+        m.d.comb += r_out_z.copy(rmod.out_z)
+
+        # Corrections (chained to rounding)
+        cmod = FPCorrectionsMod(self.width)
+        c_out_z = FPNumBase(self.width)
+        cmod.setup(m, r_out_z)
+        m.d.comb += c_out_z.copy(cmod.out_z)
+
+        # Pack (chained to corrections)
+        self.pmod = FPPackMod(self.width)
+        self.out_z = FPNumBase(self.width)
+        self.pmod.setup(m, c_out_z)
+
+        # Multiplex ID
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
+
+    def action(self, m):
+        self.idsync(m) # copies incoming ID to outgoing
+        m.d.sync += self.out_z.v.eq(self.pmod.out_z.v) # outputs packed result
+        m.next = "pack_put_z"
+
+
 class FPRoundMod:
 
     def __init__(self, width):
 class FPRoundMod:
 
     def __init__(self, width):
@@ -800,6 +1051,12 @@ class FPRoundMod:
         self.in_z = FPNumBase(width, False)
         self.out_z = FPNumBase(width, False)
 
         self.in_z = FPNumBase(width, False)
         self.out_z = FPNumBase(width, False)
 
+    def setup(self, m, in_z, roundz):
+        m.submodules.roundz = self
+
+        m.d.comb += self.in_z.copy(in_z)
+        m.d.comb += self.in_roundz.eq(roundz)
+
     def elaborate(self, platform):
         m = Module()
         m.d.comb += self.out_z.copy(self.in_z)
     def elaborate(self, platform):
         m = Module()
         m.d.comb += self.out_z.copy(self.in_z)
@@ -810,22 +1067,24 @@ class FPRoundMod:
         return m
 
 
         return m
 
 
-class FPRound(FPState):
+class FPRound(FPState, FPID):
 
 
-    def __init__(self, width):
+    def __init__(self, width, id_wid):
         FPState.__init__(self, "round")
         FPState.__init__(self, "round")
+        FPID.__init__(self, id_wid)
         self.mod = FPRoundMod(width)
         self.out_z = FPNumBase(width)
 
         self.mod = FPRoundMod(width)
         self.out_z = FPNumBase(width)
 
-    def setup(self, m, in_z, roundz):
+    def setup(self, m, in_z, roundz, in_mid):
         """ links module to inputs and outputs
         """
         """ links module to inputs and outputs
         """
-        m.submodules.roundz = self.mod
+        self.mod.setup(m, in_z, roundz)
 
 
-        m.d.comb += self.mod.in_z.copy(in_z)
-        m.d.comb += self.mod.in_roundz.eq(roundz)
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
 
     def action(self, m):
 
     def action(self, m):
+        self.idsync(m)
         m.d.sync += self.out_z.copy(self.mod.out_z)
         m.next = "corrections"
 
         m.d.sync += self.out_z.copy(self.mod.out_z)
         m.next = "corrections"
 
@@ -836,6 +1095,12 @@ class FPCorrectionsMod:
         self.in_z = FPNumOut(width, False)
         self.out_z = FPNumOut(width, False)
 
         self.in_z = FPNumOut(width, False)
         self.out_z = FPNumOut(width, False)
 
+    def setup(self, m, in_z):
+        """ links module to inputs and outputs
+        """
+        m.submodules.corrections = self
+        m.d.comb += self.in_z.copy(in_z)
+
     def elaborate(self, platform):
         m = Module()
         m.submodules.corr_in_z = self.in_z
     def elaborate(self, platform):
         m = Module()
         m.submodules.corr_in_z = self.in_z
@@ -843,28 +1108,26 @@ class FPCorrectionsMod:
         m.d.comb += self.out_z.copy(self.in_z)
         with m.If(self.in_z.is_denormalised):
             m.d.comb += self.out_z.e.eq(self.in_z.N127)
         m.d.comb += self.out_z.copy(self.in_z)
         with m.If(self.in_z.is_denormalised):
             m.d.comb += self.out_z.e.eq(self.in_z.N127)
-
-        #        with m.If(self.in_z.is_overflowed):
-        #            m.d.comb += self.out_z.inf(self.in_z.s)
-        #        with m.Else():
-        #            m.d.comb += self.out_z.create(self.in_z.s, self.in_z.e, self.in_z.m)
         return m
 
 
         return m
 
 
-class FPCorrections(FPState):
+class FPCorrections(FPState, FPID):
 
 
-    def __init__(self, width):
+    def __init__(self, width, id_wid):
         FPState.__init__(self, "corrections")
         FPState.__init__(self, "corrections")
+        FPID.__init__(self, id_wid)
         self.mod = FPCorrectionsMod(width)
         self.out_z = FPNumBase(width)
 
         self.mod = FPCorrectionsMod(width)
         self.out_z = FPNumBase(width)
 
-    def setup(self, m, in_z):
+    def setup(self, m, in_z, in_mid):
         """ links module to inputs and outputs
         """
         """ links module to inputs and outputs
         """
-        m.submodules.corrections = self.mod
-        m.d.comb += self.mod.in_z.copy(in_z)
+        self.mod.setup(m, in_z)
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
 
     def action(self, m):
 
     def action(self, m):
+        self.idsync(m)
         m.d.sync += self.out_z.copy(self.mod.out_z)
         m.next = "pack"
 
         m.d.sync += self.out_z.copy(self.mod.out_z)
         m.next = "pack"
 
@@ -875,6 +1138,12 @@ class FPPackMod:
         self.in_z = FPNumOut(width, False)
         self.out_z = FPNumOut(width, False)
 
         self.in_z = FPNumOut(width, False)
         self.out_z = FPNumOut(width, False)
 
+    def setup(self, m, in_z):
+        """ links module to inputs and outputs
+        """
+        m.submodules.pack = self
+        m.d.comb += self.in_z.copy(in_z)
+
     def elaborate(self, platform):
         m = Module()
         m.submodules.pack_in_z = self.in_z
     def elaborate(self, platform):
         m = Module()
         m.submodules.pack_in_z = self.in_z
@@ -885,50 +1154,67 @@ class FPPackMod:
         return m
 
 
         return m
 
 
-class FPPack(FPState):
+class FPPack(FPState, FPID):
 
 
-    def __init__(self, width):
+    def __init__(self, width, id_wid):
         FPState.__init__(self, "pack")
         FPState.__init__(self, "pack")
+        FPID.__init__(self, id_wid)
         self.mod = FPPackMod(width)
         self.out_z = FPNumOut(width, False)
 
         self.mod = FPPackMod(width)
         self.out_z = FPNumOut(width, False)
 
-    def setup(self, m, in_z):
+    def setup(self, m, in_z, in_mid):
         """ links module to inputs and outputs
         """
         """ links module to inputs and outputs
         """
-        m.submodules.pack = self.mod
-        m.d.comb += self.mod.in_z.copy(in_z)
+        self.mod.setup(m, in_z)
+        if self.in_mid is not None:
+            m.d.comb += self.in_mid.eq(in_mid)
 
     def action(self, m):
 
     def action(self, m):
+        self.idsync(m)
         m.d.sync += self.out_z.v.eq(self.mod.out_z.v)
         m.next = "pack_put_z"
 
 
 class FPPutZ(FPState):
 
         m.d.sync += self.out_z.v.eq(self.mod.out_z.v)
         m.next = "pack_put_z"
 
 
 class FPPutZ(FPState):
 
-    def __init__(self, state, in_z, out_z):
+    def __init__(self, state, in_z, out_z, in_mid, out_mid):
         FPState.__init__(self, state)
         self.in_z = in_z
         self.out_z = out_z
         FPState.__init__(self, state)
         self.in_z = in_z
         self.out_z = out_z
+        self.in_mid = in_mid
+        self.out_mid = out_mid
 
     def action(self, m):
 
     def action(self, m):
+        if self.in_mid is not None:
+            m.d.sync += self.out_mid.eq(self.in_mid)
         m.d.sync += [
           self.out_z.v.eq(self.in_z.v)
         ]
         with m.If(self.out_z.stb & self.out_z.ack):
             m.d.sync += self.out_z.stb.eq(0)
         m.d.sync += [
           self.out_z.v.eq(self.in_z.v)
         ]
         with m.If(self.out_z.stb & self.out_z.ack):
             m.d.sync += self.out_z.stb.eq(0)
-            m.next = "get_a"
+            m.next = "get_ops"
         with m.Else():
             m.d.sync += self.out_z.stb.eq(1)
 
 
         with m.Else():
             m.d.sync += self.out_z.stb.eq(1)
 
 
-class FPADD:
+class FPADDBaseMod(FPID):
 
 
-    def __init__(self, width, single_cycle=False):
+    def __init__(self, width, id_wid=None, single_cycle=False, compact=True):
+        """ IEEE754 FP Add
+
+            * width: bit-width of IEEE754.  supported: 16, 32, 64
+            * id_wid: an identifier that is sync-connected to the input
+            * single_cycle: True indicates each stage to complete in 1 clock
+            * compact: True indicates a reduced number of stages
+        """
+        FPID.__init__(self, id_wid)
         self.width = width
         self.single_cycle = single_cycle
         self.width = width
         self.single_cycle = single_cycle
+        self.compact = compact
 
 
-        self.in_a  = FPOp(width)
-        self.in_b  = FPOp(width)
+        self.in_t = Trigger()
+        self.in_a  = Signal(width)
+        self.in_b  = Signal(width)
         self.out_z = FPOp(width)
 
         self.states = []
         self.out_z = FPOp(width)
 
         self.states = []
@@ -941,56 +1227,249 @@ class FPADD:
         """ creates the HDL code-fragment for FPAdd
         """
         m = Module()
         """ creates the HDL code-fragment for FPAdd
         """
         m = Module()
-        m.submodules.in_a = self.in_a
-        m.submodules.in_b = self.in_b
         m.submodules.out_z = self.out_z
         m.submodules.out_z = self.out_z
+        m.submodules.in_t = self.in_t
+        if self.compact:
+            self.get_compact_fragment(m, platform)
+        else:
+            self.get_longer_fragment(m, platform)
 
 
-        geta = self.add_state(FPGetOp("get_a", "get_b",
-                                      self.in_a, self.width))
-        geta.setup(m, self.in_a)
-        a = geta.out_op
+        with m.FSM() as fsm:
 
 
-        getb = self.add_state(FPGetOp("get_b", "special_cases",
-                                      self.in_b, self.width))
-        getb.setup(m, self.in_b)
-        b = getb.out_op
+            for state in self.states:
+                with m.State(state.state_from):
+                    state.action(m)
+
+        return m
+
+    def get_longer_fragment(self, m, platform=None):
+
+        get = self.add_state(FPGet2Op("get_ops", "special_cases",
+                                      self.in_a, self.in_b, self.width))
+        get.setup(m, self.in_a, self.in_b, self.in_t.stb, self.in_t.ack)
+        a = get.out_op1
+        b = get.out_op2
 
 
-        sc = self.add_state(FPAddSpecialCases(self.width))
-        sc.mod.setup(m, a, b, sc.out_z, sc.out_do_z)
-        m.submodules.specialcases = sc.mod
+        sc = self.add_state(FPAddSpecialCases(self.width, self.id_wid))
+        sc.setup(m, a, b, self.in_mid)
 
 
-        dn = self.add_state(FPAddDeNorm(self.width))
-        dn.setup(m, a, b)
+        dn = self.add_state(FPAddDeNorm(self.width, self.id_wid))
+        dn.setup(m, a, b, sc.in_mid)
 
         if self.single_cycle:
 
         if self.single_cycle:
-            alm = self.add_state(FPAddAlignSingle(self.width))
-            alm.setup(m, dn.out_a, dn.out_b)
+            alm = self.add_state(FPAddAlignSingle(self.width, self.id_wid))
+            alm.setup(m, dn.out_a, dn.out_b, dn.in_mid)
         else:
         else:
-            alm = self.add_state(FPAddAlignMulti(self.width))
-            #alm.set_inputs({"a": a, "b": b})
-            alm.setup(m, dn.out_a, dn.out_b)
+            alm = self.add_state(FPAddAlignMulti(self.width, self.id_wid))
+            alm.setup(m, dn.out_a, dn.out_b, dn.in_mid)
+
+        add0 = self.add_state(FPAddStage0(self.width, self.id_wid))
+        add0.setup(m, alm.out_a, alm.out_b, alm.in_mid)
+
+        add1 = self.add_state(FPAddStage1(self.width, self.id_wid))
+        add1.setup(m, add0.out_tot, add0.out_z, add0.in_mid)
+
+        if self.single_cycle:
+            n1 = self.add_state(FPNorm1Single(self.width, self.id_wid))
+            n1.setup(m, add1.out_z, add1.out_of, add0.in_mid)
+        else:
+            n1 = self.add_state(FPNorm1Multi(self.width, self.id_wid))
+            n1.setup(m, add1.out_z, add1.out_of, add1.norm_stb, add0.in_mid)
+
+        rn = self.add_state(FPRound(self.width, self.id_wid))
+        rn.setup(m, n1.out_z, n1.out_roundz, n1.in_mid)
+
+        cor = self.add_state(FPCorrections(self.width, self.id_wid))
+        cor.setup(m, rn.out_z, rn.in_mid)
+
+        pa = self.add_state(FPPack(self.width, self.id_wid))
+        pa.setup(m, cor.out_z, rn.in_mid)
+
+        ppz = self.add_state(FPPutZ("pack_put_z", pa.out_z, self.out_z,
+                                    pa.in_mid, self.out_mid))
 
 
-        add0 = self.add_state(FPAddStage0(self.width))
-        add0.setup(m, alm.out_a, alm.out_b)
+        pz = self.add_state(FPPutZ("put_z", sc.out_z, self.out_z,
+                                    pa.in_mid, self.out_mid))
 
 
-        add1 = self.add_state(FPAddStage1(self.width))
-        add1.setup(m, add0.out_tot, add0.out_z)
+    def get_compact_fragment(self, m, platform=None):
 
 
-        n1 = self.add_state(FPNorm1(self.width))
-        n1.setup(m, add1.out_z, add1.out_of, add1.norm_stb)
+        get = self.add_state(FPGet2Op("get_ops", "special_cases",
+                                      self.in_a, self.in_b, self.width))
+        get.setup(m, self.in_a, self.in_b, self.in_t.stb, self.in_t.ack)
+        a = get.out_op1
+        b = get.out_op2
 
 
-        rn = self.add_state(FPRound(self.width))
-        rn.setup(m, n1.out_z, n1.out_roundz)
+        sc = self.add_state(FPAddSpecialCasesDeNorm(self.width, self.id_wid))
+        sc.setup(m, a, b, self.in_mid)
 
 
-        cor = self.add_state(FPCorrections(self.width))
-        cor.setup(m, rn.out_z)
+        alm = self.add_state(FPAddAlignSingleAdd(self.width, self.id_wid))
+        alm.setup(m, sc.out_a, sc.out_b, sc.in_mid)
 
 
-        pa = self.add_state(FPPack(self.width))
-        pa.setup(m, cor.out_z)
+        n1 = self.add_state(FPNormToPack(self.width, self.id_wid))
+        n1.setup(m, alm.out_z, alm.out_of, alm.in_mid)
+
+        ppz = self.add_state(FPPutZ("pack_put_z", n1.out_z, self.out_z,
+                                    n1.in_mid, self.out_mid))
+
+        pz = self.add_state(FPPutZ("put_z", sc.out_z, self.out_z,
+                                    sc.in_mid, self.out_mid))
+
+
+class FPADDBase(FPState, FPID):
+
+    def __init__(self, width, id_wid=None, single_cycle=False):
+        """ IEEE754 FP Add
+
+            * width: bit-width of IEEE754.  supported: 16, 32, 64
+            * id_wid: an identifier that is sync-connected to the input
+            * single_cycle: True indicates each stage to complete in 1 clock
+        """
+        FPID.__init__(self, id_wid)
+        FPState.__init__(self, "fpadd")
+        self.width = width
+        self.single_cycle = single_cycle
+        self.mod = FPADDBaseMod(width, id_wid, single_cycle)
+
+        self.in_t = Trigger()
+        self.in_a  = Signal(width)
+        self.in_b  = Signal(width)
+        #self.out_z = FPOp(width)
+
+        self.z_done = Signal(reset_less=True) # connects to out_z Strobe
+        self.in_accept = Signal(reset_less=True)
+        self.add_stb = Signal(reset_less=True)
+        self.add_ack = Signal(reset=0, reset_less=True)
+
+    def setup(self, m, a, b, add_stb, in_mid, out_z, out_mid):
+        self.out_z = out_z
+        self.out_mid = out_mid
+        m.d.comb += [self.in_a.eq(a),
+                     self.in_b.eq(b),
+                     self.mod.in_a.eq(self.in_a),
+                     self.mod.in_b.eq(self.in_b),
+                     self.in_mid.eq(in_mid),
+                     self.mod.in_mid.eq(self.in_mid),
+                     self.z_done.eq(self.mod.out_z.trigger),
+                     #self.add_stb.eq(add_stb),
+                     self.mod.in_t.stb.eq(self.in_t.stb),
+                     self.in_t.ack.eq(self.mod.in_t.ack),
+                     self.out_mid.eq(self.mod.out_mid),
+                     self.out_z.v.eq(self.mod.out_z.v),
+                     self.out_z.stb.eq(self.mod.out_z.stb),
+                     self.mod.out_z.ack.eq(self.out_z.ack),
+                    ]
+
+        m.d.sync += self.add_stb.eq(add_stb)
+        m.d.sync += self.add_ack.eq(0) # sets to zero when not in active state
+        #m.d.sync += self.in_t.stb.eq(0)
+
+        m.submodules.fpadd = self.mod
+
+    def action(self, m):
+
+        # in_accept is set on incoming strobe HIGH and ack LOW.
+        m.d.comb += self.in_accept.eq((~self.add_ack) & (self.add_stb))
+
+        #with m.If(self.in_t.ack):
+        #    m.d.sync += self.in_t.stb.eq(0)
+        with m.If(~self.z_done):
+            # not done: test for accepting an incoming operand pair
+            with m.If(self.in_accept):
+                m.d.sync += [
+                    self.add_ack.eq(1), # acknowledge receipt...
+                    self.in_t.stb.eq(1), # initiate add
+                ]
+            with m.Else():
+                m.d.sync += [self.add_ack.eq(0),
+                             self.in_t.stb.eq(0),
+                            ]
+        with m.Else():
+            # done: acknowledge, and write out id and value
+            m.d.sync += [self.add_ack.eq(1),
+                         self.in_t.stb.eq(0)
+                        ]
+            m.next = "get_a"
+
+            return
+
+            if self.in_mid is not None:
+                m.d.sync += self.out_mid.eq(self.mod.out_mid)
+
+            m.d.sync += [
+              self.out_z.v.eq(self.mod.out_z.v)
+            ]
+            # move to output state on detecting z ack
+            with m.If(self.out_z.trigger):
+                m.d.sync += self.out_z.stb.eq(0)
+                m.next = "put_z"
+            with m.Else():
+                m.d.sync += self.out_z.stb.eq(1)
+
+
+class FPADD(FPID):
+    """ FPADD: stages as follows:
+
+        FPGetOp (a)
+           |
+        FPGetOp (b)
+           |
+        FPAddBase---> FPAddBaseMod
+           |            |
+        PutZ          GetOps->Specials->Align->Add1/2->Norm->Round/Pack->PutZ
+
+        FPAddBase is tricky: it is both a stage and *has* stages.
+        Connection to FPAddBaseMod therefore requires an in stb/ack
+        and an out stb/ack.  Just as with Add1-Norm1 interaction, FPGetOp
+        needs to be the thing that raises the incoming stb.
+    """
+
+    def __init__(self, width, id_wid=None, single_cycle=False):
+        """ IEEE754 FP Add
+
+            * width: bit-width of IEEE754.  supported: 16, 32, 64
+            * id_wid: an identifier that is sync-connected to the input
+            * single_cycle: True indicates each stage to complete in 1 clock
+        """
+        self.width = width
+        self.id_wid = id_wid
+        self.single_cycle = single_cycle
+
+        self.ids = FPID(id_wid)
+        self.in_a  = FPOp(width)
+        self.in_b  = FPOp(width)
+        self.out_z = FPOp(width)
+
+        self.states = []
+
+    def add_state(self, state):
+        self.states.append(state)
+        return state
+
+    def get_fragment(self, platform=None):
+        """ creates the HDL code-fragment for FPAdd
+        """
+        m = Module()
+        m.submodules.in_a = self.in_a
+        m.submodules.in_b = self.in_b
+        m.submodules.out_z = self.out_z
+
+        geta = self.add_state(FPGetOp("get_a", "get_b",
+                                      self.in_a, self.width))
+        geta.setup(m, self.in_a)
+        a = geta.out_op
+
+        getb = self.add_state(FPGetOp("get_b", "fpadd",
+                                      self.in_b, self.width))
+        getb.setup(m, self.in_b)
+        b = getb.out_op
 
 
-        ppz = self.add_state(FPPutZ("pack_put_z", pa.out_z, self.out_z))
+        ab = FPADDBase(self.width, self.id_wid, self.single_cycle)
+        ab = self.add_state(ab)
+        ab.setup(m, a, b, getb.out_decode, self.ids.in_mid,
+                 self.out_z, self.ids.out_mid)
 
 
-        pz = self.add_state(FPPutZ("put_z", sc.out_z, self.out_z))
+        #pz = self.add_state(FPPutZ("put_z", ab.out_z, self.out_z,
+        #                            ab.out_mid, self.out_mid))
 
         with m.FSM() as fsm:
 
 
         with m.FSM() as fsm:
 
@@ -1002,8 +1481,18 @@ class FPADD:
 
 
 if __name__ == "__main__":
 
 
 if __name__ == "__main__":
-    alu = FPADD(width=32, single_cycle=True)
-    main(alu, ports=alu.in_a.ports() + alu.in_b.ports() + alu.out_z.ports())
+    if True:
+        alu = FPADD(width=32, id_wid=5, single_cycle=True)
+        main(alu, ports=alu.in_a.ports() + \
+                        alu.in_b.ports() + \
+                        alu.out_z.ports() + \
+                        [alu.in_mid, alu.out_mid])
+    else:
+        alu = FPADDBase(width=32, id_wid=5, single_cycle=True)
+        main(alu, ports=[alu.in_a, alu.in_b] + \
+                        alu.in_t.ports() + \
+                        alu.out_z.ports() + \
+                        [alu.in_mid, alu.out_mid])
 
 
     # works... but don't use, just do "python fname.py convert -t v"
 
 
     # works... but don't use, just do "python fname.py convert -t v"