working on adding rest of stage classes for div pipeline
authorJacob Lifshay <programmerjake@gmail.com>
Thu, 18 Jun 2020 02:56:07 +0000 (19:56 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Thu, 18 Jun 2020 02:56:07 +0000 (19:56 -0700)
src/soc/fu/div/core_stages.py [new file with mode: 0644]
src/soc/fu/div/output_stage.py [new file with mode: 0644]
src/soc/fu/div/pipe_data.py
src/soc/fu/div/setup_stage.py

diff --git a/src/soc/fu/div/core_stages.py b/src/soc/fu/div/core_stages.py
new file mode 100644 (file)
index 0000000..cc4e6f7
--- /dev/null
@@ -0,0 +1,68 @@
+# This stage is the setup stage that converts the inputs
+# into the values expected by DivPipeCore
+
+from nmigen import (Module, Signal, Cat, Repl, Mux, Const, Array)
+from nmutil.pipemodbase import PipeModBase
+from soc.fu.logical.pipe_data import LogicalInputData
+from soc.fu.alu.pipe_data import ALUOutputData
+from ieee754.part.partsig import PartitionedSignal
+from soc.decoder.power_enums import InternalOp
+
+from soc.decoder.power_fields import DecodeFields
+from soc.decoder.power_fieldsn import SignalBitRange
+from soc.fu.div.pipe_data import CoreInputData, CoreInterstageData, CoreOutputData
+from ieee754.div_rem_sqrt_rsqrt.core import (DivPipeCoreSetupStage,
+                                             DivPipeCoreCalculateStage,
+                                             DivPipeCoreFinalStage)
+
+
+class DivCoreBaseStage(PipeModBase):
+    def __init__(self, pspec, modname, core_class, *args, **kwargs):
+        super().__init__(pspec, modname)
+        self.core = core_class(pspec.core_config, *args, **kwargs)
+
+    def elaborate(self, platform):
+        m = Module()
+
+        m.d.comb += self.o.eq_without_core(self.i)
+
+        m.submodules.core = self.core
+
+        m.d.comb += self.core.i.eq(self.i.core)
+        m.d.comb += self.o.core.eq(self.core.o)
+
+        return m
+
+
+class DivCoreSetupStage(DivCoreBaseStage):
+    def __init__(self, pspec):
+        super().__init__(pspec, "core_setup_stage", DivPipeCoreSetupStage)
+
+    def ispec(self):
+        return CoreInputData(self.pspec)
+
+    def ospec(self):
+        return CoreInterstageData(self.pspec)
+
+
+class DivCoreCalculateStage(DivCoreBaseStage):
+    def __init__(self, pspec, stage_index):
+        super().__init__(pspec, f"core_calculate_stage_{stage_index}",
+                         DivPipeCoreCalculateStage, stage_index)
+
+    def ispec(self):
+        return CoreInterstageData(self.pspec)
+
+    def ospec(self):
+        return CoreInterstageData(self.pspec)
+
+
+class DivCoreFinalStage(DivCoreBaseStage):
+    def __init__(self, pspec):
+        super().__init__(pspec, "core_final_stage", DivPipeCoreFinalStage)
+
+    def ispec(self):
+        return CoreInterstageData(self.pspec)
+
+    def ospec(self):
+        return CoreOutputData(self.pspec)
diff --git a/src/soc/fu/div/output_stage.py b/src/soc/fu/div/output_stage.py
new file mode 100644 (file)
index 0000000..eb4461e
--- /dev/null
@@ -0,0 +1,104 @@
+# This stage is the setup stage that converts the inputs
+# into the values expected by DivPipeCore
+
+from nmigen import (Module, Signal, Cat, Repl, Mux, Const, Array)
+from nmutil.pipemodbase import PipeModBase
+from soc.fu.logical.pipe_data import LogicalInputData
+from soc.fu.alu.pipe_data import ALUOutputData
+from ieee754.part.partsig import PartitionedSignal
+from soc.decoder.power_enums import InternalOp
+
+from soc.decoder.power_fields import DecodeFields
+from soc.decoder.power_fieldsn import SignalBitRange
+from soc.fu.div.pipe_data import CoreOutputData
+
+
+class DivOutputStage(PipeModBase):
+    def __init__(self, pspec):
+        super().__init__(pspec, "output_stage")
+        self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
+        self.fields.create_specs()
+        self.quotient_neg = Signal()
+        self.remainder_neg = Signal()
+        self.quotient_64 = Signal(64)
+        self.remainder_64 = Signal(64)
+
+    def ispec(self):
+        return CoreOutputData(self.pspec)
+
+    def ospec(self):
+        return ALUOutputData(self.pspec)
+
+    def elaborate(self, platform):
+        m = Module()
+        comb = m.d.comb
+        op = self.i.ctx.op
+        abs_quotient = self.i.core.quotient_root
+        fract_width = self.pspec.core_config.fract_width
+        # fract width of `DivPipeCoreOutputData.remainder`
+        remainder_fract_width = fract_width * 3
+        # fract width of `DivPipeCoreInputData.dividend`
+        dividend_fract_width = fract_width * 2
+        rem_start = remainder_fract_width - dividend_fract_width
+        abs_remainder = self.i.core.remainder[rem_start:rem_start+64]
+        dividend_neg = self.i.dividend_neg
+        divisor_neg = self.i.divisor_neg
+        quotient_64 = self.quotient_64
+        remainder_64 = self.remainder_64
+
+        comb += self.quotient_neg.eq(dividend_neg ^ divisor_neg)
+        # follows rules for truncating division
+        comb += self.remainder_neg.eq(dividend_neg)
+
+        # negation of a 64-bit value produces the same lower 32-bit
+        # result as negation of just the lower 32-bits, so we don't
+        # need to do anything special before negating
+        comb += [
+            quotient_64.eq(Mux(self.quotient_neg,
+                               -abs_quotient, abs_quotient)),
+            remainder_64.eq(Mux(self.remainder_neg,
+                                -abs_remainder, abs_remainder))
+        ]
+
+        xer_ov = self.o.xer_ov.data
+
+        # TODO(programmerjake): check code against instruction models
+
+        def calc_overflow(dive_abs_overflow, sign_bit_mask):
+            nonlocal comb
+            overflow = dive_abs_overflow | self.i.div_by_zero
+            with m.If(op.is_signed):
+                comb += xer_ov.eq(overflow
+                                  | (abs_quotient > sign_bit_mask)
+                                  | ((abs_quotient == sign_bit_mask)
+                                     & ~self.quotient_neg))
+            with m.Else():
+                comb += xer_ov.eq(overflow)
+
+        with m.If(op.is_32bit):
+            calc_overflow(self.i.dive_abs_overflow_32, 0x8000_0000)
+        with m.Else():
+            calc_overflow(self.i.dive_abs_overflow_32, 0x8000_0000_0000_0000)
+
+        ##########################
+        # main switch for DIV
+
+        with m.Switch(op.insn_type):
+            # TODO(programmerjake): finish switch
+            with m.Case(InternalOp.OP_DIV, InternalOp.OP_DIVE):
+                with m.If(op.is_32bit):
+                    comb += dividend_in.eq(self.abs_dividend[0:32])
+                with m.Else():
+                    comb += dividend_in.eq(self.abs_dividend[0:64])
+            with m.Case(InternalOp.OP_MOD):
+                with m.If(op.is_32bit):
+                    comb += dividend_in.eq(self.abs_dividend[0:32] << 32)
+                with m.Else():
+                    comb += dividend_in.eq(self.abs_dividend[0:64] << 64)
+
+        ###### 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 c31641d678dc50a47d22371cd07a67c42f00613b..f9df4e563ccd9dc1ca1fa6239e75f609f0679b66 100644 (file)
@@ -22,8 +22,15 @@ class CoreBaseData(ALUInputData):
     def __init__(self, pspec, core_data_class):
         super().__init__(pspec)
         self.core = core_data_class(pspec.core_config)
-        self.divisor_neg = Signal(1, reset_less=True)
-        self.dividend_neg = Signal(1, reset_less=True)
+        self.divisor_neg = Signal(reset_less=True)
+        self.dividend_neg = Signal(reset_less=True)
+        self.div_by_zero = Signal(reset_less=True)
+
+        # set if an overflow for divide extended instructions is detected because
+        # `abs_dividend >= abs_divisor` for the appropriate bit width;
+        # 0 if the instruction is not a divide extended instruction
+        self.dive_abs_overflow_32 = Signal(reset_less=True)
+        self.dive_abs_overflow_64 = Signal(reset_less=True)
 
     def __iter__(self):
         yield from super().__iter__()
@@ -32,8 +39,10 @@ class CoreBaseData(ALUInputData):
         yield self.dividend_neg
 
     def eq(self, rhs):
+        return self.eq_without_core(rhs) + self.core.eq(rhs.core)
+
+    def eq_without_core(self, rhs):
         return super().eq(rhs) + \
-            self.core.eq(rhs.core) + \
             [self.divisor_neg.eq(rhs.divisor_neg),
              self.dividend_neg.eq(rhs.dividend_neg)]
 
index 6f04e83984000a378c444ed50e6d6bf1ec166b27..6da1d733c8e29a25195a052adc7daae105edcb57 100644 (file)
@@ -16,7 +16,7 @@ from ieee754.div_rem_sqrt_rsqrt.core import DivPipeCoreOperation
 
 class DivSetupStage(PipeModBase):
     def __init__(self, pspec):
-        super().__init__(pspec, "main")
+        super().__init__(pspec, "setup_stage")
         self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
         self.fields.create_specs()
         self.abs_divisor = Signal(64)
@@ -50,11 +50,21 @@ class DivSetupStage(PipeModBase):
         comb += self.abs_divisor.eq(Mux(divisor_neg, -b, b))
         comb += self.abs_dividend.eq(Mux(dividend_neg, -a, a))
 
+        comb += self.o.dive_abs_overflow_64.eq(
+            (self.abs_dividend >= self.abs_divisor)
+            & (op.insn_type == InternalOp.OP_DIVE))
+
+        comb += self.o.dive_abs_overflow_32.eq(
+            (self.abs_dividend[0:32] >= self.abs_divisor[0:32])
+            & (op.insn_type == InternalOp.OP_DIVE))
+
         with m.If(op.is_32bit):
             comb += divisor_in.eq(self.abs_divisor[0:32])
         with m.Else():
             comb += divisor_in.eq(self.abs_divisor[0:64])
 
+        comb += self.o.div_by_zero.eq(self.divisor_in == 0)
+
         ##########################
         # main switch for DIV