1 # SPDX-License-Identifier: LGPL-2.1-or-later
2 # See Notices.txt for copyright information
3 """ Core of the div/rem/sqrt/rsqrt pipeline.
5 Special case handling, input/output conversion, and muxid handling are handled
6 outside of these classes.
8 Algorithms based on ``algorithm.FixedUDivRemSqrtRSqrt``.
12 ``dividend == quotient_root * divisor_radicand``
14 ``divisor_radicand == quotient_root * quotient_root``
16 ``1 == quotient_root * quotient_root * divisor_radicand``
18 The remainder is the left-hand-side of the comparison minus the
19 right-hand-side of the comparison in the above formulas.
21 from nmigen
import (Elaboratable
, Module
, Signal
)
25 class DivPipeCoreConfig
:
26 """ Configuration for core of the div/rem/sqrt/rsqrt pipeline.
28 :attribute bit_width: base bit-width.
29 :attribute fract_width: base fract-width. Specifies location of base-2
31 :attribute log2_radix: number of bits of ``quotient_root`` that should be
32 computed per pipeline stage.
35 def __init__(self
, bit_width
, fract_width
, log2_radix
):
36 """ Create a ``DivPipeCoreConfig`` instance. """
37 self
.bit_width
= bit_width
38 self
.fract_width
= fract_width
39 self
.log2_radix
= log2_radix
43 return f
"DivPipeCoreConfig({self.bit_width}, " \
44 + f
"{self.fract_width}, {self.log2_radix})"
47 class DivPipeCoreOperation(enum
.IntEnum
):
48 """ Operation for ``DivPipeCore``.
50 :attribute UDivRem: unsigned divide/remainder.
51 :attribute SqrtRem: square-root/remainder.
52 :attribute RSqrtRem: reciprocal-square-root/remainder.
60 def create_signal(cls
, *, src_loc_at
=0, **kwargs
):
61 """ Create a signal that can contain a ``DivPipeCoreOperation``. """
62 return Signal(min=int(min(cls
)),
64 src_loc_at
=(src_loc_at
+ 1),
69 class DivPipeCoreInputData
:
70 """ input data type for ``DivPipeCore``.
72 :attribute core_config: ``DivPipeCoreConfig`` instance describing the
73 configuration to be used.
74 :attribute dividend: dividend for div/rem. Signal with a bit-width of
75 ``core_config.bit_width + core_config.fract_width`` and a fract-width
76 of ``core_config.fract_width * 2`` bits.
77 :attribute divisor_radicand: divisor for div/rem and radicand for
78 sqrt/rsqrt. Signal with a bit-width of ``core_config.bit_width`` and a
79 fract-width of ``core_config.fract_width`` bits.
80 :attribute operation: the ``DivPipeCoreOperation`` to be computed.
83 def __init__(self
, core_config
):
84 """ Create a ``DivPipeCoreInputData`` instance. """
85 self
.core_config
= core_config
86 self
.dividend
= Signal(core_config
.bit_width
+ core_config
.fract_width
,
88 self
.divisor_radicand
= Signal(core_config
.bit_width
, reset_less
=True)
89 self
.operation
= DivPipeCoreOperation
.create_signal(reset_less
=True)
92 """ Get member signals. """
94 yield self
.divisor_radicand
98 """ Assign member signals. """
99 return [self
.dividend
.eq(rhs
.dividend
),
100 self
.divisor_radicand
.eq(rhs
.divisor_radicand
),
101 self
.operation
.eq(rhs
.operation
)]
104 class DivPipeCoreInterstageData
:
105 """ interstage data type for ``DivPipeCore``.
107 :attribute core_config: ``DivPipeCoreConfig`` instance describing the
108 configuration to be used.
109 :attribute divisor_radicand: divisor for div/rem and radicand for
110 sqrt/rsqrt. Signal with a bit-width of ``core_config.bit_width`` and a
111 fract-width of ``core_config.fract_width`` bits.
112 :attribute operation: the ``DivPipeCoreOperation`` to be computed.
113 :attribute quotient_root: the quotient or root part of the result of the
114 operation. Signal with a bit-width of ``core_config.bit_width`` and a
115 fract-width of ``core_config.fract_width`` bits.
116 :attribute root_times_radicand: ``quotient_root * divisor_radicand``.
117 Signal with a bit-width of ``core_config.bit_width * 2`` and a
118 fract-width of ``core_config.fract_width * 2`` bits.
119 :attribute compare_lhs: The left-hand-side of the comparison in the
120 equation to be solved. Signal with a bit-width of
121 ``core_config.bit_width * 3`` and a fract-width of
122 ``core_config.fract_width * 3`` bits.
123 :attribute compare_rhs: The right-hand-side of the comparison in the
124 equation to be solved. Signal with a bit-width of
125 ``core_config.bit_width * 3`` and a fract-width of
126 ``core_config.fract_width * 3`` bits.
129 def __init__(self
, core_config
):
130 """ Create a ``DivPipeCoreInterstageData`` instance. """
131 self
.core_config
= core_config
132 self
.divisor_radicand
= Signal(core_config
.bit_width
, reset_less
=True)
133 self
.operation
= DivPipeCoreOperation
.create_signal(reset_less
=True)
134 self
.quotient_root
= Signal(core_config
.bit_width
, reset_less
=True)
135 self
.root_times_radicand
= Signal(core_config
.bit_width
* 2,
137 self
.compare_lhs
= Signal(core_config
.bit_width
* 3, reset_less
=True)
138 self
.compare_rhs
= Signal(core_config
.bit_width
* 3, reset_less
=True)
141 """ Get member signals. """
142 yield self
.divisor_radicand
144 yield self
.quotient_root
145 yield self
.root_times_radicand
146 yield self
.compare_lhs
147 yield self
.compare_rhs
150 """ Assign member signals. """
151 return [self
.divisor_radicand
.eq(rhs
.divisor_radicand
),
152 self
.operation
.eq(rhs
.operation
),
153 self
.quotient_root
.eq(rhs
.quotient_root
),
154 self
.root_times_radicand
.eq(rhs
.root_times_radicand
),
155 self
.compare_lhs
.eq(rhs
.compare_lhs
),
156 self
.compare_rhs
.eq(rhs
.compare_rhs
)]
159 class DivPipeCoreSetupStage(Elaboratable
):
160 """ Setup Stage of the core of the div/rem/sqrt/rsqrt pipeline.
163 def __init__(self
, core_config
):
164 """ Create a ``DivPipeCoreSetupStage`` instance."""
165 self
.core_config
= core_config
166 self
.i
= self
.ispec()
167 self
.o
= self
.ospec()
170 """ Get the input spec for this pipeline stage."""
171 return DivPipeCoreInputData(self
.core_config
)
174 """ Get the output spec for this pipeline stage."""
175 return DivPipeCoreInterstageData(self
.core_config
)
177 def setup(self
, m
, i
):
178 """ Pipeline stage setup. """
179 m
.submodules
.div_pipe_core_setup
= self
180 m
.d
.comb
+= self
.i
.eq(i
)
182 def process(self
, i
):
183 """ Pipeline stage process. """
184 return self
.o
# return processed data (ignore i)
186 def elaborate(self
, platform
):
187 """ Elaborate into ``Module``. """
190 m
.d
.comb
+= self
.o
.divisor_radicand
.eq(self
.i
.divisor_radicand
)
191 m
.d
.comb
+= self
.o
.quotient_root
.eq(0)
192 m
.d
.comb
+= self
.o
.root_times_radicand
.eq(0)
194 with m
.If(self
.i
.operation
== DivPipeCoreOperation
.UDivRem
):
195 m
.d
.comb
+= self
.o
.compare_lhs
.eq(self
.i
.dividend
196 << self
.core_config
.fract_width
)
197 with m
.Elif(self
.i
.operation
== DivPipeCoreOperation
.SqrtRem
):
198 m
.d
.comb
+= self
.o
.compare_lhs
.eq(
199 self
.i
.divisor_radicand
<< (self
.core_config
.fract_width
* 2))
200 with m
.Else(): # DivPipeCoreOperation.RSqrtRem
201 m
.d
.comb
+= self
.o
.compare_lhs
.eq(
202 1 << (self
.core_config
.fract_width
* 3))
204 m
.d
.comb
+= self
.o
.compare_rhs
.eq(0)
205 m
.d
.comb
+= self
.o
.operation
.eq(self
.i
.operation
)