add readonly option to TestMemory
[soc.git] / src / soc / experiment / alu_hier.py
index 007d8b69b297d192a1c35b07c1445b52d5167822..99ff39e47f287ff4125ea025c249ddfe4804c207 100644 (file)
@@ -218,14 +218,6 @@ class ALU(Elaboratable):
         alu_done = Signal(reset_less=True)
         m.d.comb += alu_done.eq(self.counter == 1)
 
-        # in a sequential ALU, valid_o rises when the ALU is done
-        # and falls when acknowledged by ready_i
-        valid_o = Signal()
-        with m.If(alu_done):
-            m.d.sync += valid_o.eq(1)
-        with m.Elif(self.n.ready_i):
-            m.d.sync += valid_o.eq(0)
-
         # select handshake handling according to ALU type
         with m.If(go_now):
             # with a combinatorial, no-delay ALU, just pass through
@@ -237,7 +229,7 @@ class ALU(Elaboratable):
             # ready_o responds to valid_i, but only if the ALU is idle
             m.d.comb += self.p.ready_o.eq(self.p.valid_i & alu_idle)
             # select the internally generated valid_o, above
-            m.d.comb += self.n.valid_o.eq(valid_o)
+            m.d.comb += self.n.valid_o.eq(alu_done)
 
         # hold the ALU result until ready_o is asserted
         alu_r = Signal(self.width)
@@ -259,18 +251,18 @@ class ALU(Elaboratable):
                 # MUL, to take 5 instructions
                 with m.If(self.op.insn_type == InternalOp.OP_MUL_L64):
                     m.d.sync += self.counter.eq(5)
-                # SHIFT to take 7
+                # SHIFT to take 1, straight away
                 with m.Elif(self.op.insn_type == InternalOp.OP_SHR):
-                    m.d.sync += self.counter.eq(7)
-                # ADD/SUB to take 2, straight away
+                    m.d.sync += self.counter.eq(1)
+                # ADD/SUB to take 3
                 with m.Elif(self.op.insn_type == InternalOp.OP_ADD):
                     m.d.sync += self.counter.eq(3)
                 # others to take no delay
                 with m.Else():
                     m.d.comb += go_now.eq(1)
 
-        with m.Else():
-            # decrement the counter while the ALU is not idle
+        with m.Elif(~alu_done | self.n.ready_i):
+            # decrement the counter while the ALU is neither idle nor finished
             m.d.sync += self.counter.eq(self.counter - 1)
 
         # choose between zero-delay output, or registered
@@ -388,16 +380,17 @@ class BranchALU(Elaboratable):
         return list(self)
 
 def run_op(dut, a, b, op, inv_a=0):
+    from nmigen.back.pysim import Settle
     yield dut.a.eq(a)
     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
 
     # if valid_o rose on the very first cycle, it is a
     # zero-delay ALU
+    yield Settle()
     vld = yield dut.n.valid_o
     if vld:
         # special case for zero-delay ALU
@@ -412,6 +405,8 @@ def run_op(dut, a, b, op, inv_a=0):
         yield
         return result
 
+    yield
+
     # wait for the ALU to accept our input data
     while True:
         rdy = yield dut.p.ready_o
@@ -423,6 +418,7 @@ def run_op(dut, a, b, op, inv_a=0):
 
     # wait for the ALU to present the output data
     while True:
+        yield Settle()
         vld = yield dut.n.valid_o
         if vld:
             break
@@ -457,6 +453,10 @@ def alu_sim(dut):
     print ("alu_sim sub", result)
     assert (result == 2)
 
+    result = yield from run_op(dut, 13, 2, InternalOp.OP_SHR)
+    print ("alu_sim shr", result)
+    assert (result == 3)
+
 
 def test_alu():
     alu = ALU(width=16)