add in write-mask into MultiCompUnit and MCU-ALU unit test: bug detected in
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 30 May 2020 19:37:10 +0000 (20:37 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 30 May 2020 19:37:13 +0000 (20:37 +0100)
RC handling

src/soc/experiment/compalu_multi.py
src/soc/fu/compunits/test/test_alu_compunit.py
src/soc/fu/regspec.py

index d143bebc8187fb7e59fa8fa72cc413665072f9fe..d41fdd64f00bac3890cdb909eb836cda22c0a909 100644 (file)
@@ -23,6 +23,15 @@ from soc.decoder.power_enums import InternalOp
 from soc.fu.regspec import RegSpec, RegSpecALUAPI
 
 
+def find_ok(fields):
+    """find_ok helper function - finds field ending in "_ok"
+    """
+    for field_name in fields:
+        if field_name.endswith("_ok"):
+            return field_name
+    return None
+
+
 def go_record(n, name):
     r = Record([('go', n, DIR_FANIN),
                 ('rel', n, DIR_FANOUT)], name=name)
@@ -30,6 +39,7 @@ def go_record(n, name):
     r.rel.reset_less = True
     return r
 
+
 # see https://libre-soc.org/3d_gpu/architecture/regfile/ section on regspecs
 
 class CompUnitRecord(RegSpec, RecordObject):
@@ -83,6 +93,7 @@ class CompUnitRecord(RegSpec, RecordObject):
         self.rd = go_record(n_src, name="rd") # read in, req out
         self.wr = go_record(n_dst, name="wr") # write in, req out
         self.rdmaskn = Signal(n_src, reset_less=True) # read mask
+        self.wrmask = Signal(n_dst, reset_less=True) # write mask
         self.issue_i = Signal(reset_less=True) # fn issue in
         self.shadown_i = Signal(reset=1) # shadow function, defaults to ON
         self.go_die_i = Signal() # go die (reset)
@@ -124,6 +135,7 @@ class MultiCompUnit(RegSpecALUAPI, Elaboratable):
         self.rd = cu.rd
         self.wr = cu.wr
         self.rdmaskn = cu.rdmaskn
+        self.wrmask = cu.wrmask
         self.go_rd_i = self.rd.go # temporary naming
         self.go_wr_i = self.wr.go # temporary naming
         self.rd_rel_o = self.rd.rel # temporary naming
@@ -238,8 +250,11 @@ class MultiCompUnit(RegSpecALUAPI, Elaboratable):
             ok = Const(1, 1)
             if isinstance(lro, Record):
                 data_r = Record.like(lro, name=name)
-                if hasattr(data_r, "ok"): # bye-bye abstract interface design..
-                    ok = data_r.ok
+                print ("wr fields", i, lro, data_r.fields)
+                # bye-bye abstract interface design..
+                fname = find_ok(data_r.fields)
+                if fname:
+                    ok = data_r[fname]
             else:
                 data_r = Signal.like(lro, name=name, reset_less=True)
             wrok.append(ok)
@@ -250,8 +265,7 @@ class MultiCompUnit(RegSpecALUAPI, Elaboratable):
         # now actually use those to create a write-mask.  this basically
         # is now the Function Unit API tells the Comp Unit "do not request
         # a regfile port because this particular output is not valid"
-        wrmask = Signal(self.n_dst, reset_less=True)
-        m.d.comb += wrmask.eq(Cat(*wrok))
+        m.d.comb += self.wrmask.eq(Cat(*wrok))
 
         # pass the operation to the ALU
         m.d.comb += self.get_op().eq(oper_r)
@@ -318,7 +332,7 @@ class MultiCompUnit(RegSpecALUAPI, Elaboratable):
 
         # write-release gated by busy and by shadow (and write-mask)
         brd = Repl(self.busy_o & self.shadown_i, self.n_dst)
-        m.d.comb += self.wr.rel.eq(req_l.q & brd & wrmask)
+        m.d.comb += self.wr.rel.eq(req_l.q & brd & self.wrmask)
 
         # output the data from the latch on go_write
         for i in range(self.n_dst):
index 0412ccf00cc388d12a7eef6fae659c6666b7270b..b0739bc1b9feb5db33f4feb25c124c1015e4f2f4 100644 (file)
@@ -13,6 +13,7 @@ from soc.decoder.isa.all import ISA
 
 from soc.fu.alu.test.test_pipe_caller import TestCase, ALUTestCase, test_data
 from soc.fu.compunits.compunits import ALUFunctionUnit
+from soc.experiment.compalu_multi import find_ok # hack
 import random
 
 def set_cu_input(cu, idx, data):
@@ -34,7 +35,17 @@ def set_cu_input(cu, idx, data):
     yield cu.rd.go[idx].eq(0)
 
 
-def get_cu_output(cu, idx):
+def get_cu_output(cu, idx, code):
+    wrmask = yield cu.wrmask
+    wrop = cu.get_out_name(idx)
+    wrok = cu.get_out(idx)
+    fname = find_ok(wrok.fields)
+    wrok = yield getattr(wrok, fname)
+    print ("wr_rel mask", repr(code), idx, wrop, bin(wrmask), fname, wrok)
+    assert wrmask & (1<<idx), \
+            "get_cu_output '%s': mask bit %d not set\n" \
+            "write-operand '%s' Data.ok likely not set (%s)" \
+            % (code, idx, wrop, hex(wrok))
     while True:
         wr_relall_o = yield cu.wr.rel
         wr_rel_o = yield cu.wr.rel[idx]
@@ -174,8 +185,9 @@ class TestRunner(FHDLTestCase):
                     yield
                     rd_rel_o = yield cu.rd.rel
                     wr_rel_o = yield cu.wr.rel
-                    print ("after inputs, rd_rel, wr_rel: ",
-                            bin(rd_rel_o), bin(wr_rel_o))
+                    wrmask = yield cu.wrmask
+                    print ("after inputs, rd_rel, wr_rel, wrmask: ",
+                            bin(rd_rel_o), bin(wr_rel_o), bin(wrmask))
                     opname = code.split(' ')[0]
                     yield from sim.call(opname)
                     index = sim.pc.CIA.value//4
@@ -187,7 +199,7 @@ class TestRunner(FHDLTestCase):
                     if out_reg_valid:
                         write_reg_idx = yield pdecode2.e.write_reg.data
                         expected = sim.gpr(write_reg_idx).value
-                        cu_out = yield from get_cu_output(cu, 0)
+                        cu_out = yield from get_cu_output(cu, 0, code)
                         print(f"expected {expected:x}, actual: {cu_out:x}")
                         self.assertEqual(expected, cu_out, code)
                     yield
@@ -203,7 +215,7 @@ class TestRunner(FHDLTestCase):
                             wr_rel_o = yield cu.wr.rel[i]
                             if wr_rel_o:
                                 print ("discard output", i)
-                                discard = yield from get_cu_output(cu, i)
+                                discard = yield from get_cu_output(cu, i, code)
                         yield
 
         sim.add_sync_process(process)
@@ -218,7 +230,7 @@ class TestRunner(FHDLTestCase):
         if rc or \
            op == InternalOp.OP_CMP.value or \
            op == InternalOp.OP_CMPEQB.value:
-            cr_actual = yield from get_cu_output(cu, 1)
+            cr_actual = yield from get_cu_output(cu, 1, code)
 
         if rc:
             cr_expected = sim.crl[0].get_range().value
@@ -233,15 +245,15 @@ class TestRunner(FHDLTestCase):
         cry_out = yield dec2.e.output_carry
         if cry_out:
             expected_carry = 1 if sim.spr['XER'][XER_bits['CA']] else 0
-            xer_ca = yield from get_cu_output(cu, 2)
+            xer_ca = yield from get_cu_output(cu, 2, code)
             real_carry = xer_ca & 0b1 # XXX CO not CO32
             self.assertEqual(expected_carry, real_carry, code)
             expected_carry32 = 1 if sim.spr['XER'][XER_bits['CA32']] else 0
             real_carry32 = bool(xer_ca & 0b10) # XXX CO32
             self.assertEqual(expected_carry32, real_carry32, code)
 
-        xer_ov = yield from get_cu_output(cu, 3)
-        xer_so = yield from get_cu_output(cu, 4)
+        xer_ov = yield from get_cu_output(cu, 3, code)
+        xer_so = yield from get_cu_output(cu, 4, code)
 
 
 if __name__ == "__main__":
index e7a4cf8e3d88936f0aba3c6b550a943aaab1d692..a729dce03102232aafb3eec78ade548c520d67f7 100644 (file)
@@ -65,17 +65,23 @@ class RegSpecALUAPI:
         self.rwid = rwid
         self.alu = alu # actual ALU - set as a "submodule" of the CU
 
+    def get_in_name(self, i):
+        return self.rwid[0][i][1]
+
+    def get_out_name(self, i):
+        return self.rwid[1][i][1]
+
     def get_out(self, i):
         if isinstance(self.rwid, int): # old - testing - API (rwid is int)
             return self.alu.out[i]
         # regspec-based API: look up variable through regspec thru row number
-        return getattr(self.alu.n.data_o, self.rwid[1][i][1])
+        return getattr(self.alu.n.data_o, self.get_out_name(i))
 
     def get_in(self, i):
         if isinstance(self.rwid, int): # old - testing - API (rwid is int)
             return self.alu.i[i]
         # regspec-based API: look up variable through regspec thru row number
-        return getattr(self.alu.p.data_i, self.rwid[0][i][1])
+        return getattr(self.alu.p.data_i, self.get_in_name(i))
 
     def get_op(self):
         if isinstance(self.rwid, int): # old - testing - API (rwid is int)