2 /*============================================================================
4 This Verilog source file is part of the Berkeley HardFloat IEEE Floating-Point
5 Arithmetic Package, Release 1, by John R. Hauser.
7 Copyright 2019 The Regents of the University of California. All rights
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions are met:
13 1. Redistributions of source code must retain the above copyright notice,
14 this list of conditions, and the following disclaimer.
16 2. Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions, and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
20 3. Neither the name of the University nor the names of its contributors may
21 be used to endorse or promote products derived from this software without
22 specific prior written permission.
24 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY
25 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
27 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
28 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 =============================================================================*/
37 `include "HardFloat_consts.vi"
38 `include "HardFloat_specialize.vi"
42 from nmigen
import Elaboratable
, Cat
, Const
, Mux
, Module
, Signal
43 from nmutil
.concurrentunit
import num_bits
45 #/*----------------------------------------------------------------------------
46 #*----------------------------------------------------------------------------*/
48 class mulAddRecFNToRaw_preMul(Elaboratable
):
49 def __init__(self
, expWidth
=3, sigWidth
=3):
51 self
.control
= Signal(floatControlWidth
, reset_less
=True)
52 self
.op
= Signal(2, reset_less
=True)
53 self
.a
= Signal(expWidth
+ sigWidth
+ 1, reset_less
=True)
54 self
.b
= Signal(expWidth
+ sigWidth
+ 1, reset_less
=True)
55 self
.c
= Signal(expWidth
+ sigWidth
+ 1, reset_less
=True)
56 self
.roundingMode
= Signal(3, reset_less
=True)
59 self
.mulAddA
= Signal(sigWidth
, reset_less
=True)
60 self
.mulAddB
= Signal(sigWidth
, reset_less
=True)
61 self
.mulAddC
= Signal(sigWidth
*2, reset_less
=True)
62 self
.intermed_compactState
= Signal(6, reset_less
=True)
63 self
.intermed_sExp
= Signal(expWidth
+ 2, reset_less
=True)
64 wid
= num_bits(sigWidth
+ 1)
65 self
.intermed_CDom_CAlignDist
= Signal(wid
, reset_less
=True)
66 self
.intermed_highAlignedSigC
= Signal((sigWidth
+ 2), reset_less
=True)
68 def elaborate(self
, platform
):
72 #/*-------------------------------------------------------------------
73 #*--------------------------------------------------------------------*/
74 prodWidth
= sigWidth
*2;
75 sigSumWidth
= sigWidth
+ prodWidth
+ 3;
76 #/*-------------------------------------------------------------------
77 #*-------------------------------------------------------------------*/
78 isNaNA
= Signal(reset_less
=True)
79 isInfA
= Signal(reset_less
=True)
80 isZeroA
= Signal(reset_less
=True)
81 signA
= Signal(reset_less
=True)
83 sExpA
= Signal((expWidth
+ 2, True), reset_less
=True)
84 sigA
= Signal(sigWidth
+1, reset_less
=True)
85 m
.submodules
.recFNToRawFN_a
= rf
= recFNToRawFN(expWidth
, sigWidth
)
86 comb
+= [(a
, isNaNA
, isInfA
, isZeroA
, signA
, sExpA
, sigA
)]
88 isSigNaNA
= Signal(reset_less
=True)
89 m
.submodules
.isSigNaN_a
= nan_a
= isSigNaNRecFN(expWidth
, sigWidth
)
90 comb
+= [(a
, isSigNaNA
)]
92 isNaNB
= Signal(reset_less
=True)
93 isInfB
= Signal(reset_less
=True)
94 isZeroB
= Signal(reset_less
=True)
95 signB
= Signal(reset_less
=True)
97 sExpB
= Signal((expWidth
+ 2, True), reset_less
=True)
98 sigB
= Signal(sigWidth
+1, reset_less
=True)
99 m
.submodules
.recFNToRawFN_b
= rf
= recFNToRawFN(expWidth
, sigWidth
)
100 comb
+= [(b
, isNaNB
, isInfB
, isZeroB
, signB
, sExpB
, sigB
)]
102 isSigNaNB
= Signal(reset_less
=True)
103 m
.submodules
.isSigNaN_b
= nan_b
= isSigNaNRecFN(expWidth
, sigWidth
)
104 comb
+= [(b
, isSigNaNB
)]
106 isNaNC
= Signal(reset_less
=True)
107 isInfC
= Signal(reset_less
=True)
108 isZeroC
= Signal(reset_less
=True)
109 signC
= Signal(reset_less
=True)
111 sExpC
= Signal((expWidth
+ 2, True), reset_less
=True)
112 sigC
= Signal(sigWidth
+1, reset_less
=True)
113 m
.submodules
.recFNToRawFN_c
= rf
= recFNToRawFN(expWidth
, sigWidth
)
114 comb
+= [(c
, isNaNC
, isInfC
, isZeroC
, signC
, sExpC
, sigC
)]
116 isSigNaNC
= Signal(reset_less
=True)
117 m
.submodules
.isSigNaN_c
= nan_c
= isSigNaNRecFN(expWidth
, sigWidth
)
118 comb
+= [(c
, isSigNaNC
)]
120 #/*-------------------------------------------------------------------
121 #*-------------------------------------------------------------------*/
122 signProd
= Signal(reset_less
=True)
123 sExpAlignedProd
= Signal((expWidth
+ 3, True), reset_less
=True)
124 doSubMags
= Signal(reset_less
=True)
125 opSignC
= Signal(reset_less
=True)
126 roundingMode_min
= Signal(reset_less
=True)
128 comb
+= signProd
.eq(signA ^ signB ^ op
[1])
129 comb
+= sExpAlignedProd
.eq(sExpA
+ sExpB
+ \
130 (-(1<<expWidth
) + sigWidth
+ 3))
131 comb
+= doSubMags
.eq(signProd ^ signC ^ op
[0])
132 comb
+= opSignC
.eq(signProd ^ doSubMags
)
133 comb
+= roundingMode_min
.eq(roundingMode
== ROUND_MIN
)
135 #/*-------------------------------------------------------------------
136 #*-------------------------------------------------------------------*/
137 sNatCAlignDist
= Signal((expWidth
+ 3, True), reset_less
=True)
138 posNatCAlignDist
= Signal(expWidth
+ 2, reset_less
=True)
139 isMinCAlign
= Signal(reset_less
=True)
140 CIsDominant
= Signal(reset_less
=True)
141 sExpSum
= Signal((expWidth
+ 2, True), reset_less
=True)
142 CAlignDist
= Signal(num_bits(sigSumWidth
), reset_less
=True)
143 extComplSigC
= Signal((sigSumWidth
+ 3, True), reset_less
=True)
144 mainAlignedSigC
= Signal(sigSumWidth
+ 2, reset_less
=True)
146 CGrainAlign
= (sigSumWidth
- sigWidth
- 1) & 3;
147 grainAlignedSigC
= Signal(sigWidth
+CGrainAlign
+ 1, reset_less
=True)
148 reduced4SigC
= Signal((sigWidth
+CGrainAlign
)/4 + 1, reset_less
=True)
149 m
.submodules
.compressBy4_sigC
= compressBy4(sigWidth
+ 1 + CGrainAlign
)
150 comb
+= (grainAlignedSigC
, reduced4SigC
)
151 CExtraMaskHiBound
= (sigSumWidth
- 1)/4;
152 CExtraMaskLoBound
= (sigSumWidth
- sigWidth
- 1)/4;
153 CExtraMask
= Signal(CExtraMaskHiBound
- CExtraMaskLoBound
,
155 m
.submodules
.lowMask_CExtraMask
= lowMaskHiLo(clog2(sigSumWidth
) - 2,
158 comb
+= (CAlignDist
[(clog2(sigSumWidth
) - 1):2], CExtraMask
);
159 reduced4CExtra
= Signal(reset_less
=True)
160 alignedSigC
= Signal(sigSumWidth
, reset_less
=True)
163 sNatCAlignDist
.eq(sExpAlignedProd
- sExpC
),
164 posNatCAlignDist
.eq(sNatCAlignDist
[:expWidth
+ 2]),
165 isMinCAlign
.eq(isZeroA | isZeroB |
(sNatCAlignDist
< 0))
166 CIsDominant
.eq(~isZeroC
& \
167 (isMinCAlign |
(posNatCAlignDist
<= sigWidth
)))
168 sExpSum
.eq(Mux(CIsDominant
, sExpC
, sExpAlignedProd
- sigWidth
)),
169 CAlignDist
.eq(Mux(isMinCAlign
, 0,
170 Mux((posNatCAlignDist
< sigSumWidth
- 1),
171 posNatCAlignDist
[:num_bits(sigSumWidth
)],
173 # XXX check! {doSubMags ? ~sigC : sigC,
174 # {(sigSumWidth - sigWidth + 2){doSubMags}}};
175 sc
= [doSubMags
] * (sigSumWidth
- sigWidth
+ 2) + \
176 [Mux(doSubMags
, ~sigC
, sigC
)]
177 extComplSigC
.eq(Cat(*sc
))
178 # XXX check! nmigen doesn't have >>> operator, only >>
179 mainAlignedSigC
.eq(extComplSigC
>>> CAlignDist
),
180 grainAlignedSigC
.eq(sigC
<<CGrainAlign
),
181 compressBy4_sigC
.in.eq(grainAlignedSigC
),
182 reduced4SigC
.eq(compressBy4_sigC
.out
),
183 lowMaskHiLo
.in.eq(CAlignDist
[2:(clog2(sigSumWidth
)]),
184 CExtraMask
.eq(lowMaskHiLo
.out
),
185 reduced4CExtra
.eq((reduced4SigC
& CExtraMask
).bool()),
187 Mux(doSubMags
, (mainAlignedSigC
[:3]=0b111) & ~reduced4CExtra
,
188 (mainAlignedSigC
[:3].bool()) | reduced4CExtra
),
191 #/*-------------------------------------------------------------------
192 #*-------------------------------------------------------------------*/
193 isNaNAOrB
= Signal(reset_less
=True)
194 isNaNAny
= Signal(reset_less
=True)
195 isInfAOrB
= Signal(reset_less
=True)
196 invalidProd
= Signal(reset_less
=True)
197 notSigNaN_invalidExc
= Signal(reset_less
=True)
198 invalidExc
= Signal(reset_less
=True)
199 notNaN_addZeros
= Signal(reset_less
=True)
200 specialCase
= Signal(reset_less
=True)
201 specialNotNaN_signOut
= Signal(reset_less
=True)
203 isNaNAOrB
.eq(isNaNA | isNaNB
),
204 isNaNAny
.eq(isNaNAOrB | isNaNC
),
205 isInfAOrB
.eq(isInfA | isInfB
),
206 invalidProd
.eq((isInfA
& isZeroB
) |
(isZeroA
& isInfB
)),
207 notSigNaN_invalidExc
.eq(
208 invalidProd |
(!isNaNAOrB
& isInfAOrB
& isInfC
& doSubMags
)),
210 isSigNaNA | isSigNaNB | isSigNaNC | notSigNaN_invalidExc
),
211 notNaN_addZeros
.eq((isZeroA | isZeroB
) && isZeroC
),
212 specialCase
.eq(isNaNAny | isInfAOrB | isInfC | notNaN_addZeros
),
213 specialNotNaN_signOut
.eq(
214 (isInfAOrB
& signProd
) |
(isInfC
& opSignC
)
215 |
(notNaN_addZeros
& !roundingMode_min
& signProd
& opSignC
)
216 |
(notNaN_addZeros
& roundingMode_min
& (signProd | opSignC
)))
219 special_signOut
= specialNotNaN_signOut
;
220 #/*-------------------------------------------------------------------
221 # *-------------------------------------------------------------------*/
224 mulAddC
= Signal(prodWidth
, reset_less
=True)
225 intermed_compactState
= Signal(6, reset_less
=True)
227 comb
+= mulAddC
.eq(alignedSigC
[1:prodWidth
+1])
228 comb
+= intermed_compactState
.eq(Cat(
230 notNaN_addZeros |
(~specialCase
& alignedSigC
[0]),
231 isInfAOrB | isInfC |
(~specialCase
& CIsDominant
),
232 isNaNAny |
(~specialCase
& doSubMags
),
233 invalidExc |
(~specialCase
& signProd
),
235 intermed_sExp
= sExpSum
;
236 intermed_CDom_CAlignDist
= CAlignDist
[(clog2(sigWidth
+ 1) - 1):0];
237 intermed_highAlignedSigC
=
238 alignedSigC
[(sigSumWidth
- 1):(prodWidth
+ 1)];
242 #/*------------------------------------------------------------------------
243 #*------------------------------------------------------------------------*/
246 mulAddRecFNToRaw_postMul
#(parameter expWidth = 3, parameter sigWidth = 3) (
247 intermed_compactState
,
249 intermed_CDom_CAlignDist
,
250 intermed_highAlignedSigC
,
261 `include
"HardFloat_localFuncs.vi"
262 input [5:0] intermed_compactState
;
263 input signed
[(expWidth
+ 1):0] intermed_sExp
;
264 input [(clog2(sigWidth
+ 1) - 1):0] intermed_CDom_CAlignDist
;
265 input [(sigWidth
+ 1):0] intermed_highAlignedSigC
;
266 input [sigWidth
*2:0] mulAddResult
;
267 input [2:0] roundingMode
;
273 output signed
[(expWidth
+ 1):0] out_sExp
;
274 output
[(sigWidth
+ 2):0] out_sig
;
276 /*------------------------------------------------------------------------
277 *------------------------------------------------------------------------*/
278 localparam prodWidth
= sigWidth
*2;
279 localparam sigSumWidth
= sigWidth
+ prodWidth
+ 3;
280 /*------------------------------------------------------------------------
281 *------------------------------------------------------------------------*/
282 wire specialCase
= intermed_compactState
[5];
283 assign invalidExc
= specialCase
&& intermed_compactState
[4];
284 assign out_isNaN
= specialCase
&& intermed_compactState
[3];
285 assign out_isInf
= specialCase
&& intermed_compactState
[2];
286 wire notNaN_addZeros
= specialCase
&& intermed_compactState
[1];
287 wire signProd
= intermed_compactState
[4];
288 wire doSubMags
= intermed_compactState
[3];
289 wire CIsDominant
= intermed_compactState
[2];
290 wire bit0AlignedSigC
= intermed_compactState
[1];
291 wire special_signOut
= intermed_compactState
[0];
292 `ifdef HardFloat_propagateNaNPayloads
293 wire
[(sigWidth
- 2):0] fractNaN
= intermed_highAlignedSigC
;
295 /*------------------------------------------------------------------------
296 *------------------------------------------------------------------------*/
297 wire opSignC
= signProd ^ doSubMags
;
298 wire
[(sigWidth
+ 1):0] incHighAlignedSigC
= intermed_highAlignedSigC
+ 1;
299 wire
[(sigSumWidth
- 1):0] sigSum
=
300 {mulAddResult
[prodWidth
] ? incHighAlignedSigC
301 : intermed_highAlignedSigC
,
302 mulAddResult
[(prodWidth
- 1):0],
304 wire roundingMode_min
= (roundingMode
== `round_min
);
305 /*------------------------------------------------------------------------
306 *------------------------------------------------------------------------*/
307 wire CDom_sign
= opSignC
;
308 wire signed
[(expWidth
+ 1):0] CDom_sExp
= intermed_sExp
- doSubMags
;
309 wire
[(sigWidth
*2 + 1):0] CDom_absSigSum
=
310 doSubMags ? ~sigSum
[(sigSumWidth
- 1):(sigWidth
+ 1)]
311 : {0b0, intermed_highAlignedSigC
[(sigWidth
+ 1):sigWidth
],
312 sigSum
[(sigSumWidth
- 3):(sigWidth
+ 2)]};
313 wire CDom_absSigSumExtra
=
314 doSubMags ?
!(&sigSum
[sigWidth
:1]) : |sigSum
[(sigWidth
+ 1):1];
315 wire
[(sigWidth
+ 4):0] CDom_mainSig
=
316 (CDom_absSigSum
<<intermed_CDom_CAlignDist
)>>(sigWidth
- 3);
317 wire
[((sigWidth |
3) - 1):0] CDom_grainAlignedLowSig
=
318 CDom_absSigSum
[(sigWidth
- 1):0]<<(~sigWidth
& 3);
319 wire
[sigWidth
/4:0] CDom_reduced4LowSig
;
320 compressBy4
#(sigWidth | 3)
321 compressBy4_CDom_absSigSum(
322 CDom_grainAlignedLowSig
, CDom_reduced4LowSig
);
323 wire
[(sigWidth
/4 - 1):0] CDom_sigExtraMask
;
324 lowMaskLoHi
#(clog2(sigWidth + 1) - 2, 0, sigWidth/4)
325 lowMask_CDom_sigExtraMask(
326 intermed_CDom_CAlignDist
[(clog2(sigWidth
+ 1) - 1):2],
329 wire CDom_reduced4SigExtra
= |
(CDom_reduced4LowSig
& CDom_sigExtraMask
);
330 wire
[(sigWidth
+ 2):0] CDom_sig
=
332 (|CDom_mainSig
[2:0]) | CDom_reduced4SigExtra | CDom_absSigSumExtra
};
333 /*------------------------------------------------------------------------
334 *------------------------------------------------------------------------*/
335 wire notCDom_signSigSum
= sigSum
[prodWidth
+ 3];
336 wire
[(prodWidth
+ 2):0] notCDom_absSigSum
=
337 notCDom_signSigSum ? ~sigSum
[(prodWidth
+ 2):0]
338 : sigSum
[(prodWidth
+ 2):0] + doSubMags
;
339 wire
[(prodWidth
+ 2)/2:0] notCDom_reduced2AbsSigSum
;
340 compressBy2
#(prodWidth + 3)
341 compressBy2_notCDom_absSigSum(
342 notCDom_absSigSum
, notCDom_reduced2AbsSigSum
);
343 wire
[(clog2(prodWidth
+ 4) - 2):0] notCDom_normDistReduced2
;
344 countLeadingZeros
#((prodWidth + 2)/2 + 1, clog2(prodWidth + 4) - 1)
345 countLeadingZeros_notCDom(
346 notCDom_reduced2AbsSigSum
, notCDom_normDistReduced2
);
347 wire
[(clog2(prodWidth
+ 4) - 1):0] notCDom_nearNormDist
=
348 notCDom_normDistReduced2
<<1;
349 wire signed
[(expWidth
+ 1):0] notCDom_sExp
=
350 intermed_sExp
- notCDom_nearNormDist
;
351 wire
[(sigWidth
+ 4):0] notCDom_mainSig
=
352 ({0b0, notCDom_absSigSum
}<<notCDom_nearNormDist
)>>(sigWidth
- 1);
353 wire
[(((sigWidth
/2 + 1) |
1) - 1):0] CDom_grainAlignedLowReduced2Sig
=
354 notCDom_reduced2AbsSigSum
[sigWidth
/2:0]<<((sigWidth
/2) & 1);
355 wire
[(sigWidth
+ 2)/4:0] notCDom_reduced4AbsSigSum
;
356 compressBy2
#((sigWidth/2 + 1) | 1)
357 compressBy2_notCDom_reduced2AbsSigSum(
358 CDom_grainAlignedLowReduced2Sig
, notCDom_reduced4AbsSigSum
);
359 wire
[((sigWidth
+ 2)/4 - 1):0] notCDom_sigExtraMask
;
360 lowMaskLoHi
#(clog2(prodWidth + 4) - 2, 0, (sigWidth + 2)/4)
361 lowMask_notCDom_sigExtraMask(
362 notCDom_normDistReduced2
[(clog2(prodWidth
+ 4) - 2):1],
365 wire notCDom_reduced4SigExtra
=
366 |
(notCDom_reduced4AbsSigSum
& notCDom_sigExtraMask
);
367 wire
[(sigWidth
+ 2):0] notCDom_sig
=
369 (|notCDom_mainSig
[2:0]) | notCDom_reduced4SigExtra
};
370 wire notCDom_completeCancellation
=
371 (notCDom_sig
[(sigWidth
+ 2):(sigWidth
+ 1)] == 0);
373 notCDom_completeCancellation ? roundingMode_min
374 : signProd ^ notCDom_signSigSum
;
375 /*------------------------------------------------------------------------
376 *------------------------------------------------------------------------*/
378 notNaN_addZeros |
(!CIsDominant
&& notCDom_completeCancellation
);
380 ( specialCase
&& special_signOut
)
381 |
(!specialCase
&& CIsDominant
&& CDom_sign
)
382 |
(!specialCase
&& !CIsDominant
&& notCDom_sign
);
383 assign out_sExp
= CIsDominant ? CDom_sExp
: notCDom_sExp
;
384 assign out_sig
= CIsDominant ? CDom_sig
: notCDom_sig
;
388 /*----------------------------------------------------------------------------
389 *----------------------------------------------------------------------------*/
392 mulAddRecFNToRaw
#(parameter expWidth = 3, parameter sigWidth = 3) (
393 input [(`floatControlWidth
- 1):0] control
,
395 input [(expWidth
+ sigWidth
):0] a
,
396 input [(expWidth
+ sigWidth
):0] b
,
397 input [(expWidth
+ sigWidth
):0] c
,
398 input [2:0] roundingMode
,
404 output signed
[(expWidth
+ 1):0] out_sExp
,
405 output
[(sigWidth
+ 2):0] out_sig
407 `include
"HardFloat_localFuncs.vi"
409 wire
[(sigWidth
- 1):0] mulAddA
, mulAddB
;
410 wire
[(sigWidth
*2 - 1):0] mulAddC
;
411 wire
[5:0] intermed_compactState
;
412 wire signed
[(expWidth
+ 1):0] intermed_sExp
;
413 wire
[(clog2(sigWidth
+ 1) - 1):0] intermed_CDom_CAlignDist
;
414 wire
[(sigWidth
+ 1):0] intermed_highAlignedSigC
;
415 mulAddRecFNToRaw_preMul
#(expWidth, sigWidth)
426 intermed_compactState
,
428 intermed_CDom_CAlignDist
,
429 intermed_highAlignedSigC
431 wire
[sigWidth
*2:0] mulAddResult
= mulAddA
* mulAddB
+ mulAddC
;
432 mulAddRecFNToRaw_postMul
#(expWidth, sigWidth)
434 intermed_compactState
,
436 intermed_CDom_CAlignDist
,
437 intermed_highAlignedSigC
,
451 /*----------------------------------------------------------------------------
452 *----------------------------------------------------------------------------*/
455 mulAddRecFN
#(parameter expWidth = 3, parameter sigWidth = 3) (
456 input [(`floatControlWidth
- 1):0] control
,
458 input [(expWidth
+ sigWidth
):0] a
,
459 input [(expWidth
+ sigWidth
):0] b
,
460 input [(expWidth
+ sigWidth
):0] c
,
461 input [2:0] roundingMode
,
462 output
[(expWidth
+ sigWidth
):0] out
,
463 output
[4:0] exceptionFlags
466 wire invalidExc
, out_isNaN
, out_isInf
, out_isZero
, out_sign
;
467 wire signed
[(expWidth
+ 1):0] out_sExp
;
468 wire
[(sigWidth
+ 2):0] out_sig
;
469 mulAddRecFNToRaw
#(expWidth, sigWidth)
485 roundRawFNToRecFN
#(expWidth, sigWidth, 0)