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
.div
.pipe_data
import DivMulOutputData
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 DivMulOutputData(self
.pspec
)
32 def elaborate(self
, platform
):
36 # convenience variables
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
51 # work out if sign of result is to be negative
52 comb
+= self
.quotient_neg
.eq(dividend_neg ^ divisor_neg
)
54 # follows rules for truncating division
55 comb
+= self
.remainder_neg
.eq(dividend_neg
)
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
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
))
68 self
.o
.xer_ov
.ok
.eq(1)
69 xer_ov
= self
.o
.xer_ov
.data
71 def calc_overflow(dive_abs_overflow
, sign_bit_mask
):
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
))
80 comb
+= xer_ov
.eq(Repl(overflow
, 2)) # set OV _and_ OV32
82 with m
.If(op
.is_32bit
):
83 calc_overflow(self
.i
.dive_abs_ov32
, 0x80000000)
85 calc_overflow(self
.i
.dive_abs_ov64
, 0x8000000000000000)
87 ##########################
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())
99 comb
+= o
.eq(quotient_64
[0:32].as_unsigned())
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())
108 comb
+= o
.eq(quotient_64
[0:32].as_unsigned())
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())
117 comb
+= o
.eq(remainder_64
[0:32].as_unsigned())
119 comb
+= o
.eq(remainder_64
)
121 ###### sticky overflow and context, both pass-through #####
123 comb
+= self
.o
.xer_so
.data
.eq(self
.i
.xer_so
)
124 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)