reorg of SO handling related to CR0
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 26 Aug 2020 17:59:47 +0000 (18:59 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 27 Aug 2020 12:23:09 +0000 (13:23 +0100)
because CR0 needs XER SO, logical pipe needs to read but not write SO
this means quite a substantial but relatively straightforward change
in the pipe_data for logical and ALU

src/soc/fu/alu/output_stage.py
src/soc/fu/common_input_stage.py
src/soc/fu/common_output_stage.py
src/soc/fu/logical/main_stage.py
src/soc/fu/logical/output_stage.py
src/soc/fu/logical/pipe_data.py
src/soc/fu/logical/test/test_pipe_caller.py
src/soc/fu/test/common.py

index e7d1c673c0d80685700e6f37d265bed13afbb4c7..44c90a375b69882505ceb5744de146295210133a 100644 (file)
@@ -21,6 +21,7 @@ class ALUOutputStage(CommonOutputStage):
         comb = m.d.comb
         op = self.i.ctx.op
         xer_so_i, xer_ov_i = self.i.xer_so.data, self.i.xer_ov.data
+        xer_so_o, xer_ov_o = self.o.xer_so, self.o.xer_ov
 
         # copy overflow and sticky-overflow.  indicate to CompALU if they
         # are actually required (oe enabled/set) otherwise the CompALU
@@ -29,10 +30,9 @@ class ALUOutputStage(CommonOutputStage):
         comb += oe.eq(op.oe.oe & op.oe.oe_ok)
         with m.If(oe):
             # XXX see https://bugs.libre-soc.org/show_bug.cgi?id=319#c5
-            comb += self.so.eq(xer_so_i[0] | xer_ov_i[0]) # SO
-            comb += self.o.xer_so.data.eq(self.so)
-            comb += self.o.xer_so.ok.eq(1)
-            comb += self.o.xer_ov.data.eq(xer_ov_i)
-            comb += self.o.xer_ov.ok.eq(1) # OV/32 is to be set
+            comb += xer_so_o.data.eq(xer_so_i[0] | xer_ov_i[0]) # SO
+            comb += xer_so_o.ok.eq(1)
+            comb += xer_ov_o.data.eq(xer_ov_i)
+            comb += xer_ov_o.ok.eq(1) # OV/32 is to be set
 
         return m
index 238c8d57a9dec7907d497701597f01e419d90ebb..e36b14db340905cdf097cd084f1f3e9a0a6ca007 100644 (file)
@@ -66,8 +66,7 @@ class CommonInputStage(PipeModBase):
         ##### sticky overflow and context (both pass-through) #####
 
         if hasattr(self.o, "xer_so"): # hack (for now - for LogicalInputData)
-            with m.If(op.oe.oe_ok):
-                comb += self.o.xer_so.eq(self.i.xer_so)
+            comb += self.o.xer_so.eq(self.i.xer_so)
         comb += self.o.ctx.eq(self.i.ctx)
 
         return m
index cc0f00a38063df1ee54b3dfdd2c1cbf758b3bf3a..530db3ac0120fe2dd2bd28b493405378c1619df4 100644 (file)
@@ -14,10 +14,17 @@ class CommonOutputStage(PipeModBase):
         m = Module()
         comb = m.d.comb
         op = self.i.ctx.op
+        # ok so there are two different ways this goes:
+        # (1) something involving XER ov in which case so gets modified
+        #     and that means we need the modified version of so in CR0
+        # (2) something that does *not* have XER ov, in which case so
+        #     has been pass-through just to get it into CR0
+        # in case (1) we don't *have* an xer_so output so put xer_so *input*
+        # into CR0.
         if hasattr(self.o, "xer_so"):
             xer_so_o = self.o.xer_so.data[0]
         else:
-            xer_so_o = Const(0, 1)
+            xer_so_o = self.i.xer_so.data[0]
 
         # op requests inversion of the output...
         o = Signal.like(self.i.o)
@@ -53,7 +60,6 @@ class CommonOutputStage(PipeModBase):
         msb_test = Signal(reset_less=True) # set equal to MSB, invert if OP=CMP
         is_cmp = Signal(reset_less=True)     # true if OP=CMP
         is_cmpeqb = Signal(reset_less=True)  # true if OP=CMPEQB
-        self.so = Signal(1, reset_less=True)
         cr0 = Signal(4, reset_less=True)
 
         # TODO: if o[63] is XORed with "operand == OP_CMP"
index d6ae4a2f9e4dc0c33c95183c438190443fc69973..c9cc4c869248cc4320b3e2e5f11d6f3c0d5ebb46 100644 (file)
@@ -123,8 +123,9 @@ class LogicalMainStage(PipeModBase):
             with m.Default():
                 comb += o.ok.eq(0)
 
-        ###### context, pass-through #####
+        ###### sticky overflow and context, both pass-through #####
 
+        comb += self.o.xer_so.data.eq(self.i.xer_so)
         comb += self.o.ctx.eq(self.i.ctx)
 
         return m
index a985511f75823b6bc7ac374a0299693ca91b9efd..4a6694a851886f6fcd3d39562233088165b5fd59 100644 (file)
@@ -4,7 +4,8 @@
 from nmigen import (Module, Signal, Cat, Repl)
 from nmutil.pipemodbase import PipeModBase
 from soc.fu.common_output_stage import CommonOutputStage
-from soc.fu.logical.pipe_data import LogicalInputData, LogicalOutputData
+from soc.fu.logical.pipe_data import (LogicalInputData, LogicalOutputData,
+                                      LogicalOutputDataFinal)
 from ieee754.part.partsig import PartitionedSignal
 from soc.decoder.power_enums import MicrOp
 
@@ -15,5 +16,5 @@ class LogicalOutputStage(CommonOutputStage):
         return LogicalOutputData(self.pspec)
 
     def ospec(self):
-        return LogicalOutputData(self.pspec)
+        return LogicalOutputDataFinal(self.pspec)
 
index 82092b4707bdbda1ca8a7f8bc865b0fb863400ce..42a31ca10a89a473932cf5de16ab54234a76ffd0 100644 (file)
@@ -3,9 +3,11 @@ from soc.fu.alu.pipe_data import ALUOutputData, CommonPipeSpec
 from soc.fu.logical.logical_input_record import CompLogicalOpSubset
 
 
+# input (and output) for logical initial stage (common input)
 class LogicalInputData(IntegerData):
     regspec = [('INT', 'ra', '0:63'), # RA
                ('INT', 'rb', '0:63'), # RB/immediate
+               ('XER', 'xer_so', '32'),    # bit0: so
                ]
     def __init__(self, pspec):
         super().__init__(pspec, False)
@@ -13,10 +15,23 @@ class LogicalInputData(IntegerData):
         self.a, self.b = self.ra, self.rb
 
 
+# input to logical final stage (common output)
 class LogicalOutputData(IntegerData):
     regspec = [('INT', 'o', '0:63'),        # RT
                ('CR', 'cr_a', '0:3'),
-               ('XER', 'xer_ca', '34,45'), # bit0: ca, bit1: ca32
+               ('XER', 'xer_so', '32'),    # bit0: so
+               ]
+    def __init__(self, pspec):
+        super().__init__(pspec, True)
+        # convenience
+        self.cr0 = self.cr_a
+
+
+# output from logical final stage (common output) - note that XER.so
+# is *not* included (the only reason it's in the input is because of CR0)
+class LogicalOutputDataFinal(IntegerData):
+    regspec = [('INT', 'o', '0:63'),        # RT
+               ('CR', 'cr_a', '0:3'),
                ]
     def __init__(self, pspec):
         super().__init__(pspec, True)
@@ -25,5 +40,5 @@ class LogicalOutputData(IntegerData):
 
 
 class LogicalPipeSpec(CommonPipeSpec):
-    regspec = (LogicalInputData.regspec, LogicalOutputData.regspec)
+    regspec = (LogicalInputData.regspec, LogicalOutputDataFinal.regspec)
     opsubsetkls = CompLogicalOpSubset
index 8af95ead98932cc8533de53010fc38b9a66984e1..794e9fcdaaa53b10690d389f0775e715df520274 100644 (file)
@@ -26,6 +26,9 @@ def get_cu_inputs(dec2, sim):
 
     yield from ALUHelpers.get_sim_int_ra(res, sim, dec2)  # RA
     yield from ALUHelpers.get_sim_int_rb(res, sim, dec2)  # RB
+    yield from ALUHelpers.get_sim_xer_so(res, sim, dec2)  # XER.so
+
+    print("alu get_cu_inputs", res)
 
     return res
 
@@ -36,8 +39,10 @@ def set_alu_inputs(alu, dec2, sim):
     # and place it into data_i.b
 
     inp = yield from get_cu_inputs(dec2, sim)
+    print ("set alu inputs", inp)
     yield from ALUHelpers.set_int_ra(alu, dec2, inp)
     yield from ALUHelpers.set_int_rb(alu, dec2, inp)
+    yield from ALUHelpers.set_xer_so(alu, dec2, inp)
 
 
 # This test bench is a bit different than is usual. Initially when I
@@ -81,6 +86,33 @@ class LogicalTestCase(TestAccumulatorBase):
             initial_regs[2] = random.randint(0, (1 << 64)-1)
             self.add_case(Program(lst, bigendian), initial_regs)
 
+    def case_rand_(self):
+        insns = ["and.", "or.", "xor.", "eqv.", "andc.",
+                 "orc.", "nand.", "nor."]
+        for XER in [0, 0xe00c0000]:
+            for i in range(40):
+                choice = random.choice(insns)
+                lst = [f"{choice} 3, 1, 2"]
+                initial_regs = [0] * 32
+                initial_regs[1] = random.randint(0, (1 << 64)-1)
+                initial_regs[2] = random.randint(0, (1 << 64)-1)
+                self.add_case(Program(lst, bigendian), initial_regs,
+                                initial_sprs = {'XER': XER})
+
+    def case_rand_imm_so(self):
+        insns = ["andi.", "andis."]
+        for i in range(1):
+            choice = random.choice(insns)
+            imm = random.randint(0, (1 << 16)-1)
+            lst = [f"{choice} 3, 1, {imm}"]
+            print(lst)
+            initial_regs = [0] * 32
+            initial_regs[1] = random.randint(0, (1 << 64)-1)
+            initial_sprs = {'XER': 0xe00c0000}
+
+            self.add_case(Program(lst, bigendian), initial_regs,
+                          initial_sprs=initial_sprs)
+
     def case_rand_imm_logical(self):
         insns = ["andi.", "andis.", "ori", "oris", "xori", "xoris"]
         for i in range(10):
@@ -253,6 +285,7 @@ class TestRunner(FHDLTestCase):
         yield from ALUHelpers.get_wr_sim_cr_a(sim_o, sim, dec2)
 
         ALUHelpers.check_cr_a(self, res, sim_o, "CR%d %s" % (cridx, code))
+        ALUHelpers.check_xer_ca(self, res, sim_o, code)
         ALUHelpers.check_int_o(self, res, sim_o, code)
 
 
index d1473b052a1e7567495f5087aa1a58937f07b192..2ced9569aa8a69979aeaa72bbfc1882263f70511 100644 (file)
@@ -438,11 +438,12 @@ class ALUHelpers:
             res['xer_ov'] = expected_ov | (expected_ov32 << 1)
 
     def get_sim_xer_so(res, sim, dec2):
-        oe = yield dec2.e.do.oe.oe
-        oe_ok = yield dec2.e.do.oe.ok
-        xer_in = yield dec2.e.xer_in
-        if xer_in or (oe and oe_ok):
-            res['xer_so'] = 1 if sim.spr['XER'][XER_bits['SO']] else 0
+        yield
+        #oe = yield dec2.e.do.oe.oe
+        #oe_ok = yield dec2.e.do.oe.ok
+        #xer_in = yield dec2.e.xer_in
+        #if xer_in or (oe and oe_ok):
+        res['xer_so'] = 1 if sim.spr['XER'][XER_bits['SO']] else 0
 
     def check_slow_spr1(dut, res, sim_o, msg):
         if 'spr1' in res: