/*============================================================================ | |
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 | |
recFNToRawFN#(parameter expWidth = 3, parameter sigWidth = 3) ( | |
input [(expWidth + sigWidth):0] in, | |
output isNaN, | |
output isInf, | |
output isZero, | |
output sign, | |
output signed [(expWidth + 1):0] sExp, | |
output [sigWidth:0] sig | |
); | |
/*------------------------------------------------------------------------ | |
*------------------------------------------------------------------------*/ | |
wire [expWidth:0] exp; | |
wire [(sigWidth - 2):0] fract; | |
assign {sign, exp, fract} = in; | |
wire isSpecial = (exp>>(expWidth - 1) == 'b11); | |
/*------------------------------------------------------------------------ | |
*------------------------------------------------------------------------*/ | |
assign isNaN = isSpecial && exp[expWidth - 2]; | |
assign isInf = isSpecial && !exp[expWidth - 2]; | |
assign isZero = (exp>>(expWidth - 2) == 'b000); | |
assign sExp = exp; | |
assign sig = {1'b0, !isZero, fract}; | |
endmodule | |
/*---------------------------------------------------------------------------- | |
*----------------------------------------------------------------------------*/ | |
module | |
roundAnyRawFNToRecFN#( | |
parameter inExpWidth = 3, | |
parameter inSigWidth = 3, | |
parameter outExpWidth = 3, | |
parameter outSigWidth = 3, | |
parameter options = 0 | |
) ( | |
input [(`floatControlWidth - 1):0] control, | |
input invalidExc, // overrides 'infiniteExc' and 'in_*' inputs | |
input infiniteExc, // overrides 'in_*' inputs except 'in_sign' | |
input in_isNaN, | |
input in_isInf, | |
input in_isZero, | |
input in_sign, | |
input signed [(inExpWidth + 1):0] in_sExp, // limited range allowed | |
input [inSigWidth:0] in_sig, | |
input [2:0] roundingMode, | |
output [(outExpWidth + outSigWidth):0] out, | |
output [4:0] exceptionFlags | |
); | |
/*------------------------------------------------------------------------ | |
*------------------------------------------------------------------------*/ | |
localparam sigMSBitAlwaysZero = | |
((options & `flRoundOpt_sigMSBitAlwaysZero) != 0); | |
localparam effectiveInSigWidth = | |
sigMSBitAlwaysZero ? inSigWidth : inSigWidth + 1; | |
localparam neverUnderflows = | |
((options | |
& (`flRoundOpt_neverUnderflows | |
| `flRoundOpt_subnormsAlwaysExact)) | |
!= 0) | |
|| (inExpWidth < outExpWidth); | |
localparam neverOverflows = | |
((options & `flRoundOpt_neverOverflows) != 0) | |
|| (inExpWidth < outExpWidth); | |
localparam adjustedExpWidth = | |
(inExpWidth < outExpWidth) ? outExpWidth + 1 | |
: (inExpWidth == outExpWidth) ? inExpWidth + 2 | |
: inExpWidth + 3; | |
localparam outNaNExp = 7<<(outExpWidth - 2); | |
localparam outInfExp = 6<<(outExpWidth - 2); | |
localparam outMaxFiniteExp = outInfExp - 1; | |
localparam outMinNormExp = (1<<(outExpWidth - 1)) + 2; | |
localparam outMinNonzeroExp = outMinNormExp - outSigWidth + 1; | |
/*------------------------------------------------------------------------ | |
*------------------------------------------------------------------------*/ | |
wire roundingMode_near_even = (roundingMode == `round_near_even); | |
wire roundingMode_minMag = (roundingMode == `round_minMag); | |
wire roundingMode_min = (roundingMode == `round_min); | |
wire roundingMode_max = (roundingMode == `round_max); | |
wire roundingMode_near_maxMag = (roundingMode == `round_near_maxMag); | |
wire roundingMode_odd = (roundingMode == `round_odd); | |
wire roundMagUp = | |
(roundingMode_min && in_sign) || (roundingMode_max && !in_sign); | |
/*------------------------------------------------------------------------ | |
*------------------------------------------------------------------------*/ | |
wire isNaNOut = invalidExc || (!infiniteExc && in_isNaN); | |
`ifdef HardFloat_propagateNaNPayloads | |
wire propagateNaNPayload = isNaNOut; | |
`else | |
wire propagateNaNPayload = 0; | |
`endif | |
wire signed [(adjustedExpWidth - 1):0] sAdjustedExp = | |
in_sExp + ((1<<outExpWidth) - (1<<inExpWidth)); | |
wire [(outSigWidth + 2):0] adjustedSig; | |
generate | |
if (inSigWidth <= outSigWidth + 2) begin | |
assign adjustedSig = in_sig<<(outSigWidth - inSigWidth + 2); | |
end else begin | |
assign adjustedSig = | |
{in_sig[inSigWidth:(inSigWidth - outSigWidth - 1)], | |
|in_sig[(inSigWidth - outSigWidth - 2):0]}; | |
end | |
endgenerate | |
wire doShiftSigDown1 = | |
sigMSBitAlwaysZero ? 0 : adjustedSig[outSigWidth + 2]; | |
/*------------------------------------------------------------------------ | |
*------------------------------------------------------------------------*/ | |
wire [outExpWidth:0] common_expOut; | |
wire [(outSigWidth - 2):0] common_fractOut; | |
wire common_overflow, common_totalUnderflow, common_underflow; | |
wire common_inexact; | |
generate | |
if ( | |
neverOverflows && neverUnderflows | |
&& (effectiveInSigWidth <= outSigWidth) | |
) begin | |
/*---------------------------------------------------------------- | |
*----------------------------------------------------------------*/ | |
assign common_expOut = sAdjustedExp + doShiftSigDown1; | |
assign common_fractOut = | |
doShiftSigDown1 ? adjustedSig>>3 : adjustedSig>>2; | |
assign common_overflow = 0; | |
assign common_totalUnderflow = 0; | |
assign common_underflow = 0; | |
assign common_inexact = 0; | |
end else begin | |
/*---------------------------------------------------------------- | |
*----------------------------------------------------------------*/ | |
wire [(outSigWidth + 2):0] roundMask; | |
if (neverUnderflows) begin | |
assign roundMask = {doShiftSigDown1, 2'b11}; | |
end else begin | |
wire [outSigWidth:0] roundMask_main; | |
lowMaskLoHi#( | |
outExpWidth + 1, | |
outMinNormExp - outSigWidth - 1, | |
outMinNormExp | |
) lowMask_roundMask( | |
sAdjustedExp[outExpWidth:0] | |
| (propagateNaNPayload ? 1'b1<<outExpWidth : 1'b0), | |
roundMask_main | |
); | |
assign roundMask = {roundMask_main | doShiftSigDown1, 2'b11}; | |
end | |
wire [(outSigWidth + 2):0] shiftedRoundMask = roundMask>>1; | |
wire [(outSigWidth + 2):0] roundPosMask = | |
~shiftedRoundMask & roundMask; | |
wire roundPosBit = | |
(|(adjustedSig[(outSigWidth + 2):3] | |
& roundPosMask[(outSigWidth + 2):3])) | |
|| ((|(adjustedSig[2:0] & roundPosMask[2:0])) | |
&& !propagateNaNPayload); | |
wire anyRoundExtra = | |
(|(adjustedSig[(outSigWidth + 2):3] | |
& shiftedRoundMask[(outSigWidth + 2):3])) | |
|| ((|(adjustedSig[2:0] & shiftedRoundMask[2:0])) | |
&& !propagateNaNPayload); | |
wire anyRound = roundPosBit || anyRoundExtra; | |
/*---------------------------------------------------------------- | |
*----------------------------------------------------------------*/ | |
wire roundIncr = | |
((roundingMode_near_even || roundingMode_near_maxMag) | |
&& roundPosBit) | |
|| (roundMagUp && anyRound); | |
wire [(outSigWidth + 1):0] roundedSig = | |
roundIncr | |
? (((adjustedSig | roundMask)>>2) + 1) | |
& ~(roundingMode_near_even && roundPosBit | |
&& !anyRoundExtra | |
? roundMask>>1 : 0) | |
: (adjustedSig & ~roundMask)>>2 | |
| (roundingMode_odd && anyRound | |
? roundPosMask>>1 : 0); | |
wire signed [adjustedExpWidth:0] sExtAdjustedExp = sAdjustedExp; | |
wire signed [adjustedExpWidth:0] sRoundedExp = | |
sExtAdjustedExp + (roundedSig>>outSigWidth); | |
/*---------------------------------------------------------------- | |
*----------------------------------------------------------------*/ | |
assign common_expOut = sRoundedExp; | |
assign common_fractOut = | |
doShiftSigDown1 ? roundedSig>>1 : roundedSig; | |
assign common_overflow = | |
neverOverflows ? 0 : (sRoundedExp>>>(outExpWidth - 1) >= 3); | |
assign common_totalUnderflow = | |
neverUnderflows ? 0 : (sRoundedExp < outMinNonzeroExp); | |
/*---------------------------------------------------------------- | |
*----------------------------------------------------------------*/ | |
wire unboundedRange_roundPosBit = | |
doShiftSigDown1 ? adjustedSig[2] : adjustedSig[1]; | |
wire unboundedRange_anyRound = | |
(doShiftSigDown1 && adjustedSig[2]) || (|adjustedSig[1:0]); | |
wire unboundedRange_roundIncr = | |
((roundingMode_near_even || roundingMode_near_maxMag) | |
&& unboundedRange_roundPosBit) | |
|| (roundMagUp && unboundedRange_anyRound); | |
wire roundCarry = | |
doShiftSigDown1 | |
? roundedSig[outSigWidth + 1] : roundedSig[outSigWidth]; | |
assign common_underflow = | |
neverUnderflows ? 0 | |
: common_totalUnderflow | |
|| (anyRound && (sAdjustedExp>>>outExpWidth <= 0) | |
&& (doShiftSigDown1 | |
? roundMask[3] : roundMask[2]) | |
&& !(((control | |
& `flControl_tininessAfterRounding) | |
!= 0) | |
&& !(doShiftSigDown1 ? roundMask[4] | |
: roundMask[3]) | |
&& roundCarry && roundPosBit | |
&& unboundedRange_roundIncr)); | |
/*---------------------------------------------------------------- | |
*----------------------------------------------------------------*/ | |
assign common_inexact = common_totalUnderflow || anyRound; | |
end | |
endgenerate | |
/*------------------------------------------------------------------------ | |
*------------------------------------------------------------------------*/ | |
wire notNaN_isSpecialInfOut = infiniteExc || in_isInf; | |
wire commonCase = !isNaNOut && !notNaN_isSpecialInfOut && !in_isZero; | |
wire overflow = commonCase && common_overflow; | |
wire underflow = commonCase && common_underflow; | |
wire inexact = overflow || (commonCase && common_inexact); | |
/*------------------------------------------------------------------------ | |
*------------------------------------------------------------------------*/ | |
wire overflow_roundMagUp = | |
roundingMode_near_even || roundingMode_near_maxMag || roundMagUp; | |
wire pegMinNonzeroMagOut = | |
commonCase && common_totalUnderflow | |
&& (roundMagUp || roundingMode_odd); | |
wire pegMaxFiniteMagOut = overflow && !overflow_roundMagUp; | |
wire notNaN_isInfOut = | |
notNaN_isSpecialInfOut || (overflow && overflow_roundMagUp); | |
/*------------------------------------------------------------------------ | |
*------------------------------------------------------------------------*/ | |
`ifdef HardFloat_propagateNaNPayloads | |
wire signOut = in_sign; | |
`else | |
wire signOut = isNaNOut ? `HardFloat_signDefaultNaN : in_sign; | |
`endif | |
wire [outExpWidth:0] expOut = | |
(common_expOut | |
& ~(in_isZero || common_totalUnderflow ? 7<<(outExpWidth - 2) : 0) | |
& ~(pegMinNonzeroMagOut ? ~outMinNonzeroExp : 0) | |
& ~(pegMaxFiniteMagOut ? 1<<(outExpWidth - 1) : 0) | |
& ~(notNaN_isInfOut ? 1<<(outExpWidth - 2) : 0)) | |
| (pegMinNonzeroMagOut ? outMinNonzeroExp : 0) | |
| (pegMaxFiniteMagOut ? outMaxFiniteExp : 0) | |
| (notNaN_isInfOut ? outInfExp : 0) | |
| (isNaNOut ? outNaNExp : 0); | |
`ifdef HardFloat_propagateNaNPayloads | |
wire [(outSigWidth - 2):0] fractOut = | |
{isNaNOut | |
|| (!in_isZero && !common_totalUnderflow | |
&& common_fractOut[outSigWidth - 2]), | |
isNaNOut || (!in_isZero && !common_totalUnderflow) | |
? common_fractOut[(outSigWidth - 3):0] : 1'b0} | |
| {(outSigWidth - 1){pegMaxFiniteMagOut}}; | |
`else | |
wire [(outSigWidth - 2):0] fractOut = | |
(isNaNOut ? `HardFloat_fractDefaultNaN(outSigWidth) : 0) | |
| (!in_isZero && !common_totalUnderflow | |
? common_fractOut & `HardFloat_fractDefaultNaN(outSigWidth) : 0) | |
| (!isNaNOut && !in_isZero && !common_totalUnderflow | |
? common_fractOut & ~`HardFloat_fractDefaultNaN(outSigWidth) | |
: 0) | |
| {(outSigWidth - 1){pegMaxFiniteMagOut}}; | |
`endif | |
assign out = {signOut, expOut, fractOut}; | |
assign exceptionFlags = | |
{invalidExc, infiniteExc, overflow, underflow, inexact}; | |
endmodule | |
/*---------------------------------------------------------------------------- | |
*----------------------------------------------------------------------------*/ | |
module | |
roundRawFNToRecFN#( | |
parameter expWidth = 3, | |
parameter sigWidth = 3, | |
parameter options = 0 | |
) ( | |
input [(`floatControlWidth - 1):0] control, | |
input invalidExc, // overrides 'infiniteExc' and 'in_*' inputs | |
input infiniteExc, // overrides 'in_*' inputs except 'in_sign' | |
input in_isNaN, | |
input in_isInf, | |
input in_isZero, | |
input in_sign, | |
input signed [(expWidth + 1):0] in_sExp, // limited range allowed | |
input [(sigWidth + 2):0] in_sig, | |
input [2:0] roundingMode, | |
output [(expWidth + sigWidth):0] out, | |
output [4:0] exceptionFlags | |
); | |
roundAnyRawFNToRecFN#(expWidth, sigWidth + 2, expWidth, sigWidth, options) | |
roundAnyRawFNToRecFN( | |
control, | |
invalidExc, | |
infiniteExc, | |
in_isNaN, | |
in_isInf, | |
in_isZero, | |
in_sign, | |
in_sExp, | |
in_sig, | |
roundingMode, | |
out, | |
exceptionFlags | |
); | |
endmodule | |