fix up setup and process functions
[ieee754fpu.git] / src / ieee754 / div_rem_sqrt_rsqrt / core.py
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.
4
5 Special case handling, input/output conversion, and muxid handling are handled
6 outside of these classes.
7
8 Algorithms based on ``algorithm.FixedUDivRemSqrtRSqrt``.
9
10 Formulas solved are:
11 * div/rem:
12 ``dividend == quotient_root * divisor_radicand``
13 * sqrt/rem:
14 ``divisor_radicand == quotient_root * quotient_root``
15 * rsqrt/rem:
16 ``1 == quotient_root * quotient_root * divisor_radicand``
17
18 The remainder is the left-hand-side of the comparison minus the
19 right-hand-side of the comparison in the above formulas.
20 """
21 from nmigen import (Elaboratable, Module, Signal)
22 import enum
23
24
25 class DivPipeCoreConfig:
26 """ Configuration for core of the div/rem/sqrt/rsqrt pipeline.
27
28 :attribute bit_width: base bit-width.
29 :attribute fract_width: base fract-width. Specifies location of base-2
30 radix point.
31 :attribute log2_radix: number of bits of ``quotient_root`` that should be
32 computed per pipeline stage.
33 """
34
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
40
41 def __repr__(self):
42 """ Get repr. """
43 return f"DivPipeCoreConfig({self.bit_width}, " \
44 + f"{self.fract_width}, {self.log2_radix})"
45
46
47 class DivPipeCoreOperation(enum.IntEnum):
48 """ Operation for ``DivPipeCore``.
49
50 :attribute UDivRem: unsigned divide/remainder.
51 :attribute SqrtRem: square-root/remainder.
52 :attribute RSqrtRem: reciprocal-square-root/remainder.
53 """
54
55 UDivRem = 0
56 SqrtRem = 1
57 RSqrtRem = 2
58
59 @classmethod
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)),
63 max=int(max(cls)),
64 src_loc_at=(src_loc_at + 1),
65 decoder=cls,
66 **kwargs)
67
68
69 class DivPipeCoreInputData:
70 """ input data type for ``DivPipeCore``.
71
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.
81 """
82
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,
87 reset_less=True)
88 self.divisor_radicand = Signal(core_config.bit_width, reset_less=True)
89 self.operation = DivPipeCoreOperation.create_signal(reset_less=True)
90
91 def __iter__(self):
92 """ Get member signals. """
93 yield self.dividend
94 yield self.divisor_radicand
95 yield self.operation
96
97 def eq(self, rhs):
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)]
102
103
104 class DivPipeCoreInterstageData:
105 """ interstage data type for ``DivPipeCore``.
106
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.
127 """
128
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,
136 reset_less=True)
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)
139
140 def __iter__(self):
141 """ Get member signals. """
142 yield self.divisor_radicand
143 yield self.operation
144 yield self.quotient_root
145 yield self.root_times_radicand
146 yield self.compare_lhs
147 yield self.compare_rhs
148
149 def eq(self, 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)]
157
158
159 class DivPipeCoreSetupStage(Elaboratable):
160 """ Setup Stage of the core of the div/rem/sqrt/rsqrt pipeline.
161 """
162
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()
168
169 def ispec(self):
170 """ Get the input spec for this pipeline stage."""
171 return DivPipeCoreInputData(self.core_config)
172
173 def ospec(self):
174 """ Get the output spec for this pipeline stage."""
175 return DivPipeCoreInterstageData(self.core_config)
176
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)
181
182 def process(self, i):
183 """ Pipeline stage process. """
184 return self.o # return processed data (ignore i)
185
186 def elaborate(self, platform):
187 """ Elaborate into ``Module``. """
188 m = Module()
189
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)
193
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))
203
204 m.d.comb += self.o.compare_rhs.eq(0)
205 m.d.comb += self.o.operation.eq(self.i.operation)
206
207 return m