1 # This stage is the setup stage that converts the inputs
2 # into the values expected by DivPipeCore
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
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
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)
27 return CoreOutputData(self
.pspec
)
30 return ALUOutputData(self
.pspec
)
32 def elaborate(self
, platform
):
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
49 comb
+= self
.quotient_neg
.eq(dividend_neg ^ divisor_neg
)
50 # follows rules for truncating division
51 comb
+= self
.remainder_neg
.eq(dividend_neg
)
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
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
))
63 xer_ov
= self
.o
.xer_ov
.data
65 def calc_overflow(dive_abs_overflow
, sign_bit_mask
):
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
))
74 comb
+= xer_ov
.eq(overflow
)
76 with m
.If(op
.is_32bit
):
77 calc_overflow(self
.i
.dive_abs_overflow_32
, 0x8000_0000)
79 calc_overflow(self
.i
.dive_abs_overflow_64
, 0x8000_0000_0000_0000)
81 ##########################
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())
93 comb
+= o
.eq(quotient_64
[0:32].as_unsigned())
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())
102 comb
+= o
.eq(quotient_64
[0:32].as_unsigned())
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())
111 comb
+= o
.eq(remainder_64
[0:32].as_unsigned())
113 comb
+= o
.eq(remainder_64
)
115 ###### sticky overflow and context, both pass-through #####
117 comb
+= self
.o
.xer_so
.data
.eq(self
.i
.xer_so
)
118 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)