start adding in immediates into CompUnit ALU
[soc.git] / src / experiment / compalu.py
index 1f3b90512e1d8940f9be7d096c2390c2ac12bd63..c8815353f5199d5ccf1b3ca46837f4dca94472eb 100644 (file)
@@ -1,6 +1,6 @@
 from nmigen.compat.sim import run_simulation
 from nmigen.cli import verilog, rtlil
 from nmigen.compat.sim import run_simulation
 from nmigen.cli import verilog, rtlil
-from nmigen import Module, Signal, Elaboratable
+from nmigen import Module, Signal, Mux, Elaboratable
 
 from nmutil.latch import SRLatch, latchregister
 
 
 from nmutil.latch import SRLatch, latchregister
 
@@ -36,10 +36,16 @@ from nmutil.latch import SRLatch, latchregister
       register is placed combinatorially onto the output, and (2) the
       req_l latch is cleared, busy is dropped, and the Comp Unit is back
       through its revolving door to do another task.
       register is placed combinatorially onto the output, and (2) the
       req_l latch is cleared, busy is dropped, and the Comp Unit is back
       through its revolving door to do another task.
+
+    Notes on oper_i:
+
+    * bits[0:2] are for the ALU, add=0, sub=1, shift=2, mul=3
+    * bit[2] are the immediate (bit[2]=1 == immediate mode)
 """
 
 class ComputationUnitNoDelay(Elaboratable):
     def __init__(self, rwid, opwid, alu):
 """
 
 class ComputationUnitNoDelay(Elaboratable):
     def __init__(self, rwid, opwid, alu):
+        self.opwid = opwid
         self.rwid = rwid
         self.alu = alu
 
         self.rwid = rwid
         self.alu = alu
 
@@ -51,6 +57,7 @@ class ComputationUnitNoDelay(Elaboratable):
         self.go_die_i = Signal() # go die (reset)
 
         self.oper_i = Signal(opwid, reset_less=True) # opcode in
         self.go_die_i = Signal() # go die (reset)
 
         self.oper_i = Signal(opwid, reset_less=True) # opcode in
+        self.imm_i = Signal(rwid, reset_less=True) # immediate in
         self.src1_i = Signal(rwid, reset_less=True) # oper1 in
         self.src2_i = Signal(rwid, reset_less=True) # oper2 in
 
         self.src1_i = Signal(rwid, reset_less=True) # oper1 in
         self.src2_i = Signal(rwid, reset_less=True) # oper2 in
 
@@ -88,24 +95,52 @@ class ComputationUnitNoDelay(Elaboratable):
         m.d.sync += req_l.s.eq(self.go_rd_i)
         m.d.sync += req_l.r.eq(reset_w)
 
         m.d.sync += req_l.s.eq(self.go_rd_i)
         m.d.sync += req_l.r.eq(reset_w)
 
-        # XXX
-        # XXX NOTE: sync on req_rel_o and data_o due to simulation lock-up
-        # XXX
 
 
+        # create a latch/register for the operand
+        oper_r = Signal(self.opwid+1, reset_less=True) # opcode reg
+        latchregister(m, self.oper_i, oper_r, self.issue_i)
+
+        # and one for the output from the ALU
+        data_r = Signal(self.rwid, reset_less=True) # Dest register
+        latchregister(m, self.alu.o, data_r, req_l.q)
+
+        # get the top 2 bits for the ALU
+        m.d.comb += self.alu.op.eq(oper_r[0:2])
+
+        # 3rd bit is whether this is an immediate or not
+        op_is_imm = Signal(reset_less=True)
+        m.d.comb += op_is_imm.eq(oper_r[2])
+
+        # select immediate if opcode says so.  however also change the latch
+        # to trigger *from* the opcode latch instead.
+        src2_or_imm = Signal(self.rwid, reset_less=True)
+        src_sel = Signal(reset_less=True)
+        m.d.comb += src_sel.eq(Mux(op_is_imm, opc_l.qn, src_l.q))
+        m.d.comb += src2_or_imm.eq(Mux(op_is_imm, self.imm_i, self.src2_i))
+
+        # create a latch/register for src1/src2
+        latchregister(m, self.src1_i, self.alu.a, src_l.q)
+        latchregister(m, src2_or_imm, self.alu.b, src_sel)
+
+        # -----
         # outputs
         # outputs
-        m.d.comb += self.busy_o.eq(opc_l.q) # busy out
-        m.d.comb += self.rd_rel_o.eq(src_l.q & opc_l.q) # src1/src2 req rel
+        # -----
+
+        # all request signals gated by busy_o.  prevents picker problems
+        busy_o = self.busy_o
+        m.d.comb += busy_o.eq(opc_l.q) # busy out
+        m.d.comb += self.rd_rel_o.eq(src_l.q & busy_o) # src1/src2 req rel
 
         # the counter is just for demo purposes, to get the ALUs of different
         # types to take arbitrary completion times
         with m.If(opc_l.qn):
             m.d.sync += self.counter.eq(0)
 
         # the counter is just for demo purposes, to get the ALUs of different
         # types to take arbitrary completion times
         with m.If(opc_l.qn):
             m.d.sync += self.counter.eq(0)
-        with m.If(req_l.qn & opc_l.q & (self.counter == 0)):
-            with m.If(self.oper_i == 2): # MUL, to take 5 instructions
+        with m.If(req_l.qn & busy_o & (self.counter == 0)):
+            with m.If(self.alu.op == 2): # MUL, to take 5 instructions
                 m.d.sync += self.counter.eq(5)
                 m.d.sync += self.counter.eq(5)
-            with m.Elif(self.oper_i == 3): # SHIFT to take 7
+            with m.Elif(self.alu.op == 3): # SHIFT to take 7
                 m.d.sync += self.counter.eq(7)
                 m.d.sync += self.counter.eq(7)
-            with m.Elif(self.oper_i >= 4): # Branches take 6 (to test shadow)
+            with m.Elif(self.alu.op >= 4): # Branches take 6 (to test shadow)
                 m.d.sync += self.counter.eq(6)
             with m.Else(): # ADD/SUB to take 2
                 m.d.sync += self.counter.eq(2)
                 m.d.sync += self.counter.eq(6)
             with m.Else(): # ADD/SUB to take 2
                 m.d.sync += self.counter.eq(2)
@@ -113,26 +148,32 @@ class ComputationUnitNoDelay(Elaboratable):
             m.d.sync += self.counter.eq(self.counter - 1)
         with m.If(self.counter == 1):
             # write req release out.  waits until shadow is dropped.
             m.d.sync += self.counter.eq(self.counter - 1)
         with m.If(self.counter == 1):
             # write req release out.  waits until shadow is dropped.
-            m.d.comb += self.req_rel_o.eq(req_l.q & opc_l.q & self.shadown_i)
-
-        # create a latch/register for src1/src2
-        latchregister(m, self.src1_i, self.alu.a, src_l.q)
-        latchregister(m, self.src2_i, self.alu.b, src_l.q)
-        #with m.If(src_l.qn):
-        #    m.d.comb += self.alu.op.eq(self.oper_i)
-
-        # create a latch/register for the operand
-        latchregister(m, self.oper_i, self.alu.op, src_l.q)
-
-        # and one for the output from the ALU
-        data_r = Signal(self.rwid, reset_less=True) # Dest register
-        latchregister(m, self.alu.o, data_r, req_l.q)
+            m.d.comb += self.req_rel_o.eq(req_l.q & busy_o & self.shadown_i)
 
         with m.If(self.go_wr_i):
             m.d.comb += self.data_o.eq(data_r)
 
         return m
 
 
         with m.If(self.go_wr_i):
             m.d.comb += self.data_o.eq(data_r)
 
         return m
 
+    def __iter__(self):
+        yield self.go_rd_i
+        yield self.go_wr_i
+        yield self.issue_i
+        yield self.shadown_i
+        yield self.go_die_i
+        yield self.oper_i
+        yield self.imm_i
+        yield self.src1_i
+        yield self.src2_i
+        yield self.busy_o
+        yield self.rd_rel_o
+        yield self.req_rel_o
+        yield self.data_o
+
+    def ports(self):
+        return list(self)
+
+
 def scoreboard_sim(dut):
     yield dut.dest_i.eq(1)
     yield dut.issue_i.eq(1)
 def scoreboard_sim(dut):
     yield dut.dest_i.eq(1)
     yield dut.issue_i.eq(1)
@@ -156,12 +197,14 @@ def scoreboard_sim(dut):
     yield
 
 def test_scoreboard():
     yield
 
 def test_scoreboard():
-    dut = Scoreboard(32, 8)
+    from alu_hier import ALU
+    alu = ALU(16)
+    dut = ComputationUnitNoDelay(16, 8, alu)
     vl = rtlil.convert(dut, ports=dut.ports())
     vl = rtlil.convert(dut, ports=dut.ports())
-    with open("test_scoreboard.il", "w") as f:
+    with open("test_compalu.il", "w") as f:
         f.write(vl)
 
         f.write(vl)
 
-    run_simulation(dut, scoreboard_sim(dut), vcd_name='test_scoreboard.vcd')
+    run_simulation(dut, scoreboard_sim(dut), vcd_name='test_compalu.vcd')
 
 if __name__ == '__main__':
     test_scoreboard()
 
 if __name__ == '__main__':
     test_scoreboard()