set xer_ov.ok = 1
[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.div.pipe_data import DivMulOutputData
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 DivMulOutputData(self.pspec)
31
32 def elaborate(self, platform):
33 m = Module()
34 comb = m.d.comb
35
36 # convenience variables
37 op = self.i.ctx.op
38 abs_quotient = self.i.core.quotient_root
39 fract_width = self.pspec.core_config.fract_width
40 # fract width of `DivPipeCoreOutputData.remainder`
41 remainder_fract_width = fract_width * 3
42 # fract width of `DivPipeCoreInputData.dividend`
43 dividend_fract_width = fract_width * 2
44 rem_start = remainder_fract_width - dividend_fract_width
45 abs_remainder = self.i.core.remainder[rem_start:rem_start+64]
46 dividend_neg = self.i.dividend_neg
47 divisor_neg = self.i.divisor_neg
48 quotient_64 = self.quotient_64
49 remainder_64 = self.remainder_64
50
51 # work out if sign of result is to be negative
52 comb += self.quotient_neg.eq(dividend_neg ^ divisor_neg)
53
54 # follows rules for truncating division
55 comb += self.remainder_neg.eq(dividend_neg)
56
57 # negation of a 64-bit value produces the same lower 32-bit
58 # result as negation of just the lower 32-bits, so we don't
59 # need to do anything special before negating
60 comb += [
61 quotient_64.eq(Mux(self.quotient_neg,
62 -abs_quotient, abs_quotient)),
63 remainder_64.eq(Mux(self.remainder_neg,
64 -abs_remainder, abs_remainder))
65 ]
66
67 # calculate overflow
68 self.o.xer_ov.ok.eq(1)
69 xer_ov = self.o.xer_ov.data
70
71 def calc_overflow(dive_abs_overflow, sign_bit_mask):
72 nonlocal comb
73 overflow = dive_abs_overflow | self.i.div_by_zero
74 with m.If(op.is_signed):
75 comb += xer_ov.eq(overflow
76 | (abs_quotient > sign_bit_mask)
77 | ((abs_quotient == sign_bit_mask)
78 & ~self.quotient_neg))
79 with m.Else():
80 comb += xer_ov.eq(Repl(overflow, 2)) # set OV _and_ OV32
81
82 with m.If(op.is_32bit):
83 calc_overflow(self.i.dive_abs_ov32, 0x80000000)
84 with m.Else():
85 calc_overflow(self.i.dive_abs_ov64, 0x8000000000000000)
86
87 ##########################
88 # main switch for DIV
89
90 o = self.o.o.data
91
92 with m.Switch(op.insn_type):
93 with m.Case(InternalOp.OP_DIVE):
94 with m.If(op.is_32bit):
95 with m.If(op.is_signed):
96 # matches POWER9's divweo behavior
97 comb += o.eq(quotient_64[0:32].as_unsigned())
98 with m.Else():
99 comb += o.eq(quotient_64[0:32].as_unsigned())
100 with m.Else():
101 comb += o.eq(quotient_64)
102 with m.Case(InternalOp.OP_DIV):
103 with m.If(op.is_32bit):
104 with m.If(op.is_signed):
105 # matches POWER9's divwo behavior
106 comb += o.eq(quotient_64[0:32].as_unsigned())
107 with m.Else():
108 comb += o.eq(quotient_64[0:32].as_unsigned())
109 with m.Else():
110 comb += o.eq(quotient_64)
111 with m.Case(InternalOp.OP_MOD):
112 with m.If(op.is_32bit):
113 with m.If(op.is_signed):
114 # matches POWER9's modsw behavior
115 comb += o.eq(remainder_64[0:32].as_signed())
116 with m.Else():
117 comb += o.eq(remainder_64[0:32].as_unsigned())
118 with m.Else():
119 comb += o.eq(remainder_64)
120
121 ###### sticky overflow and context, both pass-through #####
122
123 comb += self.o.xer_so.data.eq(self.i.xer_so)
124 comb += self.o.ctx.eq(self.i.ctx)
125
126 return m