code-morph on div pipeline
[soc.git] / src / soc / fu / div / setup_stage.py
1 # This stage is the setup stage that converts the inputs
2 # into the values expected by DivPipeCore
3
4 from nmigen import (Module, Signal, Cat, Repl, Mux, Const, Array)
5 from nmutil.pipemodbase import PipeModBase
6 from soc.fu.div.pipe_data import DIVInputData
7 from soc.fu.alu.pipe_data import ALUOutputData
8 from ieee754.part.partsig import PartitionedSignal
9 from soc.decoder.power_enums import InternalOp
10
11 from soc.decoder.power_fields import DecodeFields
12 from soc.decoder.power_fieldsn import SignalBitRange
13 from soc.fu.div.pipe_data import CoreInputData
14 from ieee754.div_rem_sqrt_rsqrt.core import DivPipeCoreOperation
15
16 def eq32(is_32bit, dest, src):
17 return [dest[0:32].eq(src[0:32]),
18 dest[32:64].eq(Mux(is_32bit, 0, src[32:64]))]
19
20
21 class DivSetupStage(PipeModBase):
22 def __init__(self, pspec):
23 super().__init__(pspec, "setup_stage")
24 self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
25 self.fields.create_specs()
26
27 def ispec(self):
28 return DIVInputData(self.pspec)
29
30 def ospec(self):
31 return CoreInputData(self.pspec)
32
33 def elaborate(self, platform):
34 m = Module()
35 comb = m.d.comb
36 # convenience variables
37 op, a, b = self.i.ctx.op, self.i.a, self.i.b
38 core_o = self.o.core
39 dividend_neg_o = self.o.dividend_neg
40 divisor_neg_o = self.o.divisor_neg
41 dividend_o = core_o.dividend
42 divisor_o = core_o.divisor_radicand
43
44 # set operation to unsigned div/remainder
45 comb += core_o.operation.eq(int(DivPipeCoreOperation.UDivRem))
46
47 # work out if a/b are negative (check 32-bit / signed)
48 comb += dividend_neg_o.eq(Mux(op.is_32bit, a[31], a[63]) & op.is_signed)
49 comb += divisor_neg_o.eq(Mux(op.is_32bit, b[31], b[63]) & op.is_signed)
50
51 # negation of a 64-bit value produces the same lower 32-bit
52 # result as negation of just the lower 32-bits, so we don't
53 # need to do anything special before negating
54 abs_dor = Signal(64, reset_less=True) # absolute of divisor
55 abs_dend = Signal(64, reset_less=True) # absolute of dividend
56 comb += abs_dor.eq(Mux(divisor_neg_o, -b, b))
57 comb += abs_dend.eq(Mux(dividend_neg_o, -a, a))
58
59 # check for absolute overflow condition (32/64)
60 comb += self.o.dive_abs_ov64.eq((abs_dend >= abs_dor)
61 & (op.insn_type == InternalOp.OP_DIVE))
62
63 comb += self.o.dive_abs_ov32.eq((abs_dend[0:32] >= abs_dor[0:32])
64 & (op.insn_type == InternalOp.OP_DIVE))
65
66 # set divisor based on 32/64 bit mode (must be absolute)
67 comb += eq32(op.is_32bit, divisor_o, abs_dor)
68
69 # divide by zero error detection
70 comb += self.o.div_by_zero.eq(divisor_o == 0)
71
72 ##########################
73 # main switch for DIV
74
75 with m.Switch(op.insn_type):
76 # div/mod takes straight (absolute) dividend
77 with m.Case(InternalOp.OP_DIV, InternalOp.OP_MOD):
78 comb += eq32(op.is_32bit, dividend_o, abs_dend)
79 # extended div shifts dividend up
80 with m.Case(InternalOp.OP_DIVE):
81 with m.If(op.is_32bit):
82 comb += dividend_o.eq(abs_dend[0:32] << 32)
83 with m.Else():
84 comb += dividend_o.eq(abs_dend[0:64] << 64)
85
86 ###### sticky overflow and context, both pass-through #####
87
88 comb += self.o.xer_so.eq(self.i.xer_so)
89 comb += self.o.ctx.eq(self.i.ctx)
90
91 return m