From 38124a158a732c7ea2e3d51ba67990bf8b145630 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Fri, 22 May 2020 19:19:16 +0100 Subject: [PATCH] split out Logical Input and Output stages to common code, allows removal of XER.SO from Logical pipeline --- src/soc/fu/alu/output_stage.py | 60 +++---------------- src/soc/fu/common_input_stage.py | 3 +- src/soc/fu/common_output_stage.py | 66 +++++++++++++++++++++ src/soc/fu/logical/main_stage.py | 7 +-- src/soc/fu/logical/pipe_data.py | 32 ++++++++-- src/soc/fu/logical/pipeline.py | 8 +-- src/soc/fu/logical/test/test_pipe_caller.py | 2 - 7 files changed, 111 insertions(+), 67 deletions(-) create mode 100644 src/soc/fu/common_output_stage.py diff --git a/src/soc/fu/alu/output_stage.py b/src/soc/fu/alu/output_stage.py index 8b953347..e228e871 100644 --- a/src/soc/fu/alu/output_stage.py +++ b/src/soc/fu/alu/output_stage.py @@ -2,82 +2,38 @@ # out, summary overflow generation, and updating the condition # register from nmigen import (Module, Signal, Cat, Repl) -from nmutil.pipemodbase import PipeModBase from soc.fu.alu.pipe_data import ALUInputData, ALUOutputData +from soc.fu.common_output_stage import CommonOutputStage from ieee754.part.partsig import PartitionedSignal from soc.decoder.power_enums import InternalOp -class ALUOutputStage(PipeModBase): - def __init__(self, pspec): - super().__init__(pspec, "output") +class ALUOutputStage(CommonOutputStage): def ispec(self): - return ALUOutputData(self.pspec) # TODO: ALUIntermediateData + return ALUOutputData(self.pspec) def ospec(self): return ALUOutputData(self.pspec) def elaborate(self, platform): - m = Module() + m = super().elaborate(platform) comb = m.d.comb op = self.i.ctx.op - # op requests inversion of the output - o = Signal.like(self.i.o) - with m.If(op.invert_out): - comb += o.eq(~self.i.o) - with m.Else(): - comb += o.eq(self.i.o) - - # target register if 32-bit is only the 32 LSBs - target = Signal(64, reset_less=True) - with m.If(op.is_32bit): - comb += target.eq(o[:32]) - with m.Else(): - comb += target.eq(o) - - # Handle carry_out - comb += self.o.xer_ca.data.eq(self.i.xer_ca.data) - comb += self.o.xer_ca.ok.eq(op.output_carry) - - # create condition register cr0 and sticky-overflow - is_zero = Signal(reset_less=True) - is_positive = Signal(reset_less=True) - is_negative = Signal(reset_less=True) - msb_test = Signal(reset_less=True) # set equal to MSB, invert if OP=CMP - is_cmp = Signal(reset_less=True) # true if OP=CMP - so = Signal(1, reset_less=True) + # create overflow ov = Signal(2, reset_less=True) # OV, OV32 - cr0 = Signal(4, reset_less=True) - - # TODO: if o[63] is XORed with "operand == OP_CMP" - # that can be used as a test - # see https://bugs.libre-soc.org/show_bug.cgi?id=305#c60 - comb += is_cmp.eq(op.insn_type == InternalOp.OP_CMP) - comb += msb_test.eq(target[-1] ^ is_cmp) - comb += is_zero.eq(target == 0) - comb += is_positive.eq(~is_zero & ~msb_test) - comb += is_negative.eq(~is_zero & msb_test) # XXX see https://bugs.libre-soc.org/show_bug.cgi?id=319#c5 comb += ov[0].eq(self.i.xer_so.data | self.i.xer_ov.data[0]) # OV comb += ov[1].eq(self.i.xer_so.data | self.i.xer_ov.data[1]) # OV32 XXX! - comb += so.eq(self.i.xer_so.data | self.i.xer_ov.data[0]) # OV - with m.If(op.insn_type != InternalOp.OP_CMPEQB): - comb += cr0.eq(Cat(so, is_zero, is_positive, is_negative)) - with m.Else(): - comb += cr0.eq(self.i.cr0) + comb += self.so.eq(self.i.xer_so.data | self.i.xer_ov.data[0]) # OV - # copy [inverted] cr0, output, sticky-overflow and context out - comb += self.o.o.eq(o) - comb += self.o.cr0.data.eq(cr0) - comb += self.o.cr0.ok.eq(op.rc.rc & op.rc.rc_ok) # CR0 to be set - comb += self.o.xer_so.data.eq(so) + # copy overflow and sticky-overflow + comb += self.o.xer_so.data.eq(self.so) comb += self.o.xer_so.ok.eq(op.oe.oe & op.oe.oe_ok) # SO is to be set comb += self.o.xer_ov.data.eq(ov) comb += self.o.xer_ov.ok.eq(op.oe.oe & op.oe.oe_ok) # OV/32 is to be set - comb += self.o.ctx.eq(self.i.ctx) return m diff --git a/src/soc/fu/common_input_stage.py b/src/soc/fu/common_input_stage.py index 39c56a89..2f399b49 100644 --- a/src/soc/fu/common_input_stage.py +++ b/src/soc/fu/common_input_stage.py @@ -38,7 +38,8 @@ class CommonInputStage(PipeModBase): ##### sticky overflow and context (both pass-through) ##### - comb += self.o.xer_so.eq(self.i.xer_so) + if hasattr(self.o, "xer_so"): # hack (for now - for LogicalInputData) + 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 new file mode 100644 index 00000000..3a9916a1 --- /dev/null +++ b/src/soc/fu/common_output_stage.py @@ -0,0 +1,66 @@ +# This stage is intended to handle the gating of carry out, +# and updating the condition register +from nmigen import (Module, Signal, Cat, Repl) +from nmutil.pipemodbase import PipeModBase +from ieee754.part.partsig import PartitionedSignal +from soc.decoder.power_enums import InternalOp + + +class CommonOutputStage(PipeModBase): + def __init__(self, pspec): + super().__init__(pspec, "output") + + def elaborate(self, platform): + m = Module() + comb = m.d.comb + op = self.i.ctx.op + + # op requests inversion of the output + o = Signal.like(self.i.o) + with m.If(op.invert_out): + comb += o.eq(~self.i.o) + with m.Else(): + comb += o.eq(self.i.o) + + # target register if 32-bit is only the 32 LSBs + target = Signal(64, reset_less=True) + with m.If(op.is_32bit): + comb += target.eq(o[:32]) + with m.Else(): + comb += target.eq(o) + + # Handle carry_out + comb += self.o.xer_ca.data.eq(self.i.xer_ca.data) + comb += self.o.xer_ca.ok.eq(op.output_carry) + + # create condition register cr0 and sticky-overflow + is_zero = Signal(reset_less=True) + is_positive = Signal(reset_less=True) + is_negative = Signal(reset_less=True) + msb_test = Signal(reset_less=True) # set equal to MSB, invert if OP=CMP + is_cmp = Signal(reset_less=True) # true if OP=CMP + self.so = Signal(1, reset_less=True) + cr0 = Signal(4, reset_less=True) + + # TODO: if o[63] is XORed with "operand == OP_CMP" + # that can be used as a test + # see https://bugs.libre-soc.org/show_bug.cgi?id=305#c60 + + comb += is_cmp.eq(op.insn_type == InternalOp.OP_CMP) + comb += msb_test.eq(target[-1] ^ is_cmp) + comb += is_zero.eq(target == 0) + comb += is_positive.eq(~is_zero & ~msb_test) + comb += is_negative.eq(~is_zero & msb_test) + + with m.If(op.insn_type != InternalOp.OP_CMPEQB): + comb += cr0.eq(Cat(self.so, is_zero, is_positive, is_negative)) + with m.Else(): + comb += cr0.eq(self.i.cr0) + + # copy out [inverted] cr0, output, and context out + comb += self.o.o.eq(o) + comb += self.o.cr0.data.eq(cr0) + comb += self.o.cr0.ok.eq(op.rc.rc & op.rc.rc_ok) # CR0 to be set + comb += self.o.ctx.eq(self.i.ctx) + + return m diff --git a/src/soc/fu/logical/main_stage.py b/src/soc/fu/logical/main_stage.py index 8c3703e6..b40c91fd 100644 --- a/src/soc/fu/logical/main_stage.py +++ b/src/soc/fu/logical/main_stage.py @@ -10,7 +10,7 @@ from nmutil.pipemodbase import PipeModBase from nmutil.clz import CLZ from soc.fu.logical.pipe_data import LogicalInputData from soc.fu.logical.bpermd import Bpermd -from soc.fu.alu.pipe_data import ALUOutputData +from soc.fu.logical.pipe_data import LogicalOutputData from ieee754.part.partsig import PartitionedSignal from soc.decoder.power_enums import InternalOp @@ -36,7 +36,7 @@ class LogicalMainStage(PipeModBase): return LogicalInputData(self.pspec) def ospec(self): - return ALUOutputData(self.pspec) # TODO: ALUIntermediateData + return LogicalOutputData(self.pspec) def elaborate(self, platform): m = Module() @@ -135,9 +135,8 @@ class LogicalMainStage(PipeModBase): comb += bpermd.rb.eq(b) comb += o.eq(bpermd.ra) - ###### sticky overflow and context, both pass-through ##### + ###### context, 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/pipe_data.py b/src/soc/fu/logical/pipe_data.py index 332fd60e..9ded5f4a 100644 --- a/src/soc/fu/logical/pipe_data.py +++ b/src/soc/fu/logical/pipe_data.py @@ -1,6 +1,7 @@ from nmigen import Signal, Const from ieee754.fpcommon.getop import FPPipeContext from soc.fu.pipe_data import IntegerData +from soc.decoder.power_decoder2 import Data from soc.fu.alu.pipe_data import ALUOutputData, CommonPipeSpec from soc.fu.logical.logical_input_record import CompLogicalOpSubset @@ -8,13 +9,11 @@ from soc.fu.logical.logical_input_record import CompLogicalOpSubset class LogicalInputData(IntegerData): regspec = [('INT', 'a', '0:63'), ('INT', 'rb', '0:63'), - ('XER', 'xer_so', '32'), ('XER', 'xer_ca', '34,45')] def __init__(self, pspec): super().__init__(pspec) self.a = Signal(64, reset_less=True) # RA self.b = Signal(64, reset_less=True) # RB/immediate - self.xer_so = Signal(reset_less=True) # XER bit 32: SO self.xer_ca = Signal(2, reset_less=True) # XER bit 34/45: CA/CA32 def __iter__(self): @@ -22,15 +21,40 @@ class LogicalInputData(IntegerData): yield self.a yield self.b yield self.xer_ca - yield self.xer_so def eq(self, i): lst = super().eq(i) return lst + [self.a.eq(i.a), self.b.eq(i.b), + self.xer_ca.eq(i.xer_ca) ] + + +class LogicalOutputData(IntegerData): + regspec = [('INT', 'o', '0:63'), + ('CR', 'cr0', '0:3'), + ('XER', 'xer_ca', '34,45'), + ('XER', 'xer_so', '32')] + def __init__(self, pspec): + super().__init__(pspec) + self.o = Signal(64, reset_less=True, name="stage_o") + self.cr0 = Data(4, name="cr0") + self.xer_ca = Data(2, name="xer_co") # bit0: ca, bit1: ca32 + self.xer_so = Data(1, name="xer_so") + + def __iter__(self): + yield from super().__iter__() + yield self.o + yield self.xer_ca + yield self.cr0 + yield self.xer_so + + def eq(self, i): + lst = super().eq(i) + return lst + [self.o.eq(i.o), self.xer_ca.eq(i.xer_ca), + self.cr0.eq(i.cr0), self.xer_so.eq(i.xer_so)] class LogicalPipeSpec(CommonPipeSpec): - regspec = (LogicalInputData.regspec, ALUOutputData.regspec) + regspec = (LogicalInputData.regspec, LogicalOutputData.regspec) opsubsetkls = CompLogicalOpSubset diff --git a/src/soc/fu/logical/pipeline.py b/src/soc/fu/logical/pipeline.py index 1a2fd1fc..4ae1d1d4 100644 --- a/src/soc/fu/logical/pipeline.py +++ b/src/soc/fu/logical/pipeline.py @@ -1,14 +1,14 @@ from nmutil.singlepipe import ControlBase from nmutil.pipemodbase import PipeModBaseChain -from soc.fu.alu.input_stage import ALUInputStage +from soc.fu.logical.input_stage import LogicalInputStage from soc.fu.logical.main_stage import LogicalMainStage -from soc.fu.alu.output_stage import ALUOutputStage +from soc.fu.logical.output_stage import LogicalOutputStage class LogicalStages(PipeModBaseChain): def get_chain(self): - inp = ALUInputStage(self.pspec) + inp = LogicalInputStage(self.pspec) main = LogicalMainStage(self.pspec) - out = ALUOutputStage(self.pspec) + out = LogicalOutputStage(self.pspec) return [inp, main, out] diff --git a/src/soc/fu/logical/test/test_pipe_caller.py b/src/soc/fu/logical/test/test_pipe_caller.py index 073aad72..adf0c4cc 100644 --- a/src/soc/fu/logical/test/test_pipe_caller.py +++ b/src/soc/fu/logical/test/test_pipe_caller.py @@ -61,8 +61,6 @@ def set_extra_alu_inputs(alu, dec2, sim): carry32 = 1 if sim.spr['XER'][XER_bits['CA32']] else 0 yield alu.p.data_i.xer_ca[0].eq(carry) yield alu.p.data_i.xer_ca[1].eq(carry32) - so = 1 if sim.spr['XER'][XER_bits['SO']] else 0 - yield alu.p.data_i.xer_so.eq(so) # This test bench is a bit different than is usual. Initially when I -- 2.30.2