finish code to calculate the 64-bit output of the div pipeline
[soc.git] / src / soc / fu / div / output_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 CoreOutputData
14
15
16 class DivOutputStage(PipeModBase):
17 def __init__(self, pspec):
18 super().__init__(pspec, "output_stage")
19 self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
20 self.fields.create_specs()
21 self.quotient_neg = Signal()
22 self.remainder_neg = Signal()
23 self.quotient_64 = Signal(64)
24 self.remainder_64 = Signal(64)
25
26 def ispec(self):
27 return CoreOutputData(self.pspec)
28
29 def ospec(self):
30 return ALUOutputData(self.pspec)
31
32 def elaborate(self, platform):
33 m = Module()
34 comb = m.d.comb
35 op = self.i.ctx.op
36 abs_quotient = self.i.core.quotient_root
37 fract_width = self.pspec.core_config.fract_width
38 # fract width of `DivPipeCoreOutputData.remainder`
39 remainder_fract_width = fract_width * 3
40 # fract width of `DivPipeCoreInputData.dividend`
41 dividend_fract_width = fract_width * 2
42 rem_start = remainder_fract_width - dividend_fract_width
43 abs_remainder = self.i.core.remainder[rem_start:rem_start+64]
44 dividend_neg = self.i.dividend_neg
45 divisor_neg = self.i.divisor_neg
46 quotient_64 = self.quotient_64
47 remainder_64 = self.remainder_64
48
49 comb += self.quotient_neg.eq(dividend_neg ^ divisor_neg)
50 # follows rules for truncating division
51 comb += self.remainder_neg.eq(dividend_neg)
52
53 # negation of a 64-bit value produces the same lower 32-bit
54 # result as negation of just the lower 32-bits, so we don't
55 # need to do anything special before negating
56 comb += [
57 quotient_64.eq(Mux(self.quotient_neg,
58 -abs_quotient, abs_quotient)),
59 remainder_64.eq(Mux(self.remainder_neg,
60 -abs_remainder, abs_remainder))
61 ]
62
63 xer_ov = self.o.xer_ov.data
64
65 def calc_overflow(dive_abs_overflow, sign_bit_mask):
66 nonlocal comb
67 overflow = dive_abs_overflow | self.i.div_by_zero
68 with m.If(op.is_signed):
69 comb += xer_ov.eq(overflow
70 | (abs_quotient > sign_bit_mask)
71 | ((abs_quotient == sign_bit_mask)
72 & ~self.quotient_neg))
73 with m.Else():
74 comb += xer_ov.eq(overflow)
75
76 with m.If(op.is_32bit):
77 calc_overflow(self.i.dive_abs_overflow_32, 0x8000_0000)
78 with m.Else():
79 calc_overflow(self.i.dive_abs_overflow_64, 0x8000_0000_0000_0000)
80
81 ##########################
82 # main switch for DIV
83
84 o = self.o.o.data
85
86 with m.Switch(op.insn_type):
87 with m.Case(InternalOp.OP_DIVE):
88 with m.If(op.is_32bit):
89 with m.If(op.is_signed):
90 # matches POWER9's divweo behavior
91 comb += o.eq(quotient_64[0:32].as_unsigned())
92 with m.Else():
93 comb += o.eq(quotient_64[0:32].as_unsigned())
94 with m.Else():
95 comb += o.eq(quotient_64)
96 with m.Case(InternalOp.OP_DIV):
97 with m.If(op.is_32bit):
98 with m.If(op.is_signed):
99 # matches POWER9's divwo behavior
100 comb += o.eq(quotient_64[0:32].as_unsigned())
101 with m.Else():
102 comb += o.eq(quotient_64[0:32].as_unsigned())
103 with m.Else():
104 comb += o.eq(quotient_64)
105 with m.Case(InternalOp.OP_MOD):
106 with m.If(op.is_32bit):
107 with m.If(op.is_signed):
108 # matches POWER9's modsw behavior
109 comb += o.eq(remainder_64[0:32].as_signed())
110 with m.Else():
111 comb += o.eq(remainder_64[0:32].as_unsigned())
112 with m.Else():
113 comb += o.eq(remainder_64)
114
115 ###### sticky overflow and context, both pass-through #####
116
117 comb += self.o.xer_so.data.eq(self.i.xer_so)
118 comb += self.o.ctx.eq(self.i.ctx)
119
120 return m