From cd088b785ee6e4a9fd9e5c1b87c63a13e9e7386b Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Wed, 26 Aug 2020 18:59:47 +0100 Subject: [PATCH] reorg of SO handling related to CR0 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 | 10 +++---- src/soc/fu/common_input_stage.py | 3 +- src/soc/fu/common_output_stage.py | 10 +++++-- src/soc/fu/logical/main_stage.py | 3 +- src/soc/fu/logical/output_stage.py | 5 ++-- src/soc/fu/logical/pipe_data.py | 19 ++++++++++-- src/soc/fu/logical/test/test_pipe_caller.py | 33 +++++++++++++++++++++ src/soc/fu/test/common.py | 11 +++---- 8 files changed, 75 insertions(+), 19 deletions(-) diff --git a/src/soc/fu/alu/output_stage.py b/src/soc/fu/alu/output_stage.py index e7d1c673..44c90a37 100644 --- a/src/soc/fu/alu/output_stage.py +++ b/src/soc/fu/alu/output_stage.py @@ -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 diff --git a/src/soc/fu/common_input_stage.py b/src/soc/fu/common_input_stage.py index 238c8d57..e36b14db 100644 --- a/src/soc/fu/common_input_stage.py +++ b/src/soc/fu/common_input_stage.py @@ -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 diff --git a/src/soc/fu/common_output_stage.py b/src/soc/fu/common_output_stage.py index cc0f00a3..530db3ac 100644 --- a/src/soc/fu/common_output_stage.py +++ b/src/soc/fu/common_output_stage.py @@ -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" diff --git a/src/soc/fu/logical/main_stage.py b/src/soc/fu/logical/main_stage.py index d6ae4a2f..c9cc4c86 100644 --- a/src/soc/fu/logical/main_stage.py +++ b/src/soc/fu/logical/main_stage.py @@ -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 diff --git a/src/soc/fu/logical/output_stage.py b/src/soc/fu/logical/output_stage.py index a985511f..4a6694a8 100644 --- a/src/soc/fu/logical/output_stage.py +++ b/src/soc/fu/logical/output_stage.py @@ -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) diff --git a/src/soc/fu/logical/pipe_data.py b/src/soc/fu/logical/pipe_data.py index 82092b47..42a31ca1 100644 --- a/src/soc/fu/logical/pipe_data.py +++ b/src/soc/fu/logical/pipe_data.py @@ -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 diff --git a/src/soc/fu/logical/test/test_pipe_caller.py b/src/soc/fu/logical/test/test_pipe_caller.py index 8af95ead..794e9fcd 100644 --- a/src/soc/fu/logical/test/test_pipe_caller.py +++ b/src/soc/fu/logical/test/test_pipe_caller.py @@ -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) diff --git a/src/soc/fu/test/common.py b/src/soc/fu/test/common.py index d1473b05..2ced9569 100644 --- a/src/soc/fu/test/common.py +++ b/src/soc/fu/test/common.py @@ -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: -- 2.30.2