Allow the formal engine to perform a same-cycle result in the ALU
[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 ieee754.part.partsig import SimdSignal
8 from openpower.decoder.power_enums import MicrOp
9
10 from openpower.decoder.power_fields import DecodeFields
11 from openpower.decoder.power_fieldsn import SignalBitRange
12 from soc.fu.div.pipe_data import CoreInputData
13 from ieee754.div_rem_sqrt_rsqrt.core import DivPipeCoreOperation
14 from nmutil.util import eq32
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
23 def ispec(self):
24 return DivInputData(self.pspec)
25
26 def ospec(self):
27 return CoreInputData(self.pspec)
28
29 def elaborate(self, platform):
30 XLEN = self.pspec.XLEN
31 m = Module()
32 comb = m.d.comb
33 # convenience variables
34 op, a, b = self.i.ctx.op, self.i.a, self.i.b
35 core_o = self.o.core
36 dividend_neg_o = self.o.dividend_neg
37 divisor_neg_o = self.o.divisor_neg
38 dividend_o = core_o.dividend
39 divisor_o = core_o.divisor_radicand
40
41 # set operation to unsigned div/remainder
42 comb += core_o.operation.eq(int(DivPipeCoreOperation.UDivRem))
43
44 # work out if a/b are negative (check 32-bit / signed)
45 comb += dividend_neg_o.eq(Mux(op.is_32bit,
46 a[31], a[XLEN-1]) & op.is_signed)
47 comb += divisor_neg_o.eq(Mux(op.is_32bit,
48 b[31], b[XLEN-1]) & op.is_signed)
49
50 # negation of a 64-bit value produces the same lower 32-bit
51 # result as negation of just the lower 32-bits, so we don't
52 # need to do anything special before negating
53 abs_dor = Signal(XLEN, reset_less=True) # absolute of divisor
54 abs_dend = Signal(XLEN, reset_less=True) # absolute of dividend
55 comb += abs_dor.eq(Mux(divisor_neg_o, -b, b))
56 comb += abs_dend.eq(Mux(dividend_neg_o, -a, a))
57
58 # check for absolute overflow condition (32/64)
59 comb += self.o.dive_abs_ov64.eq((abs_dend >= abs_dor)
60 & (op.insn_type == MicrOp.OP_DIVE))
61
62 comb += self.o.dive_abs_ov32.eq((abs_dend[0:32] >= abs_dor[0:32])
63 & (op.insn_type == MicrOp.OP_DIVE))
64
65 # set divisor based on 32/64 bit mode (must be absolute)
66 comb += eq32(op.is_32bit, divisor_o, abs_dor)
67
68 # divide by zero error detection
69 comb += self.o.div_by_zero.eq(divisor_o == 0)
70
71 ##########################
72 # main switch for Div
73
74 with m.Switch(op.insn_type):
75 # div/mod takes straight (absolute) dividend
76 with m.Case(MicrOp.OP_DIV, MicrOp.OP_MOD):
77 comb += eq32(op.is_32bit, dividend_o, abs_dend)
78 # extended div shifts dividend up
79 with m.Case(MicrOp.OP_DIVE):
80 with m.If(op.is_32bit):
81 comb += dividend_o.eq(abs_dend[0:32] << 32)
82 with m.Else():
83 comb += dividend_o.eq(abs_dend[0:XLEN] << XLEN)
84
85 ###### sticky overflow and context, both pass-through #####
86
87 comb += self.o.xer_so.eq(self.i.xer_so)
88 comb += self.o.ctx.eq(self.i.ctx)
89
90 return m