6da1d733c8e29a25195a052adc7daae105edcb57
[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.logical.pipe_data import LogicalInputData
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
17 class DivSetupStage(PipeModBase):
18 def __init__(self, pspec):
19 super().__init__(pspec, "setup_stage")
20 self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
21 self.fields.create_specs()
22 self.abs_divisor = Signal(64)
23 self.abs_dividend = Signal(64)
24
25 def ispec(self):
26 return LogicalInputData(self.pspec)
27
28 def ospec(self):
29 return CoreInputData(self.pspec)
30
31 def elaborate(self, platform):
32 m = Module()
33 comb = m.d.comb
34 op, a, b = self.i.ctx.op, self.i.a, self.i.b
35 core_input_data = self.o.core
36 dividend_neg = self.o.dividend_neg
37 divisor_neg = self.o.divisor_neg
38 dividend_in = core_input_data.dividend
39 divisor_in = core_input_data.divisor_radicand
40
41 comb += core_input_data.operation.eq(
42 int(DivPipeCoreOperation.UDivRem))
43
44 comb += dividend_neg.eq(Mux(op.is_32bit, a[31], a[63]) & op.is_signed)
45 comb += divisor_neg.eq(Mux(op.is_32bit, b[31], b[63]) & op.is_signed)
46
47 # negation of a 64-bit value produces the same lower 32-bit
48 # result as negation of just the lower 32-bits, so we don't
49 # need to do anything special before negating
50 comb += self.abs_divisor.eq(Mux(divisor_neg, -b, b))
51 comb += self.abs_dividend.eq(Mux(dividend_neg, -a, a))
52
53 comb += self.o.dive_abs_overflow_64.eq(
54 (self.abs_dividend >= self.abs_divisor)
55 & (op.insn_type == InternalOp.OP_DIVE))
56
57 comb += self.o.dive_abs_overflow_32.eq(
58 (self.abs_dividend[0:32] >= self.abs_divisor[0:32])
59 & (op.insn_type == InternalOp.OP_DIVE))
60
61 with m.If(op.is_32bit):
62 comb += divisor_in.eq(self.abs_divisor[0:32])
63 with m.Else():
64 comb += divisor_in.eq(self.abs_divisor[0:64])
65
66 comb += self.o.div_by_zero.eq(self.divisor_in == 0)
67
68 ##########################
69 # main switch for DIV
70
71 with m.Switch(op.insn_type):
72 with m.Case(InternalOp.OP_DIV, InternalOp.OP_MOD):
73 with m.If(op.is_32bit):
74 comb += dividend_in.eq(self.abs_dividend[0:32])
75 with m.Else():
76 comb += dividend_in.eq(self.abs_dividend[0:64])
77 with m.Case(InternalOp.OP_DIVE):
78 with m.If(op.is_32bit):
79 comb += dividend_in.eq(self.abs_dividend[0:32] << 32)
80 with m.Else():
81 comb += dividend_in.eq(self.abs_dividend[0:64] << 64)
82
83 ###### sticky overflow and context, both pass-through #####
84
85 comb += self.o.xer_so.data.eq(self.i.xer_so)
86 comb += self.o.ctx.eq(self.i.ctx)
87
88 # pass through op
89
90 comb += self.o.op.eq(op)
91
92 return m