add (but comment out) reset signal
[ieee754fpu.git] / src / add / nmigen_add_experiment.py
index deabc682a1aaed23832ec71a07d9f8b0f18a9b51..f53037d1a88c912566cd13fd32db1945346a1751 100644 (file)
@@ -2,14 +2,16 @@
 # Copyright (C) Jonathan P Dawson 2013
 # 2013-12-12
 
-from nmigen import Module, Signal, Cat, Mux
+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 FPNumShiftMultiRight
 
+
 class FPState(FPBase):
     def __init__(self, state_from):
         self.state_from = state_from
@@ -25,6 +27,115 @@ class FPState(FPBase):
             setattr(self, k, v)
 
 
+class FPGetSyncOpsMod:
+    def __init__(self, width, num_ops=2):
+        self.width = width
+        self.num_ops = num_ops
+        inops = []
+        outops = []
+        for i in range(num_ops):
+            inops.append(Signal(width, reset_less=True))
+            outops.append(Signal(width, reset_less=True))
+        self.in_op = inops
+        self.out_op = outops
+        self.stb = Signal(num_ops)
+        self.ack = Signal()
+        self.ready = Signal(reset_less=True)
+        self.out_decode = Signal(reset_less=True)
+
+    def elaborate(self, platform):
+        m = Module()
+        m.d.comb += self.ready.eq(self.stb == Const(-1, (self.num_ops, False)))
+        m.d.comb += self.out_decode.eq(self.ack & self.ready)
+        with m.If(self.out_decode):
+            for i in range(self.num_ops):
+                m.d.comb += [
+                        self.out_op[i].eq(self.in_op[i]),
+                ]
+        return m
+
+    def ports(self):
+        return self.in_op + self.out_op + [self.stb, self.ack]
+
+
+class FPOps(Trigger):
+    def __init__(self, width, 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.mmax = int(log(self.num_rows) / log(2))
+        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))
+        self.rs = Array(self.rs)
+
+        self.out_op = FPOps(width, num_ops)
+
+    def elaborate(self, platform):
+        m = Module()
+
+        pe = PriorityEncoder(self.num_rows)
+        m.submodules.selector = pe
+        m.submodules.out_op = self.out_op
+        m.submodules.out_op_v = self.out_op.v
+        m.submodules += self.rs
+
+        # connect priority encoder
+        in_ready = []
+        for i in range(self.num_rows):
+            in_ready.append(self.rs[i].ready)
+        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
+
+    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):
         self.in_op = FPOp(width)
@@ -1177,8 +1288,11 @@ class FPPack(FPState, FPID):
 
 class FPPutZ(FPState):
 
-    def __init__(self, state, in_z, out_z, in_mid, out_mid):
+    def __init__(self, state, in_z, out_z, in_mid, out_mid, to_state=None):
         FPState.__init__(self, state)
+        if to_state is None:
+            to_state = "get_ops"
+        self.to_state = to_state
         self.in_z = in_z
         self.out_z = out_z
         self.in_mid = in_mid
@@ -1192,11 +1306,38 @@ class FPPutZ(FPState):
         ]
         with m.If(self.out_z.stb & self.out_z.ack):
             m.d.sync += self.out_z.stb.eq(0)
-            m.next = "get_ops"
+            m.next = self.to_state
         with m.Else():
             m.d.sync += self.out_z.stb.eq(1)
 
 
+class FPPutZIdx(FPState):
+
+    def __init__(self, state, in_z, out_zs, in_mid, to_state=None):
+        FPState.__init__(self, state)
+        if to_state is None:
+            to_state = "get_ops"
+        self.to_state = to_state
+        self.in_z = in_z
+        self.out_zs = out_zs
+        self.in_mid = in_mid
+
+    def action(self, m):
+        outz_stb = Signal(reset_less=True)
+        outz_ack = Signal(reset_less=True)
+        m.d.comb += [outz_stb.eq(self.out_zs[self.in_mid].stb),
+                     outz_ack.eq(self.out_zs[self.in_mid].ack),
+                    ]
+        m.d.sync += [
+          self.out_zs[self.in_mid].v.eq(self.in_z.v)
+        ]
+        with m.If(outz_stb & outz_ack):
+            m.d.sync += self.out_zs[self.in_mid].stb.eq(0)
+            m.next = self.to_state
+        with m.Else():
+            m.d.sync += self.out_zs[self.in_mid].stb.eq(1)
+
+
 class FPADDBaseMod(FPID):
 
     def __init__(self, width, id_wid=None, single_cycle=False, compact=True):
@@ -1361,6 +1502,7 @@ class FPADDBase(FPState, FPID):
 
         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.out_z.ack.eq(0) # likewise
         #m.d.sync += self.in_t.stb.eq(0)
 
         m.submodules.fpadd = self.mod
@@ -1382,13 +1524,14 @@ class FPADDBase(FPState, FPID):
             with m.Else():
                 m.d.sync += [self.add_ack.eq(0),
                              self.in_t.stb.eq(0),
+                             self.out_z.ack.eq(1),
                             ]
         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"
+            m.next = "put_z"
 
             return
 
@@ -1405,6 +1548,38 @@ class FPADDBase(FPState, FPID):
             with m.Else():
                 m.d.sync += self.out_z.stb.eq(1)
 
+class ResArray:
+    def __init__(self, width, id_wid):
+        self.width = width
+        self.id_wid = id_wid
+        res = []
+        for i in range(rs_sz):
+            out_z = FPOp(width)
+            out_z.name = "out_z_%d" % i
+            res.append(out_z)
+        self.res = Array(res)
+        self.in_z = FPOp(width)
+        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),
+                     self.in_mid.eq(in_mid)]
+
+    def get_fragment(self, platform=None):
+        """ creates the HDL code-fragment for FPAdd
+        """
+        m = Module()
+        m.submodules.res_in_z = self.in_z
+        m.submodules += self.res
+
+        return m
+
+    def ports(self):
+        res = []
+        for z in self.res:
+            res += z.ports()
+        return res
+
 
 class FPADD(FPID):
     """ FPADD: stages as follows:
@@ -1423,21 +1598,35 @@ class FPADD(FPID):
         needs to be the thing that raises the incoming stb.
     """
 
-    def __init__(self, width, id_wid=None, single_cycle=False):
+    def __init__(self, width, id_wid=None, single_cycle=False, rs_sz=2):
         """ 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)
         self.width = width
         self.id_wid = id_wid
         self.single_cycle = single_cycle
 
-        self.in_a  = FPOp(width)
-        self.in_b  = FPOp(width)
-        self.out_z = FPOp(width)
+        #self.out_z = FPOp(width)
+        self.ids = FPID(id_wid)
+
+        rs = []
+        for i in range(rs_sz):
+            in_a  = FPOp(width)
+            in_b  = FPOp(width)
+            in_a.name = "in_a_%d" % i
+            in_b.name = "in_b_%d" % i
+            rs.append((in_a, in_b))
+        self.rs = Array(rs)
+
+        res = []
+        for i in range(rs_sz):
+            out_z = FPOp(width)
+            out_z.name = "out_z_%d" % i
+            res.append(out_z)
+        self.res = Array(res)
 
         self.states = []
 
@@ -1449,27 +1638,32 @@ class FPADD(FPID):
         """ 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 += self.rs
+
+        in_a = self.rs[0][0]
+        in_b = self.rs[0][1]
+
+        out_z = FPOp(self.width)
+        out_mid = Signal(self.id_wid, reset_less=True)
+        m.submodules.out_z = out_z
 
         geta = self.add_state(FPGetOp("get_a", "get_b",
-                                      self.in_a, self.width))
-        geta.setup(m, self.in_a)
+                                      in_a, self.width))
+        geta.setup(m, 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)
+                                      in_b, self.width))
+        getb.setup(m, in_b)
         b = getb.out_op
 
         ab = FPADDBase(self.width, self.id_wid, self.single_cycle)
         ab = self.add_state(ab)
-        ab.setup(m, a, b, getb.out_decode, self.in_mid,
-                 self.out_z, self.out_mid)
+        ab.setup(m, a, b, getb.out_decode, self.ids.in_mid,
+                 out_z, out_mid)
 
-        #pz = self.add_state(FPPutZ("put_z", ab.out_z, self.out_z,
-        #                            ab.out_mid, self.out_mid))
+        pz = self.add_state(FPPutZIdx("put_z", ab.out_z, self.res,
+                                    out_mid, "get_a"))
 
         with m.FSM() as fsm:
 
@@ -1483,10 +1677,10 @@ class FPADD(FPID):
 if __name__ == "__main__":
     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])
+        main(alu, ports=alu.rs[0][0].ports() + \
+                        alu.rs[0][1].ports() + \
+                        alu.res[0].ports() + \
+                        [alu.ids.in_mid, alu.ids.out_mid])
     else:
         alu = FPADDBase(width=32, id_wid=5, single_cycle=True)
         main(alu, ports=[alu.in_a, alu.in_b] + \