| /*============================================================================ | |
| This Verilog source file is part of the Berkeley HardFloat IEEE Floating-Point | |
| Arithmetic Package, Release 1, by John R. Hauser. | |
| Copyright 2019 The Regents of the University of California. All rights | |
| reserved. | |
| Redistribution and use in source and binary forms, with or without | |
| modification, are permitted provided that the following conditions are met: | |
| 1. Redistributions of source code must retain the above copyright notice, | |
| this list of conditions, and the following disclaimer. | |
| 2. Redistributions in binary form must reproduce the above copyright notice, | |
| this list of conditions, and the following disclaimer in the documentation | |
| and/or other materials provided with the distribution. | |
| 3. Neither the name of the University nor the names of its contributors may | |
| be used to endorse or promote products derived from this software without | |
| specific prior written permission. | |
| THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY | |
| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE | |
| DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY | |
| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| =============================================================================*/ | |
| //`include "HardFloat_consts.vi" | |
| /*---------------------------------------------------------------------------- | |
| *----------------------------------------------------------------------------*/ | |
| `define round_near_even 3'b000 | |
| `define round_minMag 3'b001 | |
| `define round_min 3'b010 | |
| `define round_max 3'b011 | |
| `define round_near_maxMag 3'b100 | |
| `define round_odd 3'b110 | |
| /*---------------------------------------------------------------------------- | |
| *----------------------------------------------------------------------------*/ | |
| `define floatControlWidth 1 | |
| `define flControl_tininessBeforeRounding 1'b0 | |
| `define flControl_tininessAfterRounding 1'b1 | |
| /*---------------------------------------------------------------------------- | |
| *----------------------------------------------------------------------------*/ | |
| `define flRoundOpt_sigMSBitAlwaysZero 1 | |
| `define flRoundOpt_subnormsAlwaysExact 2 | |
| `define flRoundOpt_neverUnderflows 4 | |
| `define flRoundOpt_neverOverflows 8 | |
| //`include "HardFloat_specialize.vi" | |
| `define HardFloat_signDefaultNaN 0 | |
| `define HardFloat_fractDefaultNaN(sigWidth) {1'b1, {((sigWidth) - 2){1'b0}}} | |
| /*---------------------------------------------------------------------------- | |
| *----------------------------------------------------------------------------*/ | |
| module | |
| addRecFNToRaw#(parameter expWidth = 3, parameter sigWidth = 3) ( | |
| input [(`floatControlWidth - 1):0] control, | |
| input subOp, | |
| input [(expWidth + sigWidth):0] a, | |
| input [(expWidth + sigWidth):0] b, | |
| input [2:0] roundingMode, | |
| output invalidExc, | |
| output out_isNaN, | |
| output out_isInf, | |
| output out_isZero, | |
| output out_sign, | |
| output signed [(expWidth + 1):0] out_sExp, | |
| output [(sigWidth + 2):0] out_sig | |
| ); | |
| //`include "HardFloat_localFuncs.vi" | |
| function integer clog2; | |
| input integer a; | |
| begin | |
| a = a - 1; | |
| for (clog2 = 0; a > 0; clog2 = clog2 + 1) a = a>>1; | |
| end | |
| endfunction | |
| /*------------------------------------------------------------------------ | |
| *------------------------------------------------------------------------*/ | |
| localparam alignDistWidth = clog2(sigWidth); | |
| /*------------------------------------------------------------------------ | |
| *------------------------------------------------------------------------*/ | |
| wire isNaNA, isInfA, isZeroA, signA; | |
| wire signed [(expWidth + 1):0] sExpA; | |
| wire [sigWidth:0] sigA; | |
| recFNToRawFN#(expWidth, sigWidth) | |
| recFNToRawFN_a(a, isNaNA, isInfA, isZeroA, signA, sExpA, sigA); | |
| wire isSigNaNA; | |
| isSigNaNRecFN#(expWidth, sigWidth) isSigNaN_a(a, isSigNaNA); | |
| wire isNaNB, isInfB, isZeroB, signB; | |
| wire signed [(expWidth + 1):0] sExpB; | |
| wire [sigWidth:0] sigB; | |
| recFNToRawFN#(expWidth, sigWidth) | |
| recFNToRawFN_b(b, isNaNB, isInfB, isZeroB, signB, sExpB, sigB); | |
| wire effSignB = subOp ? !signB : signB; | |
| wire isSigNaNB; | |
| isSigNaNRecFN#(expWidth, sigWidth) isSigNaN_b(b, isSigNaNB); | |
| /*------------------------------------------------------------------------ | |
| *------------------------------------------------------------------------*/ | |
| wire eqSigns = (signA == effSignB); | |
| wire notEqSigns_signZero = (roundingMode == `round_min) ? 1 : 0; | |
| wire signed [(expWidth + 1):0] sDiffExps = sExpA - sExpB; | |
| wire [(alignDistWidth - 1):0] modNatAlignDist = | |
| (sDiffExps < 0) ? sExpB - sExpA : sDiffExps; | |
| wire isMaxAlign = | |
| (sDiffExps>>>alignDistWidth != 0) | |
| && ((sDiffExps>>>alignDistWidth != -1) | |
| || (sDiffExps[(alignDistWidth - 1):0] == 0)); | |
| wire [(alignDistWidth - 1):0] alignDist = | |
| isMaxAlign ? (1<<alignDistWidth) - 1 : modNatAlignDist; | |
| wire closeSubMags = !eqSigns && !isMaxAlign && (modNatAlignDist <= 1); | |
| /*------------------------------------------------------------------------ | |
| *------------------------------------------------------------------------*/ | |
| wire signed [(sigWidth + 2):0] close_alignedSigA = | |
| ((0 <= sDiffExps) && sDiffExps[0] ? sigA<<2 : 0) | |
| | ((0 <= sDiffExps) && !sDiffExps[0] ? sigA<<1 : 0) | |
| | ((sDiffExps < 0) ? sigA : 0); | |
| wire signed [(sigWidth + 2):0] close_sSigSum = | |
| close_alignedSigA - (sigB<<1); | |
| wire [(sigWidth + 1):0] close_sigSum = | |
| (close_sSigSum < 0) ? -close_sSigSum : close_sSigSum; | |
| wire [(sigWidth + 1 + (sigWidth & 1)):0] close_adjustedSigSum = | |
| close_sigSum<<(sigWidth & 1); | |
| wire [(sigWidth + 1)/2:0] close_reduced2SigSum; | |
| compressBy2#(sigWidth + 2 + (sigWidth & 1)) | |
| compressBy2_close_sigSum(close_adjustedSigSum, close_reduced2SigSum); | |
| wire [(alignDistWidth - 1):0] close_normDistReduced2; | |
| countLeadingZeros#((sigWidth + 3)/2, alignDistWidth) | |
| countLeadingZeros_close(close_reduced2SigSum, close_normDistReduced2); | |
| wire [(alignDistWidth - 1):0] close_nearNormDist = | |
| close_normDistReduced2<<1; | |
| wire [(sigWidth + 2):0] close_sigOut = | |
| (close_sigSum<<close_nearNormDist)<<1; | |
| wire close_totalCancellation = | |
| !(|close_sigOut[(sigWidth + 2):(sigWidth + 1)]); | |
| wire close_notTotalCancellation_signOut = signA ^ (close_sSigSum < 0); | |
| /*------------------------------------------------------------------------ | |
| *------------------------------------------------------------------------*/ | |
| wire far_signOut = (sDiffExps < 0) ? effSignB : signA; | |
| wire [(sigWidth - 1):0] far_sigLarger = (sDiffExps < 0) ? sigB : sigA; | |
| wire [(sigWidth - 1):0] far_sigSmaller = (sDiffExps < 0) ? sigA : sigB; | |
| wire [(sigWidth + 4):0] far_mainAlignedSigSmaller = | |
| {far_sigSmaller, 5'b0}>>alignDist; | |
| wire [(sigWidth + 1)/4:0] far_reduced4SigSmaller; | |
| compressBy4#(sigWidth + 2) | |
| compressBy4_far_sigSmaller( | |
| {far_sigSmaller, 2'b00}, far_reduced4SigSmaller); | |
| wire [(sigWidth + 1)/4:0] far_roundExtraMask; | |
| lowMaskHiLo#(alignDistWidth - 2, (sigWidth + 5)/4, 0) | |
| lowMask_far_roundExtraMask( | |
| alignDist[(alignDistWidth - 1):2], far_roundExtraMask); | |
| wire [(sigWidth + 2):0] far_alignedSigSmaller = | |
| {far_mainAlignedSigSmaller>>3, | |
| (|far_mainAlignedSigSmaller[2:0]) | |
| || (|(far_reduced4SigSmaller & far_roundExtraMask))}; | |
| wire far_subMags = !eqSigns; | |
| wire [(sigWidth + 3):0] far_negAlignedSigSmaller = | |
| far_subMags ? {1'b1, ~far_alignedSigSmaller} | |
| : {1'b0, far_alignedSigSmaller}; | |
| wire [(sigWidth + 3):0] far_sigSum = | |
| (far_sigLarger<<3) + far_negAlignedSigSmaller + far_subMags; | |
| wire [(sigWidth + 2):0] far_sigOut = | |
| far_subMags ? far_sigSum : far_sigSum>>1 | far_sigSum[0]; | |
| /*------------------------------------------------------------------------ | |
| *------------------------------------------------------------------------*/ | |
| wire notSigNaN_invalidExc = isInfA && isInfB && !eqSigns; | |
| wire notNaN_isInfOut = isInfA || isInfB; | |
| wire addZeros = isZeroA && isZeroB; | |
| wire notNaN_specialCase = notNaN_isInfOut || addZeros; | |
| wire notNaN_isZeroOut = | |
| addZeros | |
| || (!notNaN_isInfOut && closeSubMags && close_totalCancellation); | |
| wire notNaN_signOut = | |
| (eqSigns && signA ) | |
| || (isInfA && signA ) | |
| || (isInfB && effSignB ) | |
| || (notNaN_isZeroOut && !eqSigns && notEqSigns_signZero) | |
| || (!notNaN_specialCase && closeSubMags && !close_totalCancellation | |
| && close_notTotalCancellation_signOut) | |
| || (!notNaN_specialCase && !closeSubMags && far_signOut); | |
| wire signed [(expWidth + 1):0] common_sExpOut = | |
| (closeSubMags || (sDiffExps < 0) ? sExpB : sExpA) | |
| - (closeSubMags ? close_nearNormDist : far_subMags); | |
| wire [(sigWidth + 2):0] common_sigOut = | |
| closeSubMags ? close_sigOut : far_sigOut; | |
| /*------------------------------------------------------------------------ | |
| *------------------------------------------------------------------------*/ | |
| assign invalidExc = isSigNaNA || isSigNaNB || notSigNaN_invalidExc; | |
| assign out_isInf = notNaN_isInfOut; | |
| assign out_isZero = notNaN_isZeroOut; | |
| assign out_sExp = common_sExpOut; | |
| `ifdef HardFloat_propagateNaNPayloads | |
| assign out_isNaN = isNaNA || isNaNB || notSigNaN_invalidExc; | |
| wire signNaN; | |
| wire [(sigWidth - 2):0] fractNaN; | |
| propagateFloatNaN_add#(sigWidth) | |
| propagateNaN( | |
| control, | |
| subOp, | |
| isNaNA, | |
| signA, | |
| sigA[(sigWidth - 2):0], | |
| isNaNB, | |
| signB, | |
| sigB[(sigWidth - 2):0], | |
| signNaN, | |
| fractNaN | |
| ); | |
| assign out_sign = out_isNaN ? signNaN : notNaN_signOut; | |
| assign out_sig = out_isNaN ? {1'b1, fractNaN, 2'b00} : common_sigOut; | |
| `else | |
| assign out_isNaN = isNaNA || isNaNB; | |
| assign out_sign = notNaN_signOut; | |
| assign out_sig = common_sigOut; | |
| `endif | |
| endmodule | |
| /*---------------------------------------------------------------------------- | |
| *----------------------------------------------------------------------------*/ | |
| module | |
| addRecFN#(parameter expWidth = 3, parameter sigWidth = 3) ( | |
| input [(`floatControlWidth - 1):0] control, | |
| input subOp, | |
| input [(expWidth + sigWidth):0] a, | |
| input [(expWidth + sigWidth):0] b, | |
| input [2:0] roundingMode, | |
| output [(expWidth + sigWidth):0] out, | |
| output [4:0] exceptionFlags | |
| ); | |
| /*------------------------------------------------------------------------ | |
| *------------------------------------------------------------------------*/ | |
| wire invalidExc, out_isNaN, out_isInf, out_isZero, out_sign; | |
| wire signed [(expWidth + 1):0] out_sExp; | |
| wire [(sigWidth + 2):0] out_sig; | |
| addRecFNToRaw#(expWidth, sigWidth) | |
| addRecFNToRaw( | |
| control, | |
| subOp, | |
| a, | |
| b, | |
| roundingMode, | |
| invalidExc, | |
| out_isNaN, | |
| out_isInf, | |
| out_isZero, | |
| out_sign, | |
| out_sExp, | |
| out_sig | |
| ); | |
| /*------------------------------------------------------------------------ | |
| *------------------------------------------------------------------------*/ | |
| roundRawFNToRecFN#(expWidth, sigWidth, `flRoundOpt_subnormsAlwaysExact) | |
| roundRawOut( | |
| control, | |
| invalidExc, | |
| 1'b0, | |
| out_isNaN, | |
| out_isInf, | |
| out_isZero, | |
| out_sign, | |
| out_sExp, | |
| out_sig, | |
| roundingMode, | |
| out, | |
| exceptionFlags | |
| ); | |
| endmodule | |