/*============================================================================ | |
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 | |