blob: af38d9caabe5330daced91cd152b64f45ee08680 [file] [log] [blame]
/*============================================================================
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}}}
/*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
| Computes a division or square root for floating-point in recoded form.
| Multiple clock cycles are needed for each division or square-root operation,
| except possibly in special cases.
*----------------------------------------------------------------------------*/
module
divSqrtRecFNToRaw_small#(
parameter expWidth = 3, parameter sigWidth = 3, parameter options = 0
) (
/*--------------------------------------------------------------------
*--------------------------------------------------------------------*/
input nReset,
input clock,
/*--------------------------------------------------------------------
*--------------------------------------------------------------------*/
input [(`floatControlWidth - 1):0] control,
/*--------------------------------------------------------------------
*--------------------------------------------------------------------*/
output inReady,
input inValid,
input sqrtOp,
input [(expWidth + sigWidth):0] a,
input [(expWidth + sigWidth):0] b,
input [2:0] roundingMode,
/*--------------------------------------------------------------------
*--------------------------------------------------------------------*/
output outValid,
output sqrtOpOut,
output [2:0] roundingModeOut,
output invalidExc,
output infiniteExc,
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
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
wire isNaNA_S, isInfA_S, isZeroA_S, signA_S;
wire signed [(expWidth + 1):0] sExpA_S;
wire [sigWidth:0] sigA_S;
recFNToRawFN#(expWidth, sigWidth)
recFNToRawFN_a(
a, isNaNA_S, isInfA_S, isZeroA_S, signA_S, sExpA_S, sigA_S);
wire isSigNaNA_S;
isSigNaNRecFN#(expWidth, sigWidth) isSigNaN_a(a, isSigNaNA_S);
wire isNaNB_S, isInfB_S, isZeroB_S, signB_S;
wire signed [(expWidth + 1):0] sExpB_S;
wire [sigWidth:0] sigB_S;
recFNToRawFN#(expWidth, sigWidth)
recFNToRawFN_b(
b, isNaNB_S, isInfB_S, isZeroB_S, signB_S, sExpB_S, sigB_S);
wire isSigNaNB_S;
isSigNaNRecFN#(expWidth, sigWidth) isSigNaN_b(b, isSigNaNB_S);
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
wire notSigNaNIn_invalidExc_S_div =
(isZeroA_S && isZeroB_S) || (isInfA_S && isInfB_S);
wire notSigNaNIn_invalidExc_S_sqrt = !isNaNA_S && !isZeroA_S && signA_S;
wire majorExc_S =
sqrtOp ? isSigNaNA_S || notSigNaNIn_invalidExc_S_sqrt
: isSigNaNA_S || isSigNaNB_S || notSigNaNIn_invalidExc_S_div
|| (!isNaNA_S && !isInfA_S && isZeroB_S);
wire isNaN_S =
sqrtOp ? isNaNA_S || notSigNaNIn_invalidExc_S_sqrt
: isNaNA_S || isNaNB_S || notSigNaNIn_invalidExc_S_div;
`ifdef HardFloat_propagateNaNPayloads
wire signNaN_S;
wire [(sigWidth - 2):0] fractNaN_S;
propagateFloatNaN_divSqrt#(sigWidth)
propagateNaN(
control,
sqrtOp,
isNaNA_S,
signA_S,
sigA_S[(sigWidth - 2):0],
isNaNB_S,
signB_S,
sigB_S[(sigWidth - 2):0],
signNaN_S,
fractNaN_S
);
`endif
wire isInf_S = sqrtOp ? isInfA_S : isInfA_S || isZeroB_S;
wire isZero_S = sqrtOp ? isZeroA_S : isZeroA_S || isInfB_S;
wire sign_S = signA_S ^ (!sqrtOp && signB_S);
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
wire specialCaseA_S = isNaNA_S || isInfA_S || isZeroA_S;
wire specialCaseB_S = isNaNB_S || isInfB_S || isZeroB_S;
wire normalCase_S_div = !specialCaseA_S && !specialCaseB_S;
wire normalCase_S_sqrt = !specialCaseA_S && !signA_S;
wire normalCase_S = sqrtOp ? normalCase_S_sqrt : normalCase_S_div;
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
wire signed [(expWidth + 2):0] sExpQuot_S_div =
sExpA_S + {{3{sExpB_S[expWidth]}}, ~sExpB_S[(expWidth - 1):0]};
wire signed [(expWidth + 1):0] sSatExpQuot_S_div =
{(7<<(expWidth - 2) <= sExpQuot_S_div) ? 4'b0110
: sExpQuot_S_div[(expWidth + 1):(expWidth - 2)],
sExpQuot_S_div[(expWidth - 3): 0]};
wire evenSqrt_S = sqrtOp && !sExpA_S[0];
wire oddSqrt_S = sqrtOp && sExpA_S[0];
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
reg [(clog2(sigWidth + 3) - 1):0] cycleNum;
reg sqrtOp_Z, majorExc_Z;
reg isNaN_Z, isInf_Z, isZero_Z, sign_Z;
reg signed [(expWidth + 1):0] sExp_Z;
reg [(sigWidth - 2):0] fractB_Z;
reg [2:0] roundingMode_Z;
/*------------------------------------------------------------------------
| (The most-significant and least-significant bits of 'rem_Z' are needed
| only for square roots.)
*------------------------------------------------------------------------*/
reg [(sigWidth + 1):0] rem_Z;
reg notZeroRem_Z;
reg [(sigWidth + 1):0] sigX_Z;
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
wire idle = (cycleNum == 0);
assign inReady = (cycleNum <= 1);
wire entering = inReady && inValid;
wire entering_normalCase = entering && normalCase_S;
wire skipCycle2 = (cycleNum == 3) && sigX_Z[sigWidth + 1];
always @(negedge nReset, posedge clock) begin
if (!nReset) begin
cycleNum <= 0;
end else begin
if (!idle || inValid) begin
cycleNum <=
(entering && !normalCase_S ? 1 : 0)
| (entering_normalCase
? (sqrtOp ? (sExpA_S[0] ? sigWidth : sigWidth + 1)
: sigWidth + 2)
: 0)
| (!idle && !skipCycle2 ? cycleNum - 1 : 0)
| (!idle && skipCycle2 ? 1 : 0);
end
end
end
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
always @(posedge clock) begin
if (entering) begin
sqrtOp_Z <= sqrtOp;
majorExc_Z <= majorExc_S;
isNaN_Z <= isNaN_S;
isInf_Z <= isInf_S;
isZero_Z <= isZero_S;
`ifdef HardFloat_propagateNaNPayloads
sign_Z <= isNaN_S ? signNaN_S : sign_S;
`else
sign_Z <= sign_S;
`endif
end
if (entering_normalCase) begin
sExp_Z <=
sqrtOp ? (sExpA_S>>>1) + (1<<(expWidth - 1))
: sSatExpQuot_S_div;
roundingMode_Z <= roundingMode;
end
if (entering_normalCase && !sqrtOp) begin
fractB_Z <= sigB_S[(sigWidth - 2):0];
end
end
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
wire [1:0] decHiSigA_S = sigA_S[(sigWidth - 1):(sigWidth - 2)] - 1;
wire [(sigWidth + 2):0] rem =
(inReady && !oddSqrt_S ? sigA_S<<1 : 0)
| (inReady && oddSqrt_S
? {decHiSigA_S, sigA_S[(sigWidth - 3):0], 3'b0} : 0)
| (!inReady ? rem_Z<<1 : 0);
wire [sigWidth:0] bitMask = ({{(sigWidth + 2){1'b0}}, 1'b1}<<cycleNum)>>2;
wire [(sigWidth + 1):0] trialTerm =
( inReady && !sqrtOp ? sigB_S<<1 : 0)
| ( inReady && evenSqrt_S ? 1<<sigWidth : 0)
| ( inReady && oddSqrt_S ? 5<<(sigWidth - 1) : 0)
| (!inReady && !sqrtOp_Z ? {1'b1, fractB_Z}<<1 : 0)
| (!inReady && sqrtOp_Z ? sigX_Z<<1 | bitMask : 0);
wire signed [(sigWidth + 3):0] trialRem = rem - trialTerm;
wire newBit = (0 <= trialRem);
always @(posedge clock) begin
if (entering_normalCase || (cycleNum > 2)) begin
rem_Z <= newBit ? trialRem : rem;
end
`ifdef HardFloat_propagateNaNPayloads
if (
(entering && isNaN_S) || entering_normalCase
|| (!inReady && newBit)
) begin
notZeroRem_Z <= (trialRem != 0);
sigX_Z <=
(inReady && isNaN_S ? {1'b1, fractNaN_S, 2'b00} : 0)
| (inReady && !isNaN_S && !sqrtOp ? newBit<<(sigWidth + 1) : 0)
| (inReady && !isNaN_S && sqrtOp ? 1<<sigWidth : 0)
| (inReady && !isNaN_S && oddSqrt_S
? newBit<<(sigWidth - 1) : 0)
| (!inReady ? sigX_Z | bitMask : 0);
end
`else
if (entering_normalCase || (!inReady && newBit)) begin
notZeroRem_Z <= (trialRem != 0);
sigX_Z <=
( inReady && !sqrtOp ? newBit<<(sigWidth + 1) : 0)
| ( inReady && sqrtOp ? 1<<sigWidth : 0)
| ( inReady && oddSqrt_S ? newBit<<(sigWidth - 1) : 0)
| (!inReady ? sigX_Z | bitMask : 0);
end
`endif
end
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
assign outValid = (cycleNum == 1);
assign sqrtOpOut = sqrtOp_Z;
assign roundingModeOut = roundingMode_Z;
assign invalidExc = majorExc_Z && isNaN_Z;
assign infiniteExc = majorExc_Z && !isNaN_Z;
assign out_isNaN = isNaN_Z;
assign out_isInf = isInf_Z;
assign out_isZero = isZero_Z;
assign out_sign = sign_Z;
assign out_sExp = sExp_Z;
assign out_sig = {sigX_Z, notZeroRem_Z};
endmodule
/*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/
module
divSqrtRecFN_small#(
parameter expWidth = 3, parameter sigWidth = 3, parameter options = 0
) (
/*--------------------------------------------------------------------
*--------------------------------------------------------------------*/
input nReset,
input clock,
/*--------------------------------------------------------------------
*--------------------------------------------------------------------*/
input [(`floatControlWidth - 1):0] control,
/*--------------------------------------------------------------------
*--------------------------------------------------------------------*/
output inReady,
input inValid,
input sqrtOp,
input [(expWidth + sigWidth):0] a,
input [(expWidth + sigWidth):0] b,
input [2:0] roundingMode,
/*--------------------------------------------------------------------
*--------------------------------------------------------------------*/
output outValid,
output sqrtOpOut,
output [(expWidth + sigWidth):0] out,
output [4:0] exceptionFlags
);
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
wire sqrtOpOut;
wire [2:0] roundingModeOut;
wire invalidExc, infiniteExc, out_isNaN, out_isInf, out_isZero, out_sign;
wire signed [(expWidth + 1):0] out_sExp;
wire [(sigWidth + 2):0] out_sig;
divSqrtRecFNToRaw_small#(expWidth, sigWidth, options)
divSqrtRecFNToRaw(
nReset,
clock,
control,
inReady,
inValid,
sqrtOp,
a,
b,
roundingMode,
outValid,
sqrtOpOut,
roundingModeOut,
invalidExc,
infiniteExc,
out_isNaN,
out_isInf,
out_isZero,
out_sign,
out_sExp,
out_sig
);
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
roundRawFNToRecFN#(expWidth, sigWidth, 0)
roundRawOut(
control,
invalidExc,
infiniteExc,
out_isNaN,
out_isInf,
out_isZero,
out_sign,
out_sExp,
out_sig,
roundingModeOut,
out,
exceptionFlags
);
endmodule