use ospec in FPAddAlignSingleAdd
[ieee754fpu.git] / src / add / nmigen_add_experiment.py
index 3ce1988d427bc5d97e244b56ecb8418230029434..e3e904bc05c61156775973b33c677fed9ae14313 100644 (file)
@@ -5,6 +5,7 @@
 from nmigen import Module, Signal, Cat, Mux, Array, Const
 from nmigen.lib.coding import PriorityEncoder
 from nmigen.cli import main, verilog
 from nmigen import Module, Signal, Cat, Mux, Array, Const
 from nmigen.lib.coding import PriorityEncoder
 from nmigen.cli import main, verilog
+from math import log
 
 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPNumBase
 from fpbase import MultiShiftRMerge, Trigger
 
 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPNumBase
 from fpbase import MultiShiftRMerge, Trigger
@@ -57,35 +58,82 @@ class FPGetSyncOpsMod:
         return self.in_op + self.out_op + [self.stb, self.ack]
 
 
         return self.in_op + self.out_op + [self.stb, self.ack]
 
 
-class InputGroup(Trigger):
-    def __init__(self, width, num_ops=2, num_rows=4):
+class FPOps(Trigger):
+    def __init__(self, width, num_ops):
         Trigger.__init__(self)
         self.width = width
         self.num_ops = num_ops
         Trigger.__init__(self)
         self.width = width
         self.num_ops = num_ops
+
+        res = []
+        for i in range(num_ops):
+            res.append(Signal(width))
+        self.v  = Array(res)
+
+    def ports(self):
+        res = []
+        for i in range(self.num_ops):
+            res.append(self.v[i])
+        res.append(self.ack)
+        res.append(self.stb)
+        return res
+
+
+class InputGroup:
+    def __init__(self, width, num_ops=2, num_rows=4):
+        self.width = width
+        self.num_ops = num_ops
         self.num_rows = num_rows
         self.num_rows = num_rows
+        self.mmax = int(log(self.num_rows) / log(2))
         self.rs = []
         self.rs = []
+        self.mid = Signal(self.mmax, reset_less=True) # multiplex id
         for i in range(num_rows):
             self.rs.append(FPGetSyncOpsMod(width, num_ops))
         for i in range(num_rows):
             self.rs.append(FPGetSyncOpsMod(width, num_ops))
+        self.rs = Array(self.rs)
 
 
-        outops = []
-        for i in range(num_ops):
-            outops.append(Signal(width, reset_less=True))
-        self.out_op = outops
+        self.out_op = FPOps(width, num_ops)
 
     def elaborate(self, platform):
 
     def elaborate(self, platform):
-        m = Trigger.elaborate(platform)
+        m = Module()
+
         pe = PriorityEncoder(self.num_rows)
         m.submodules.selector = pe
         pe = PriorityEncoder(self.num_rows)
         m.submodules.selector = pe
+        m.submodules.out_op = self.out_op
+        m.submodules += self.rs
 
         # connect priority encoder
         in_ready = []
         for i in range(self.num_rows):
             in_ready.append(self.rs[i].ready)
 
         # connect priority encoder
         in_ready = []
         for i in range(self.num_rows):
             in_ready.append(self.rs[i].ready)
-        m.d.comb += self.pe.i.eq(Cat(*in_ready))
-        m.d.comb += self.stb.eq(pe.n) # strobe-out valid when encoder is active
+        m.d.comb += pe.i.eq(Cat(*in_ready))
+
+        active = Signal(reset_less=True)
+        out_en = Signal(reset_less=True)
+        m.d.comb += active.eq(~pe.n) # encoder active
+        m.d.comb += out_en.eq(active & self.out_op.trigger)
+
+        # encoder active: ack relevant input, record MID, pass output
+        with m.If(out_en):
+            rs = self.rs[pe.o]
+            m.d.sync += self.mid.eq(pe.o)
+            m.d.sync += rs.ack.eq(0)
+            m.d.sync += self.out_op.stb.eq(0)
+            for j in range(self.num_ops):
+                m.d.sync += self.out_op.v[j].eq(rs.out_op[j])
+        with m.Else():
+            m.d.sync += self.out_op.stb.eq(1)
+            # acks all default to zero
+            for i in range(self.num_rows):
+                m.d.sync += self.rs[i].ack.eq(1)
 
         return m
 
 
         return m
 
+    def ports(self):
+        res = []
+        for i in range(self.num_rows):
+            inop = self.rs[i]
+            res += inop.in_op + [inop.stb]
+        return self.out_op.ports() + res + [self.mid]
+
 
 class FPGetOpMod:
     def __init__(self, width):
 
 class FPGetOpMod:
     def __init__(self, width):
@@ -121,7 +169,7 @@ class FPGetOp(FPState):
         """ links module to inputs and outputs
         """
         setattr(m.submodules, self.state_from, self.mod)
         """ links module to inputs and outputs
         """
         setattr(m.submodules, self.state_from, self.mod)
-        m.d.comb += self.mod.in_op.copy(in_op)
+        m.d.comb += self.mod.in_op.eq(in_op)
         #m.d.comb += self.out_op.eq(self.mod.out_op)
         m.d.comb += self.out_decode.eq(self.mod.out_decode)
 
         #m.d.comb += self.out_op.eq(self.mod.out_op)
         m.d.comb += self.out_decode.eq(self.mod.out_decode)
 
@@ -191,12 +239,21 @@ class FPGet2Op(FPState):
                 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.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)
+                self.out_op1.eq(self.mod.out_op1),
+                self.out_op2.eq(self.mod.out_op2)
             ]
         with m.Else():
             m.d.sync += self.mod.ack.eq(1)
 
             ]
         with m.Else():
             m.d.sync += self.mod.ack.eq(1)
 
+class FPNumBase2Ops:
+
+    def __init__(self, width, m_extra=True):
+        self.a = FPNumBase(width, m_extra)
+        self.b = FPNumBase(width, m_extra)
+
+    def eq(self, i):
+        return [self.a.eq(i.a), self.b.eq(i.b)]
+
 
 class FPAddSpecialCasesMod:
     """ special cases: NaNs, infs, zeros, denormalised
 
 class FPAddSpecialCasesMod:
     """ special cases: NaNs, infs, zeros, denormalised
@@ -205,34 +262,40 @@ class FPAddSpecialCasesMod:
     """
 
     def __init__(self, width):
     """
 
     def __init__(self, width):
-        self.in_a = FPNumBase(width)
-        self.in_b = FPNumBase(width)
-        self.out_z = FPNumOut(width, False)
+        self.width = width
+        self.i = self.ispec()
+        self.out_z = self.ospec()
         self.out_do_z = Signal(reset_less=True)
 
         self.out_do_z = Signal(reset_less=True)
 
+    def ispec(self):
+        return FPNumBase2Ops(self.width)
+
+    def ospec(self):
+        return FPNumOut(self.width, False)
+
     def setup(self, m, in_a, in_b, out_do_z):
         """ links module to inputs and outputs
         """
         m.submodules.specialcases = self
     def setup(self, m, in_a, in_b, out_do_z):
         """ 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.i.a.eq(in_a)
+        m.d.comb += self.i.b.eq(in_b)
         m.d.comb += out_do_z.eq(self.out_do_z)
 
     def elaborate(self, platform):
         m = Module()
 
         m.d.comb += out_do_z.eq(self.out_do_z)
 
     def elaborate(self, platform):
         m = Module()
 
-        m.submodules.sc_in_a = self.in_a
-        m.submodules.sc_in_b = self.in_b
+        m.submodules.sc_in_a = self.i.a
+        m.submodules.sc_in_b = self.i.b
         m.submodules.sc_out_z = self.out_z
 
         s_nomatch = Signal()
         m.submodules.sc_out_z = self.out_z
 
         s_nomatch = Signal()
-        m.d.comb += s_nomatch.eq(self.in_a.s != self.in_b.s)
+        m.d.comb += s_nomatch.eq(self.i.a.s != self.i.b.s)
 
         m_match = Signal()
 
         m_match = Signal()
-        m.d.comb += m_match.eq(self.in_a.m == self.in_b.m)
+        m.d.comb += m_match.eq(self.i.a.m == self.i.b.m)
 
         # if a is NaN or b is NaN return NaN
 
         # if a is NaN or b is NaN return NaN
-        with m.If(self.in_a.is_nan | self.in_b.is_nan):
+        with m.If(self.i.a.is_nan | self.i.b.is_nan):
             m.d.comb += self.out_do_z.eq(1)
             m.d.comb += self.out_z.nan(0)
 
             m.d.comb += self.out_do_z.eq(1)
             m.d.comb += self.out_z.nan(0)
 
@@ -260,39 +323,39 @@ class FPAddSpecialCasesMod:
         #    m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
 
         # if a is inf return inf (or NaN)
         #    m.d.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(self.in_a.is_inf):
+        with m.Elif(self.i.a.is_inf):
             m.d.comb += self.out_do_z.eq(1)
             m.d.comb += self.out_do_z.eq(1)
-            m.d.comb += self.out_z.inf(self.in_a.s)
+            m.d.comb += self.out_z.inf(self.i.a.s)
             # if a is inf and signs don't match return NaN
             # if a is inf and signs don't match return NaN
-            with m.If(self.in_b.exp_128 & s_nomatch):
+            with m.If(self.i.b.exp_128 & s_nomatch):
                 m.d.comb += self.out_z.nan(0)
 
         # if b is inf return inf
                 m.d.comb += self.out_z.nan(0)
 
         # if b is inf return inf
-        with m.Elif(self.in_b.is_inf):
+        with m.Elif(self.i.b.is_inf):
             m.d.comb += self.out_do_z.eq(1)
             m.d.comb += self.out_do_z.eq(1)
-            m.d.comb += self.out_z.inf(self.in_b.s)
+            m.d.comb += self.out_z.inf(self.i.b.s)
 
         # if a is zero and b zero return signed-a/b
 
         # if a is zero and b zero return signed-a/b
-        with m.Elif(self.in_a.is_zero & self.in_b.is_zero):
+        with m.Elif(self.i.a.is_zero & self.i.b.is_zero):
             m.d.comb += self.out_do_z.eq(1)
             m.d.comb += self.out_do_z.eq(1)
-            m.d.comb += self.out_z.create(self.in_a.s & self.in_b.s,
-                                          self.in_b.e,
-                                          self.in_b.m[3:-1])
+            m.d.comb += self.out_z.create(self.i.a.s & self.i.b.s,
+                                          self.i.b.e,
+                                          self.i.b.m[3:-1])
 
         # if a is zero return b
 
         # if a is zero return b
-        with m.Elif(self.in_a.is_zero):
+        with m.Elif(self.i.a.is_zero):
             m.d.comb += self.out_do_z.eq(1)
             m.d.comb += self.out_do_z.eq(1)
-            m.d.comb += self.out_z.create(self.in_b.s, self.in_b.e,
-                                      self.in_b.m[3:-1])
+            m.d.comb += self.out_z.create(self.i.b.s, self.i.b.e,
+                                      self.i.b.m[3:-1])
 
         # if b is zero return a
 
         # if b is zero return a
-        with m.Elif(self.in_b.is_zero):
+        with m.Elif(self.i.b.is_zero):
             m.d.comb += self.out_do_z.eq(1)
             m.d.comb += self.out_do_z.eq(1)
-            m.d.comb += self.out_z.create(self.in_a.s, self.in_a.e,
-                                      self.in_a.m[3:-1])
+            m.d.comb += self.out_z.create(self.i.a.s, self.i.a.e,
+                                      self.i.a.m[3:-1])
 
         # if a equal to -b return zero (+ve zero)
 
         # if a equal to -b return zero (+ve zero)
-        with m.Elif(s_nomatch & m_match & (self.in_a.e == self.in_b.e)):
+        with m.Elif(s_nomatch & m_match & (self.i.a.e == self.i.b.e)):
             m.d.comb += self.out_do_z.eq(1)
             m.d.comb += self.out_z.zero(0)
 
             m.d.comb += self.out_do_z.eq(1)
             m.d.comb += self.out_z.zero(0)
 
@@ -328,7 +391,7 @@ class FPAddSpecialCases(FPState, FPID):
         FPState.__init__(self, "special_cases")
         FPID.__init__(self, id_wid)
         self.mod = FPAddSpecialCasesMod(width)
         FPState.__init__(self, "special_cases")
         FPID.__init__(self, id_wid)
         self.mod = FPAddSpecialCasesMod(width)
-        self.out_z = FPNumOut(width, False)
+        self.out_z = self.mod.ospec()
         self.out_do_z = Signal(reset_less=True)
 
     def setup(self, m, in_a, in_b, in_mid):
         self.out_do_z = Signal(reset_less=True)
 
     def setup(self, m, in_a, in_b, in_mid):
@@ -357,12 +420,11 @@ class FPAddSpecialCasesDeNorm(FPState, FPID):
         FPState.__init__(self, "special_cases")
         FPID.__init__(self, id_wid)
         self.smod = FPAddSpecialCasesMod(width)
         FPState.__init__(self, "special_cases")
         FPID.__init__(self, id_wid)
         self.smod = FPAddSpecialCasesMod(width)
-        self.out_z = FPNumOut(width, False)
+        self.out_z = self.smod.ospec()
         self.out_do_z = Signal(reset_less=True)
 
         self.dmod = FPAddDeNormMod(width)
         self.out_do_z = Signal(reset_less=True)
 
         self.dmod = FPAddDeNormMod(width)
-        self.out_a = FPNumBase(width)
-        self.out_b = FPNumBase(width)
+        self.o = self.dmod.ospec()
 
     def setup(self, m, in_a, in_b, in_mid):
         """ links module to inputs and outputs
 
     def setup(self, m, in_a, in_b, in_mid):
         """ links module to inputs and outputs
@@ -379,43 +441,48 @@ class FPAddSpecialCasesDeNorm(FPState, FPID):
             m.next = "put_z"
         with m.Else():
             m.next = "align"
             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)
+            m.d.sync += self.o.a.eq(self.dmod.o.a)
+            m.d.sync += self.o.b.eq(self.dmod.o.b)
 
 
 class FPAddDeNormMod(FPState):
 
     def __init__(self, width):
 
 
 class FPAddDeNormMod(FPState):
 
     def __init__(self, width):
-        self.in_a = FPNumBase(width)
-        self.in_b = FPNumBase(width)
-        self.out_a = FPNumBase(width)
-        self.out_b = FPNumBase(width)
+        self.width = width
+        self.i = self.ispec()
+        self.o = self.ospec()
+
+    def ispec(self):
+        return FPNumBase2Ops(self.width)
+
+    def ospec(self):
+        return FPNumBase2Ops(self.width)
 
     def setup(self, m, in_a, in_b):
         """ links module to inputs and outputs
         """
         m.submodules.denormalise = self
 
     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)
+        m.d.comb += self.i.a.eq(in_a)
+        m.d.comb += self.i.b.eq(in_b)
 
     def elaborate(self, platform):
         m = Module()
 
     def elaborate(self, platform):
         m = Module()
-        m.submodules.denorm_in_a = self.in_a
-        m.submodules.denorm_in_b = self.in_b
-        m.submodules.denorm_out_a = self.out_a
-        m.submodules.denorm_out_b = self.out_b
+        m.submodules.denorm_in_a = self.i.a
+        m.submodules.denorm_in_b = self.i.b
+        m.submodules.denorm_out_a = self.o.a
+        m.submodules.denorm_out_b = self.o.b
         # hmmm, don't like repeating identical code
         # hmmm, don't like repeating identical code
-        m.d.comb += self.out_a.copy(self.in_a)
-        with m.If(self.in_a.exp_n127):
-            m.d.comb += self.out_a.e.eq(self.in_a.N126) # limit a exponent
+        m.d.comb += self.o.a.eq(self.i.a)
+        with m.If(self.i.a.exp_n127):
+            m.d.comb += self.o.a.e.eq(self.i.a.N126) # limit a exponent
         with m.Else():
         with m.Else():
-            m.d.comb += self.out_a.m[-1].eq(1) # set top mantissa bit
+            m.d.comb += self.o.a.m[-1].eq(1) # set top mantissa bit
 
 
-        m.d.comb += self.out_b.copy(self.in_b)
-        with m.If(self.in_b.exp_n127):
-            m.d.comb += self.out_b.e.eq(self.in_b.N126) # limit a exponent
+        m.d.comb += self.o.b.eq(self.i.b)
+        with m.If(self.i.b.exp_n127):
+            m.d.comb += self.o.b.e.eq(self.i.b.N126) # limit a exponent
         with m.Else():
         with m.Else():
-            m.d.comb += self.out_b.m[-1].eq(1) # set top mantissa bit
+            m.d.comb += self.o.b.m[-1].eq(1) # set top mantissa bit
 
         return m
 
 
         return m
 
@@ -440,8 +507,8 @@ class FPAddDeNorm(FPState, FPID):
         self.idsync(m)
         # Denormalised Number checks
         m.next = "align"
         self.idsync(m)
         # Denormalised Number checks
         m.next = "align"
-        m.d.sync += self.out_a.copy(self.mod.out_a)
-        m.d.sync += self.out_b.copy(self.mod.out_b)
+        m.d.sync += self.out_a.eq(self.mod.out_a)
+        m.d.sync += self.out_b.eq(self.mod.out_b)
 
 
 class FPAddAlignMultiMod(FPState):
 
 
 class FPAddAlignMultiMod(FPState):
@@ -469,8 +536,8 @@ class FPAddAlignMultiMod(FPState):
 
         # exponent of a greater than b: shift b down
         m.d.comb += self.exp_eq.eq(0)
 
         # exponent of a greater than b: shift b down
         m.d.comb += self.exp_eq.eq(0)
-        m.d.comb += self.out_a.copy(self.in_a)
-        m.d.comb += self.out_b.copy(self.in_b)
+        m.d.comb += self.out_a.eq(self.in_a)
+        m.d.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)
         agtb = Signal(reset_less=True)
         altb = Signal(reset_less=True)
         m.d.comb += agtb.eq(self.in_a.e > self.in_b.e)
@@ -500,37 +567,51 @@ class FPAddAlignMulti(FPState, FPID):
         """ links module to inputs and outputs
         """
         m.submodules.align = self.mod
         """ 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)
-        #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.mod.in_a.eq(in_a)
+        m.d.comb += self.mod.in_b.eq(in_b)
+        #m.d.comb += self.out_a.eq(self.mod.out_a)
+        #m.d.comb += self.out_b.eq(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):
         self.idsync(m)
         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):
         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)
+        m.d.sync += self.out_a.eq(self.mod.out_a)
+        m.d.sync += self.out_b.eq(self.mod.out_b)
         with m.If(self.exp_eq):
             m.next = "add_0"
 
 
         with m.If(self.exp_eq):
             m.next = "add_0"
 
 
+class FPNumIn2Ops:
+
+    def __init__(self, width):
+        self.a = FPNumIn(None, width)
+        self.b = FPNumIn(None, width)
+
+    def eq(self, i):
+        return [self.a.eq(i.a), self.b.eq(i.b)]
+
+
 class FPAddAlignSingleMod:
 
     def __init__(self, width):
         self.width = width
 class FPAddAlignSingleMod:
 
     def __init__(self, width):
         self.width = width
-        self.in_a = FPNumBase(width)
-        self.in_b = FPNumBase(width)
-        self.out_a = FPNumIn(None, width)
-        self.out_b = FPNumIn(None, width)
+        self.i = self.ispec()
+        self.o = self.ospec()
+
+    def ispec(self):
+        return FPNumBase2Ops(self.width)
+
+    def ospec(self):
+        return FPNumIn2Ops(self.width)
 
     def setup(self, m, in_a, in_b):
         """ links module to inputs and outputs
         """
         m.submodules.align = self
 
     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)
+        m.d.comb += self.i.a.eq(in_a)
+        m.d.comb += self.i.b.eq(in_b)
 
     def elaborate(self, platform):
         """ Aligns A against B or B against A, depending on which has the
 
     def elaborate(self, platform):
         """ Aligns A against B or B against A, depending on which has the
@@ -543,16 +624,16 @@ class FPAddAlignSingleMod:
         """
         m = Module()
 
         """
         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
+        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
 
         # temporary (muxed) input and output to be shifted
         t_inp = FPNumBase(self.width)
         t_out = FPNumIn(None, self.width)
 
         # temporary (muxed) input and output to be shifted
         t_inp = FPNumBase(self.width)
         t_out = FPNumIn(None, self.width)
-        espec = (len(self.in_a.e), True)
-        msr = MultiShiftRMerge(self.in_a.m_width, espec)
+        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
         m.submodules.multishift_r = msr
         m.submodules.align_t_in = t_inp
         m.submodules.align_t_out = t_out
         m.submodules.multishift_r = msr
@@ -570,29 +651,29 @@ class FPAddAlignSingleMod:
         m.d.comb += t_out.e.eq(t_inp.e + tdiff)
         m.d.comb += t_out.s.eq(t_inp.s)
 
         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.in_a.e - self.in_b.e)
-        m.d.comb += ediffr.eq(self.in_b.e - self.in_a.e)
-        m.d.comb += elz.eq(self.in_a.e < self.in_b.e)
-        m.d.comb += egz.eq(self.in_a.e > self.in_b.e)
+        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)
 
         # default: A-exp == B-exp, A and B untouched (fall through)
-        m.d.comb += self.out_a.copy(self.in_a)
-        m.d.comb += self.out_b.copy(self.in_b)
+        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(egz):
         # 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(egz):
-            m.d.comb += [t_inp.copy(self.in_b),
+            m.d.comb += [t_inp.eq(self.i.b),
                          tdiff.eq(ediff),
                          tdiff.eq(ediff),
-                         self.out_b.copy(t_out),
-                         self.out_b.s.eq(self.in_b.s), # whoops forgot sign
+                         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):
                         ]
         # exponent of b greater than a: shift a down
         with m.Elif(elz):
-            m.d.comb += [t_inp.copy(self.in_a),
+            m.d.comb += [t_inp.eq(self.i.a),
                          tdiff.eq(ediffr),
                          tdiff.eq(ediffr),
-                         self.out_a.copy(t_out),
-                         self.out_a.s.eq(self.in_a.s), # whoops forgot sign
+                         self.o.a.eq(t_out),
+                         self.o.a.s.eq(self.i.a.s), # whoops forgot sign
                         ]
         return m
 
                         ]
         return m
 
@@ -616,8 +697,8 @@ class FPAddAlignSingle(FPState, FPID):
     def action(self, m):
         self.idsync(m)
         # NOTE: could be done as comb
     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.d.sync += self.out_a.eq(self.mod.out_a)
+        m.d.sync += self.out_b.eq(self.mod.out_b)
         m.next = "add_0"
 
 
         m.next = "add_0"
 
 
@@ -627,8 +708,7 @@ class FPAddAlignSingleAdd(FPState, FPID):
         FPState.__init__(self, "align")
         FPID.__init__(self, id_wid)
         self.mod = FPAddAlignSingleMod(width)
         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.o = self.mod.ospec()
 
         self.a0mod = FPAddStage0Mod(width)
         self.a0_out_z = FPNumBase(width, False)
 
         self.a0mod = FPAddStage0Mod(width)
         self.a0_out_z = FPNumBase(width, False)
@@ -636,19 +716,17 @@ class FPAddAlignSingleAdd(FPState, FPID):
         self.a0_out_z = FPNumBase(width, False)
 
         self.a1mod = FPAddStage1Mod(width)
         self.a0_out_z = FPNumBase(width, False)
 
         self.a1mod = FPAddStage1Mod(width)
-        self.out_z = FPNumBase(width, False)
-        self.out_of = Overflow()
+        self.a1o = self.a1mod.ospec()
 
     def setup(self, m, in_a, in_b, in_mid):
         """ links module to inputs and outputs
         """
         self.mod.setup(m, in_a, in_b)
 
     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)
+        m.d.comb += self.o.eq(self.mod.o)
 
 
-        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.a0mod.setup(m, self.o.a, self.o.b)
+        m.d.comb += self.a0_out_z.eq(self.a0mod.o.z)
+        m.d.comb += self.out_tot.eq(self.a0mod.o.tot)
 
         self.a1mod.setup(m, self.out_tot, self.a0_out_z)
 
 
         self.a1mod.setup(m, self.out_tot, self.a0_out_z)
 
@@ -657,62 +735,75 @@ class FPAddAlignSingleAdd(FPState, FPID):
 
     def action(self, m):
         self.idsync(m)
 
     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.d.sync += self.a1o.eq(self.a1mod.o)
         m.next = "normalise_1"
 
 
         m.next = "normalise_1"
 
 
+class FPAddStage0Data:
+
+    def __init__(self, width):
+        self.z = FPNumBase(width, False)
+        self.tot = Signal(self.z.m_width + 4, reset_less=True)
+
+    def eq(self, i):
+        return [self.z.eq(i.z), self.tot.eq(i.tot)]
+
+
 class FPAddStage0Mod:
 
     def __init__(self, width):
 class FPAddStage0Mod:
 
     def __init__(self, width):
-        self.in_a = FPNumBase(width)
-        self.in_b = FPNumBase(width)
-        self.in_z = FPNumBase(width, False)
-        self.out_z = FPNumBase(width, False)
-        self.out_tot = Signal(self.out_z.m_width + 4, reset_less=True)
+        self.width = width
+        self.i = self.ispec()
+        self.o = self.ospec()
+
+    def ispec(self):
+        return FPNumBase2Ops(self.width)
+
+    def ospec(self):
+        return FPAddStage0Data(self.width)
 
     def setup(self, m, in_a, in_b):
         """ links module to inputs and outputs
         """
         m.submodules.add0 = self
 
     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)
+        m.d.comb += self.i.a.eq(in_a)
+        m.d.comb += self.i.b.eq(in_b)
 
     def elaborate(self, platform):
         m = Module()
 
     def elaborate(self, platform):
         m = Module()
-        m.submodules.add0_in_a = self.in_a
-        m.submodules.add0_in_b = self.in_b
-        m.submodules.add0_out_z = self.out_z
+        m.submodules.add0_in_a = self.i.a
+        m.submodules.add0_in_b = self.i.b
+        m.submodules.add0_out_z = self.o.z
 
 
-        m.d.comb += self.out_z.e.eq(self.in_a.e)
+        m.d.comb += self.o.z.e.eq(self.i.a.e)
 
         # store intermediate tests (and zero-extended mantissas)
         seq = Signal(reset_less=True)
         mge = Signal(reset_less=True)
 
         # store intermediate tests (and zero-extended mantissas)
         seq = Signal(reset_less=True)
         mge = Signal(reset_less=True)
-        am0 = Signal(len(self.in_a.m)+1, reset_less=True)
-        bm0 = Signal(len(self.in_b.m)+1, reset_less=True)
-        m.d.comb += [seq.eq(self.in_a.s == self.in_b.s),
-                     mge.eq(self.in_a.m >= self.in_b.m),
-                     am0.eq(Cat(self.in_a.m, 0)),
-                     bm0.eq(Cat(self.in_b.m, 0))
+        am0 = Signal(len(self.i.a.m)+1, reset_less=True)
+        bm0 = Signal(len(self.i.b.m)+1, reset_less=True)
+        m.d.comb += [seq.eq(self.i.a.s == self.i.b.s),
+                     mge.eq(self.i.a.m >= self.i.b.m),
+                     am0.eq(Cat(self.i.a.m, 0)),
+                     bm0.eq(Cat(self.i.b.m, 0))
                     ]
         # same-sign (both negative or both positive) add mantissas
         with m.If(seq):
             m.d.comb += [
                     ]
         # same-sign (both negative or both positive) add mantissas
         with m.If(seq):
             m.d.comb += [
-                self.out_tot.eq(am0 + bm0),
-                self.out_z.s.eq(self.in_a.s)
+                self.o.tot.eq(am0 + bm0),
+                self.o.z.s.eq(self.i.a.s)
             ]
         # a mantissa greater than b, use a
         with m.Elif(mge):
             m.d.comb += [
             ]
         # a mantissa greater than b, use a
         with m.Elif(mge):
             m.d.comb += [
-                self.out_tot.eq(am0 - bm0),
-                self.out_z.s.eq(self.in_a.s)
+                self.o.tot.eq(am0 - bm0),
+                self.o.z.s.eq(self.i.a.s)
             ]
         # b mantissa greater than a, use b
         with m.Else():
             m.d.comb += [
             ]
         # b mantissa greater than a, use b
         with m.Else():
             m.d.comb += [
-                self.out_tot.eq(bm0 - am0),
-                self.out_z.s.eq(self.in_b.s)
+                self.o.tot.eq(bm0 - am0),
+                self.o.z.s.eq(self.i.b.s)
         ]
         return m
 
         ]
         return m
 
@@ -727,8 +818,7 @@ class FPAddStage0(FPState, FPID):
         FPState.__init__(self, "add_0")
         FPID.__init__(self, id_wid)
         self.mod = FPAddStage0Mod(width)
         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.o = self.mod.ospec()
 
     def setup(self, m, in_a, in_b, in_mid):
         """ links module to inputs and outputs
 
     def setup(self, m, in_a, in_b, in_mid):
         """ links module to inputs and outputs
@@ -740,31 +830,45 @@ class FPAddStage0(FPState, FPID):
     def action(self, m):
         self.idsync(m)
         # NOTE: these could be done as combinatorial (merge add0+add1)
     def action(self, m):
         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)
+        m.d.sync += self.o.eq(self.mod.o)
         m.next = "add_1"
 
 
         m.next = "add_1"
 
 
+class FPAddStage1Data:
+
+    def __init__(self, width):
+        self.z = FPNumBase(width, False)
+        self.of = Overflow()
+
+    def eq(self, i):
+        return [self.z.eq(i.z), self.of.eq(i.of)]
+
+
+
 class FPAddStage1Mod(FPState):
     """ Second stage of add: preparation for normalisation.
         detects when tot sum is too big (tot[27] is kinda a carry bit)
     """
 
     def __init__(self, width):
 class FPAddStage1Mod(FPState):
     """ Second stage of add: preparation for normalisation.
         detects when tot sum is too big (tot[27] is kinda a carry bit)
     """
 
     def __init__(self, width):
-        self.out_norm = Signal(reset_less=True)
-        self.in_z = FPNumBase(width, False)
-        self.in_tot = Signal(self.in_z.m_width + 4, reset_less=True)
-        self.out_z = FPNumBase(width, False)
-        self.out_of = Overflow()
+        self.width = width
+        self.i = self.ispec()
+        self.o = self.ospec()
+
+    def ispec(self):
+        return FPAddStage0Data(self.width)
+
+    def ospec(self):
+        return FPAddStage1Data(self.width)
 
     def setup(self, m, in_tot, in_z):
         """ links module to inputs and outputs
         """
         m.submodules.add1 = self
 
     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.submodules.add1_out_overflow = self.o.of
 
 
-        m.d.comb += self.in_z.copy(in_z)
-        m.d.comb += self.in_tot.eq(in_tot)
+        m.d.comb += self.i.z.eq(in_z)
+        m.d.comb += self.i.tot.eq(in_tot)
 
     def elaborate(self, platform):
         m = Module()
 
     def elaborate(self, platform):
         m = Module()
@@ -772,25 +876,25 @@ class FPAddStage1Mod(FPState):
         #m.submodules.norm1_out_overflow = self.out_of
         #m.submodules.norm1_in_z = self.in_z
         #m.submodules.norm1_out_z = self.out_z
         #m.submodules.norm1_out_overflow = self.out_of
         #m.submodules.norm1_in_z = self.in_z
         #m.submodules.norm1_out_z = self.out_z
-        m.d.comb += self.out_z.copy(self.in_z)
-        # tot[27] gets set when the sum overflows. shift result down
-        with m.If(self.in_tot[-1]):
+        m.d.comb += self.o.z.eq(self.i.z)
+        # tot[-1] (MSB) gets set when the sum overflows. shift result down
+        with m.If(self.i.tot[-1]):
             m.d.comb += [
             m.d.comb += [
-                self.out_z.m.eq(self.in_tot[4:]),
-                self.out_of.m0.eq(self.in_tot[4]),
-                self.out_of.guard.eq(self.in_tot[3]),
-                self.out_of.round_bit.eq(self.in_tot[2]),
-                self.out_of.sticky.eq(self.in_tot[1] | self.in_tot[0]),
-                self.out_z.e.eq(self.in_z.e + 1)
+                self.o.z.m.eq(self.i.tot[4:]),
+                self.o.of.m0.eq(self.i.tot[4]),
+                self.o.of.guard.eq(self.i.tot[3]),
+                self.o.of.round_bit.eq(self.i.tot[2]),
+                self.o.of.sticky.eq(self.i.tot[1] | self.i.tot[0]),
+                self.o.z.e.eq(self.i.z.e + 1)
         ]
         ]
-        # tot[27] zero case
+        # tot[-1] (MSB) zero case
         with m.Else():
             m.d.comb += [
         with m.Else():
             m.d.comb += [
-                self.out_z.m.eq(self.in_tot[3:]),
-                self.out_of.m0.eq(self.in_tot[3]),
-                self.out_of.guard.eq(self.in_tot[2]),
-                self.out_of.round_bit.eq(self.in_tot[1]),
-                self.out_of.sticky.eq(self.in_tot[0])
+                self.o.z.m.eq(self.i.tot[3:]),
+                self.o.of.m0.eq(self.i.tot[3]),
+                self.o.of.guard.eq(self.i.tot[2]),
+                self.o.of.round_bit.eq(self.i.tot[1]),
+                self.o.of.sticky.eq(self.i.tot[0])
         ]
         return m
 
         ]
         return m
 
@@ -817,12 +921,75 @@ class FPAddStage1(FPState, FPID):
 
     def action(self, m):
         self.idsync(m)
 
     def action(self, m):
         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.out_of.eq(self.mod.out_of)
+        m.d.sync += self.out_z.eq(self.mod.out_z)
         m.d.sync += self.norm_stb.eq(1)
         m.next = "normalise_1"
 
 
         m.d.sync += self.norm_stb.eq(1)
         m.next = "normalise_1"
 
 
+class FPNormaliseModSingle:
+
+    def __init__(self, width):
+        self.width = width
+        self.in_z = FPNumBase(width, False)
+        self.out_z = FPNumBase(width, False)
+
+    def setup(self, m, in_z, out_z, modname):
+        """ links module to inputs and outputs
+        """
+        m.submodules.normalise = self
+        m.d.comb += self.in_z.eq(in_z)
+        m.d.comb += out_z.eq(self.out_z)
+
+    def elaborate(self, platform):
+        m = Module()
+
+        mwid = self.out_z.m_width+2
+        pe = PriorityEncoder(mwid)
+        m.submodules.norm_pe = pe
+
+        m.submodules.norm1_out_z = self.out_z
+        m.submodules.norm1_in_z = self.in_z
+
+        in_z = FPNumBase(self.width, False)
+        in_of = Overflow()
+        m.submodules.norm1_insel_z = in_z
+        m.submodules.norm1_insel_overflow = in_of
+
+        espec = (len(in_z.e), True)
+        ediff_n126 = Signal(espec, reset_less=True)
+        msr = MultiShiftRMerge(mwid, espec)
+        m.submodules.multishift_r = msr
+
+        m.d.comb += in_z.eq(self.in_z)
+        m.d.comb += in_of.eq(self.in_of)
+        # initialise out from in (overridden below)
+        m.d.comb += self.out_z.eq(in_z)
+        m.d.comb += self.out_of.eq(in_of)
+        # normalisation increase/decrease conditions
+        decrease = Signal(reset_less=True)
+        m.d.comb += decrease.eq(in_z.m_msbzero)
+        # decrease exponent
+        with m.If(decrease):
+            # *sigh* not entirely obvious: count leading zeros (clz)
+            # with a PriorityEncoder: to find from the MSB
+            # we reverse the order of the bits.
+            temp_m = Signal(mwid, reset_less=True)
+            temp_s = Signal(mwid+1, reset_less=True)
+            clz = Signal((len(in_z.e), True), reset_less=True)
+            m.d.comb += [
+                # cat round and guard bits back into the mantissa
+                temp_m.eq(Cat(in_of.round_bit, in_of.guard, in_z.m)),
+                pe.i.eq(temp_m[::-1]),          # inverted
+                clz.eq(pe.o),                   # count zeros from MSB down
+                temp_s.eq(temp_m << clz),       # shift mantissa UP
+                self.out_z.e.eq(in_z.e - clz),  # DECREASE exponent
+                self.out_z.m.eq(temp_s[2:]),    # exclude bits 0&1
+            ]
+
+        return m
+
+
 class FPNorm1ModSingle:
 
     def __init__(self, width):
 class FPNorm1ModSingle:
 
     def __init__(self, width):
@@ -838,10 +1005,10 @@ class FPNorm1ModSingle:
         """
         m.submodules.normalise_1 = self
 
         """
         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 += self.in_z.eq(in_z)
+        m.d.comb += self.in_of.eq(in_of)
 
 
-        m.d.comb += out_z.copy(self.out_z)
+        m.d.comb += out_z.eq(self.out_z)
 
     def elaborate(self, platform):
         m = Module()
 
     def elaborate(self, platform):
         m = Module()
@@ -865,11 +1032,11 @@ class FPNorm1ModSingle:
         msr = MultiShiftRMerge(mwid, espec)
         m.submodules.multishift_r = msr
 
         msr = MultiShiftRMerge(mwid, espec)
         m.submodules.multishift_r = msr
 
-        m.d.comb += in_z.copy(self.in_z)
-        m.d.comb += in_of.copy(self.in_of)
+        m.d.comb += in_z.eq(self.in_z)
+        m.d.comb += in_of.eq(self.in_of)
         # initialise out from in (overridden below)
         # initialise out from in (overridden below)
-        m.d.comb += self.out_z.copy(in_z)
-        m.d.comb += self.out_of.copy(in_of)
+        m.d.comb += self.out_z.eq(in_z)
+        m.d.comb += self.out_of.eq(in_of)
         # normalisation increase/decrease conditions
         decrease = Signal(reset_less=True)
         increase = Signal(reset_less=True)
         # normalisation increase/decrease conditions
         decrease = Signal(reset_less=True)
         increase = Signal(reset_less=True)
@@ -927,7 +1094,6 @@ class FPNorm1ModMulti:
     def __init__(self, width, single_cycle=True):
         self.width = width
         self.in_select = Signal(reset_less=True)
     def __init__(self, width, single_cycle=True):
         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.temp_z = FPNumBase(width, False)
         self.in_z = FPNumBase(width, False)
         self.in_of = Overflow()
         self.temp_z = FPNumBase(width, False)
@@ -952,14 +1118,14 @@ class FPNorm1ModMulti:
 
         # select which of temp or in z/of to use
         with m.If(self.in_select):
 
         # 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)
+            m.d.comb += in_z.eq(self.in_z)
+            m.d.comb += in_of.eq(self.in_of)
         with m.Else():
         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.eq(self.temp_z)
+            m.d.comb += in_of.eq(self.temp_of)
         # initialise out from in (overridden below)
         # initialise out from in (overridden below)
-        m.d.comb += self.out_z.copy(in_z)
-        m.d.comb += self.out_of.copy(in_of)
+        m.d.comb += self.out_z.eq(in_z)
+        m.d.comb += self.out_of.eq(in_of)
         # normalisation increase/decrease conditions
         decrease = Signal(reset_less=True)
         increase = Signal(reset_less=True)
         # normalisation increase/decrease conditions
         decrease = Signal(reset_less=True)
         increase = Signal(reset_less=True)
@@ -1045,8 +1211,8 @@ class FPNorm1Multi(FPState, FPID):
     def action(self, m):
         self.idsync(m)
         m.d.comb += self.in_accept.eq((~self.ack) & (self.stb))
     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.sync += self.temp_of.eq(self.mod.out_of)
+        m.d.sync += self.temp_z.eq(self.out_z)
         with m.If(self.out_norm):
             with m.If(self.in_accept):
                 m.d.sync += [
         with m.If(self.out_norm):
             with m.If(self.in_accept):
                 m.d.sync += [
@@ -1083,13 +1249,13 @@ class FPNormToPack(FPState, FPID):
         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)
         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)
+        m.d.comb += r_out_z.eq(rmod.out_z)
 
         # Corrections (chained to rounding)
         cmod = FPCorrectionsMod(self.width)
         c_out_z = FPNumBase(self.width)
         cmod.setup(m, r_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)
+        m.d.comb += c_out_z.eq(cmod.out_z)
 
         # Pack (chained to corrections)
         self.pmod = FPPackMod(self.width)
 
         # Pack (chained to corrections)
         self.pmod = FPPackMod(self.width)
@@ -1116,12 +1282,12 @@ class FPRoundMod:
     def setup(self, m, in_z, roundz):
         m.submodules.roundz = self
 
     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_z.eq(in_z)
         m.d.comb += self.in_roundz.eq(roundz)
 
     def elaborate(self, platform):
         m = Module()
         m.d.comb += self.in_roundz.eq(roundz)
 
     def elaborate(self, platform):
         m = Module()
-        m.d.comb += self.out_z.copy(self.in_z)
+        m.d.comb += self.out_z.eq(self.in_z)
         with m.If(self.in_roundz):
             m.d.comb += self.out_z.m.eq(self.in_z.m + 1) # mantissa rounds up
             with m.If(self.in_z.m == self.in_z.m1s): # all 1s
         with m.If(self.in_roundz):
             m.d.comb += self.out_z.m.eq(self.in_z.m + 1) # mantissa rounds up
             with m.If(self.in_z.m == self.in_z.m1s): # all 1s
@@ -1147,7 +1313,7 @@ class FPRound(FPState, FPID):
 
     def action(self, m):
         self.idsync(m)
 
     def action(self, m):
         self.idsync(m)
-        m.d.sync += self.out_z.copy(self.mod.out_z)
+        m.d.sync += self.out_z.eq(self.mod.out_z)
         m.next = "corrections"
 
 
         m.next = "corrections"
 
 
@@ -1161,13 +1327,13 @@ class FPCorrectionsMod:
         """ links module to inputs and outputs
         """
         m.submodules.corrections = self
         """ links module to inputs and outputs
         """
         m.submodules.corrections = self
-        m.d.comb += self.in_z.copy(in_z)
+        m.d.comb += self.in_z.eq(in_z)
 
     def elaborate(self, platform):
         m = Module()
         m.submodules.corr_in_z = self.in_z
         m.submodules.corr_out_z = self.out_z
 
     def elaborate(self, platform):
         m = Module()
         m.submodules.corr_in_z = self.in_z
         m.submodules.corr_out_z = self.out_z
-        m.d.comb += self.out_z.copy(self.in_z)
+        m.d.comb += self.out_z.eq(self.in_z)
         with m.If(self.in_z.is_denormalised):
             m.d.comb += self.out_z.e.eq(self.in_z.N127)
         return m
         with m.If(self.in_z.is_denormalised):
             m.d.comb += self.out_z.e.eq(self.in_z.N127)
         return m
@@ -1190,7 +1356,7 @@ class FPCorrections(FPState, FPID):
 
     def action(self, m):
         self.idsync(m)
 
     def action(self, m):
         self.idsync(m)
-        m.d.sync += self.out_z.copy(self.mod.out_z)
+        m.d.sync += self.out_z.eq(self.mod.out_z)
         m.next = "pack"
 
 
         m.next = "pack"
 
 
@@ -1204,7 +1370,7 @@ class FPPackMod:
         """ links module to inputs and outputs
         """
         m.submodules.pack = self
         """ links module to inputs and outputs
         """
         m.submodules.pack = self
-        m.d.comb += self.in_z.copy(in_z)
+        m.d.comb += self.in_z.eq(in_z)
 
     def elaborate(self, platform):
         m = Module()
 
     def elaborate(self, platform):
         m = Module()
@@ -1395,10 +1561,10 @@ class FPADDBaseMod(FPID):
         sc.setup(m, a, b, self.in_mid)
 
         alm = self.add_state(FPAddAlignSingleAdd(self.width, self.id_wid))
         sc.setup(m, a, b, self.in_mid)
 
         alm = self.add_state(FPAddAlignSingleAdd(self.width, self.id_wid))
-        alm.setup(m, sc.out_a, sc.out_b, sc.in_mid)
+        alm.setup(m, sc.o.a, sc.o.b, sc.in_mid)
 
         n1 = self.add_state(FPNormToPack(self.width, self.id_wid))
 
         n1 = self.add_state(FPNormToPack(self.width, self.id_wid))
-        n1.setup(m, alm.out_z, alm.out_of, alm.in_mid)
+        n1.setup(m, alm.a1o.z, alm.a1o.of, alm.in_mid)
 
         ppz = self.add_state(FPPutZ("pack_put_z", n1.out_z, self.out_z,
                                     n1.in_mid, self.out_mid))
 
         ppz = self.add_state(FPPutZ("pack_put_z", n1.out_z, self.out_z,
                                     n1.in_mid, self.out_mid))
@@ -1513,7 +1679,7 @@ class ResArray:
         self.in_mid = Signal(self.id_wid, reset_less=True)
 
     def setup(self, m, in_z, in_mid):
         self.in_mid = Signal(self.id_wid, reset_less=True)
 
     def setup(self, m, in_z, in_mid):
-        m.d.comb += [self.in_z.copy(in_z),
+        m.d.comb += [self.in_z.eq(in_z),
                      self.in_mid.eq(in_mid)]
 
     def get_fragment(self, platform=None):
                      self.in_mid.eq(in_mid)]
 
     def get_fragment(self, platform=None):