make demo/test ALU look like nmigen pipeline API
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 23 May 2020 17:08:08 +0000 (18:08 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 23 May 2020 17:08:08 +0000 (18:08 +0100)
src/soc/experiment/alu_hier.py
src/soc/experiment/compalu_multi.py

index 72de48749c042eafc9f4f0b9b3bbfaa96e3d9893..af373ca3c9905bfac4b87dd686619f0aa714e3e5 100644 (file)
@@ -78,13 +78,17 @@ class Shifter(Elaboratable):
         m.d.comb += self.o.eq(self.a >> btrunc)
         return m
 
+class Dummy:
+    pass
 
 class ALU(Elaboratable):
     def __init__(self, width):
-        self.p_valid_i = Signal()
-        self.p_ready_o = Signal()
-        self.n_ready_i = Signal()
-        self.n_valid_o = Signal()
+        self.p = Dummy() # make look like nmutil pipeline API
+        self.n = Dummy() # make look like nmutil pipeline API
+        self.p.valid_i = Signal()
+        self.p.ready_o = Signal()
+        self.n.ready_i = Signal()
+        self.n.valid_o = Signal()
         self.counter   = Signal(4)
         self.op  = CompALUOpSubset()
         i = []
@@ -118,11 +122,11 @@ class ALU(Elaboratable):
 
         go_now = Signal(reset_less=True) # testing no-delay ALU
 
-        with m.If(self.p_valid_i):
+        with m.If(self.p.valid_i):
             # input is valid. next check, if we already said "ready" or not
-            with m.If(~self.p_ready_o):
+            with m.If(~self.p.ready_o):
                 # we didn't say "ready" yet, so say so and initialise
-                m.d.sync += self.p_ready_o.eq(1)
+                m.d.sync += self.p.ready_o.eq(1)
 
                 # as this is a "fake" pipeline, just grab the output right now
                 with m.If(self.op.insn_type == InternalOp.OP_ADD):
@@ -152,14 +156,14 @@ class ALU(Elaboratable):
         with m.Else():
             # input says no longer valid, so drop ready as well.
             # a "proper" ALU would have had to sync in the opcode and a/b ops
-            m.d.sync += self.p_ready_o.eq(0)
+            m.d.sync += self.p.ready_o.eq(0)
 
         # ok so the counter's running: when it gets to 1, fire the output
         with m.If((self.counter == 1) | go_now):
             # set the output as valid if the recipient is ready for it
-            m.d.sync += self.n_valid_o.eq(1)
-        with m.If(self.n_ready_i & self.n_valid_o):
-            m.d.sync += self.n_valid_o.eq(0)
+            m.d.sync += self.n.valid_o.eq(1)
+        with m.If(self.n.ready_i & self.n.valid_o):
+            m.d.sync += self.n.valid_o.eq(0)
             # recipient said it was ready: reset back to known-good.
             m.d.sync += self.counter.eq(0) # reset the counter
             m.d.sync += self.o.eq(0) # clear the output for tidiness sake
@@ -195,10 +199,10 @@ class BranchOp(Elaboratable):
 
 class BranchALU(Elaboratable):
     def __init__(self, width):
-        self.p_valid_i = Signal()
-        self.p_ready_o = Signal()
-        self.n_ready_i = Signal()
-        self.n_valid_o = Signal()
+        self.p.valid_i = Signal()
+        self.p.ready_o = Signal()
+        self.n.ready_i = Signal()
+        self.n.valid_o = Signal()
         self.counter   = Signal(4)
         self.op  = Signal(2)
         i = []
@@ -228,11 +232,11 @@ class BranchALU(Elaboratable):
             ]
 
         go_now = Signal(reset_less=True) # testing no-delay ALU
-        with m.If(self.p_valid_i):
+        with m.If(self.p.valid_i):
             # input is valid. next check, if we already said "ready" or not
-            with m.If(~self.p_ready_o):
+            with m.If(~self.p.ready_o):
                 # we didn't say "ready" yet, so say so and initialise
-                m.d.sync += self.p_ready_o.eq(1)
+                m.d.sync += self.p.ready_o.eq(1)
 
                 # as this is a "fake" pipeline, just grab the output right now
                 with m.Switch(self.op):
@@ -244,14 +248,14 @@ class BranchALU(Elaboratable):
         with m.Else():
             # input says no longer valid, so drop ready as well.
             # a "proper" ALU would have had to sync in the opcode and a/b ops
-            m.d.sync += self.p_ready_o.eq(0)
+            m.d.sync += self.p.ready_o.eq(0)
 
         # ok so the counter's running: when it gets to 1, fire the output
         with m.If((self.counter == 1) | go_now):
             # set the output as valid if the recipient is ready for it
-            m.d.sync += self.n_valid_o.eq(1)
-        with m.If(self.n_ready_i & self.n_valid_o):
-            m.d.sync += self.n_valid_o.eq(0)
+            m.d.sync += self.n.valid_o.eq(1)
+        with m.If(self.n.ready_i & self.n.valid_o):
+            m.d.sync += self.n.valid_o.eq(0)
             # recipient said it was ready: reset back to known-good.
             m.d.sync += self.counter.eq(0) # reset the counter
             m.d.sync += self.o.eq(0) # clear the output for tidiness sake
@@ -276,19 +280,19 @@ def run_op(dut, a, b, op, inv_a=0):
     yield dut.b.eq(b)
     yield dut.op.insn_type.eq(op)
     yield dut.op.invert_a.eq(inv_a)
-    yield dut.n_ready_i.eq(0)
-    yield dut.p_valid_i.eq(1)
+    yield dut.n.ready_i.eq(0)
+    yield dut.p.valid_i.eq(1)
     yield
     while True:
         yield
-        n_valid_o = yield dut.n_valid_o
-        if n_valid_o:
+        n.valid_o = yield dut.n.valid_o
+        if n.valid_o:
             break
     yield
 
     result = yield dut.o
-    yield dut.p_valid_i.eq(0)
-    yield dut.n_ready_i.eq(0)
+    yield dut.p.valid_i.eq(0)
+    yield dut.n.ready_i.eq(0)
     yield
 
     return result
index b25749c8b879969ee044e3717e68061b4585d0c0..7cdd19d0fa35b4a926b0e26bd5d082fb512e9f2c 100644 (file)
@@ -235,7 +235,7 @@ class MultiCompUnit(Elaboratable):
 
         # read-done,wr-proceed latch
         m.d.comb += rok_l.s.eq(self.issue_i)  # set up when issue starts
-        m.d.comb += rok_l.r.eq(self.alu.p_ready_o) # off when ALU acknowledges
+        m.d.comb += rok_l.r.eq(self.alu.p.ready_o) # off when ALU acknowledges
 
         # wr-done, back-to-start latch
         m.d.comb += rst_l.s.eq(all_rd)     # set when read-phase is fully done
@@ -243,7 +243,7 @@ class MultiCompUnit(Elaboratable):
 
         # opcode latch (not using go_rd_i) - inverted so that busy resets to 0
         m.d.sync += opc_l.s.eq(self.issue_i)       # set on issue
-        m.d.sync += opc_l.r.eq(self.alu.n_valid_o & req_done) # reset on ALU
+        m.d.sync += opc_l.r.eq(self.alu.n.valid_o & req_done) # reset on ALU
 
         # src operand latch (not using go_wr_i)
         m.d.sync += src_l.s.eq(Repl(self.issue_i, self.n_src))
@@ -318,17 +318,17 @@ class MultiCompUnit(Elaboratable):
         # NOTE: this spells TROUBLE if the ALU isn't ready!
         # go_read is only valid for one clock!
         with m.If(all_rd):                           # src operands ready, GO!
-            with m.If(~self.alu.p_ready_o):          # no ACK yet
-                m.d.comb += self.alu.p_valid_i.eq(1) # so indicate valid
+            with m.If(~self.alu.p.ready_o):          # no ACK yet
+                m.d.comb += self.alu.p.valid_i.eq(1) # so indicate valid
 
         brd = Repl(self.busy_o & self.shadown_i, self.n_dst)
         # only proceed if ALU says its output is valid
-        with m.If(self.alu.n_valid_o):
+        with m.If(self.alu.n.valid_o):
             # when ALU ready, write req release out. waits for shadow
             m.d.comb += self.wr.rel.eq(req_l.q & brd)
             # when output latch is ready, and ALU says ready, accept ALU output
             with m.If(reset):
-                m.d.comb += self.alu.n_ready_i.eq(1) # tells ALU "thanks got it"
+                m.d.comb += self.alu.n.ready_i.eq(1) # tells ALU "thanks got it"
 
         # output the data from the latch on go_write
         for i in range(self.n_dst):