1 # This stage is the setup stage that converts the inputs
2 # into the values expected by DivPipeCore
4 * https://bugs.libre-soc.org/show_bug.cgi?id=424
7 from nmigen
import (Module
, Signal
, Cat
, Repl
, Mux
, Const
, Array
, signed
)
8 from nmutil
.pipemodbase
import PipeModBase
9 from soc
.fu
.logical
.pipe_data
import LogicalInputData
10 from soc
.fu
.div
.pipe_data
import DivMulOutputData
11 from ieee754
.part
.partsig
import SimdSignal
12 from openpower
.decoder
.power_enums
import MicrOp
14 from openpower
.decoder
.power_fields
import DecodeFields
15 from openpower
.decoder
.power_fieldsn
import SignalBitRange
16 from soc
.fu
.div
.pipe_data
import CoreOutputData
19 class DivOutputStage(PipeModBase
):
20 def __init__(self
, pspec
):
21 super().__init
__(pspec
, "output_stage")
22 self
.fields
= DecodeFields(SignalBitRange
, [self
.i
.ctx
.op
.insn
])
23 self
.fields
.create_specs()
24 self
.quotient_neg
= Signal()
25 self
.remainder_neg
= Signal()
26 self
.quotient_65
= Signal(65) # one extra spare bit for overflow
27 self
.remainder_64
= Signal(64)
30 return CoreOutputData(self
.pspec
)
33 return DivMulOutputData(self
.pspec
)
35 def elaborate(self
, platform
):
39 # convenience variables
41 abs_quotient
= self
.i
.core
.quotient_root
42 fract_width
= self
.pspec
.core_config
.fract_width
43 # fract width of `DivPipeCoreOutputData.remainder`
44 remainder_fract_width
= fract_width
* 3
45 # fract width of `DivPipeCoreInputData.dividend`
46 dividend_fract_width
= fract_width
* 2
47 rem_start
= remainder_fract_width
- dividend_fract_width
48 abs_remainder
= self
.i
.core
.remainder
[rem_start
:rem_start
+64]
49 dividend_neg
= self
.i
.dividend_neg
50 divisor_neg
= self
.i
.divisor_neg
51 quotient_65
= self
.quotient_65
52 remainder_64
= self
.remainder_64
54 # work out if sign of result is to be negative
55 comb
+= self
.quotient_neg
.eq(dividend_neg ^ divisor_neg
)
57 # follows rules for truncating division
58 comb
+= self
.remainder_neg
.eq(dividend_neg
)
60 # negation of a 64-bit value produces the same lower 32-bit
61 # result as negation of just the lower 32-bits, so we don't
62 # need to do anything special before negating
64 quotient_65
.eq(Mux(self
.quotient_neg
,
65 -abs_quotient
, abs_quotient
)),
66 remainder_64
.eq(Mux(self
.remainder_neg
,
67 -abs_remainder
, abs_remainder
))
71 comb
+= self
.o
.xer_ov
.ok
.eq(1)
72 xer_ov
= self
.o
.xer_ov
.data
74 # microwatt overflow detection
75 ov
= Signal(reset_less
=True)
76 with m
.If(self
.i
.div_by_zero
):
78 with m
.Elif(~op
.is_32bit
):
79 comb
+= ov
.eq(self
.i
.dive_abs_ov64
)
80 with m
.If(op
.is_signed
& (quotient_65
[64] ^ quotient_65
[63])):
82 with m
.Elif(op
.is_signed
):
83 comb
+= ov
.eq(self
.i
.dive_abs_ov32
)
84 with m
.If(quotient_65
[32] != quotient_65
[31]):
87 comb
+= ov
.eq(self
.i
.dive_abs_ov32
)
88 comb
+= xer_ov
.eq(Repl(ov
, 2)) # set OV _and_ OV32
90 ##########################
93 comb
+= self
.o
.o
.ok
.eq(1)
96 # work around https://github.com/nmigen/nmigen/issues/502
97 remainder_s32
= Signal(signed(32))
98 comb
+= remainder_s32
.eq(remainder_64
[0:32])
99 remainder_s32_as_s64
= Signal(signed(64))
100 comb
+= remainder_s32_as_s64
.eq(remainder_s32
)
102 with m
.If(~ov
): # result is valid (no overflow)
103 with m
.Switch(op
.insn_type
):
104 with m
.Case(MicrOp
.OP_DIVE
):
105 with m
.If(op
.is_32bit
):
106 with m
.If(op
.is_signed
):
107 # matches POWER9's divweo behavior
108 comb
+= o
.eq(quotient_65
[0:32].as_unsigned())
110 comb
+= o
.eq(quotient_65
[0:32].as_unsigned())
112 comb
+= o
.eq(quotient_65
)
113 with m
.Case(MicrOp
.OP_DIV
):
114 with m
.If(op
.is_32bit
):
115 with m
.If(op
.is_signed
):
116 # matches POWER9's divwo behavior
117 comb
+= o
.eq(quotient_65
[0:32].as_unsigned())
119 comb
+= o
.eq(quotient_65
[0:32].as_unsigned())
121 comb
+= o
.eq(quotient_65
)
122 with m
.Case(MicrOp
.OP_MOD
):
123 with m
.If(op
.is_32bit
):
124 with m
.If(op
.is_signed
):
125 # matches POWER9's modsw behavior
126 comb
+= o
.eq(remainder_s32_as_s64
)
128 comb
+= o
.eq(remainder_64
[0:32].as_unsigned())
130 comb
+= o
.eq(remainder_64
)
132 ###### sticky overflow and context, both pass-through #####
134 comb
+= self
.o
.xer_so
.data
.eq(self
.i
.xer_so
)
135 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)