Choose between RA (src1) and zero immediate, conditioned on zero_a
[soc.git] / src / soc / experiment / alu_hier.py
index 366dbed8f3b1d1791268eb3052f1f1c9cb5e2f49..29c97d7da3e49a2790f7ef9ddd4a1ff77c42156e 100644 (file)
@@ -9,89 +9,20 @@ A "real" integer ALU would place the answers onto the output bus after
 only one cycle (sync)
 """
 
-from nmigen import Elaboratable, Signal, Module, Const, Mux
+from nmigen import Elaboratable, Signal, Module, Const, Mux, Array
 from nmigen.hdl.rec import Record, Layout
 from nmigen.cli import main
 from nmigen.cli import verilog, rtlil
 from nmigen.compat.sim import run_simulation
 
-from soc.decoder.power_enums import InternalOp, CryIn
+from soc.decoder.power_enums import InternalOp, Function, CryIn
+
+from soc.fu.alu.alu_input_record import CompALUOpSubset
 
 import operator
 
 
-class CompALUOpSubset(Record):
-    """CompALUOpSubset
-
-    a copy of the relevant subset information from Decode2Execute1Type
-    needed for ALU operations.  use with eq_from_execute1 (below) to
-    grab subsets.
-    """
-    def __init__(self, name=None):
-        layout = (('insn_type', InternalOp),
-                  ('nia', 64),
-                  ('imm_data', Layout((("imm", 64), ("imm_ok", 1)))),
-                    #'cr = Signal(32, reset_less=True) # NO: this is from the CR SPR
-                    #'xerc = XerBits() # NO: this is from the XER SPR
-                  ('lk', 1),
-                  ('rc', Layout((("rc", 1), ("rc_ok", 1)))),
-                  ('oe', Layout((("oe", 1), ("oe_ok", 1)))),
-                  ('invert_a', 1),
-                  ('invert_out', 1),
-                  ('input_carry', CryIn),
-                  ('output_carry', 1),
-                  ('input_cr', 1),
-                  ('output_cr', 1),
-                  ('is_32bit', 1),
-                  ('is_signed', 1),
-                  ('byte_reverse', 1),
-                  ('sign_extend', 1))
-
-        Record.__init__(self, Layout(layout), name=name)
-
-        # grrr.  Record does not have kwargs
-        self.insn_type.reset_less = True
-        self.nia.reset_less = True
-        #self.cr = Signal(32, reset_less = True
-        #self.xerc = XerBits(
-        self.lk.reset_less = True
-        self.invert_a.reset_less = True
-        self.invert_out.reset_less = True
-        self.input_carry.reset_less = True
-        self.output_carry.reset_less = True
-        self.input_cr.reset_less = True
-        self.output_cr.reset_less = True
-        self.is_32bit.reset_less = True
-        self.is_signed.reset_less = True
-        self.byte_reverse.reset_less = True
-        self.sign_extend.reset_less = True
-
-    def eq_from_execute1(self, other):
-        """ use this to copy in from Decode2Execute1Type
-        """
-        res = []
-        for fname, sig in self.fields.items():
-            eqfrom = other.fields[fname]
-            res.append(sig.eq(eqfrom)
-        return res
 
-    def ports(self):
-        return [self.insn_type,
-                self.nia,
-                #self.cr,
-                #self.xerc,
-                self.lk,
-                self.invert_a,
-                self.invert_out,
-                self.input_carry,
-                self.output_carry,
-                self.input_cr,
-                self.output_cr,
-                self.is_32bit,
-                self.is_signed,
-                self.byte_reverse,
-                self.sign_extend,
-        ]
 
 class Adder(Elaboratable):
     def __init__(self, width):
@@ -147,19 +78,35 @@ 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.p.data_i = Dummy()
+        self.p.data_i.ctx = Dummy()
+        self.n = Dummy() # make look like nmutil pipeline API
+        self.n.data_o = Dummy()
+        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()
-        self.a   = Signal(width)
-        self.b   = Signal(width)
-        self.o   = Signal(width)
+        i = []
+        i.append(Signal(width, name="i1"))
+        i.append(Signal(width, name="i2"))
+        self.i = Array(i)
+        self.a, self.b = i[0], i[1]
+        self.out = Array([Signal(width)])
+        self.o = self.out[0]
         self.width = width
+        # more "look like nmutil pipeline API"
+        self.p.data_i.ctx.op = self.op
+        self.p.data_i.a = self.a
+        self.p.data_i.b = self.b
+        self.n.data_o.o = self.o
 
     def elaborate(self, platform):
         m = Module()
@@ -183,11 +130,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):
@@ -217,14 +164,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
@@ -260,15 +207,19 @@ 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)
-        self.a   = Signal(width)
-        self.b   = Signal(width)
-        self.o   = Signal(width)
+        i = []
+        i.append(Signal(width, name="i1"))
+        i.append(Signal(width, name="i2"))
+        self.i = Array(i)
+        self.a, self.b = i[0], i[1]
+        self.out = Array([Signal(width)])
+        self.o = self.out[0]
         self.width = width
 
     def elaborate(self, platform):
@@ -289,11 +240,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):
@@ -305,14 +256,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
@@ -337,19 +288,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