cvw/wally-pipelined/src/fpu/rounder_div.sv
2021-05-01 02:18:01 +00:00

189 lines
7.4 KiB
Systemverilog
Executable File

//
// The rounder takes as inputs a 64-bit value to be rounded, A, the
// exponent of the value to be rounded, the sign of the final result, Sign,
// the precision of the results, P, and the two-bit rounding mode, rm.
// It produces a rounded 52-bit result, Z, the exponent of the rounded
// result, Z_exp, and a flag that indicates if the result was rounded,
// Inexact. The rounding mode has the following values.
// rm Modee
// 00 round-to-nearest-even
// 01 round-toward-zero
// 10 round-toward-plus infinity
// 11 round-toward-minus infinity
//
module rounder_div (Result, DenormIO, Flags, rm, P, OvEn,
UnEn, exp_diff, sel_inv, Invalid, DenormIn,
SignR, q1, qm1, qp1, q0, qm0, qp0, regr_out);
input [2:0] rm;
input P;
input OvEn;
input UnEn;
input [12:0] exp_diff;
input [2:0] sel_inv;
input Invalid;
input DenormIn;
input SignR;
input [63:0] q1;
input [63:0] qm1;
input [63:0] qp1;
input [63:0] q0;
input [63:0] qm0;
input [63:0] qp0;
input [127:0] regr_out;
output [63:0] Result;
output DenormIO;
output [4:0] Flags;
supply1 vdd;
supply0 vss;
wire Rsign;
wire [10:0] Rexp;
wire [12:0] Texp;
wire [51:0] Rmant;
wire [63:0] Tmant;
wire [51:0] Smant;
wire Rzero;
wire Gdp, Gsp, G;
wire UnFlow_SP, UnFlow_DP, UnderFlow;
wire OvFlow_SP, OvFlow_DP, OverFlow;
wire Inexact;
wire Round_zero;
wire Infinite;
wire VeryLarge;
wire Largest;
wire Div0;
wire Adj_exp;
wire Valid;
wire NaN;
wire Texp_l7z;
wire Texp_l7o;
wire OvCon;
wire [1:0] mux_mant;
wire sign_rem;
wire [63:0] q, qm, qp;
wire exp_ovf, exp_ovfSP, exp_ovfDP;
logic zero_rem;
// Remainder = 0?
assign zero_rem = ~(|regr_out);
// Remainder Sign
assign sign_rem = ~regr_out[127];
// choose correct Guard bit [1,2) or [0,1)
assign Gdp = q1[63] ? q1[10] : q0[10];
assign Gsp = q1[63] ? q1[39] : q0[39];
assign G = P ? Gsp : Gdp;
// Selection of Rounding (from logic/switching)
assign mux_mant[1] = (SignR&rm[1]&rm[0]&G) | (!SignR&rm[1]&!rm[0]&G) |
(!rm[1]&!rm[0]&G&!sign_rem) |
(SignR&rm[1]&rm[0]&!zero_rem&!sign_rem) |
(!SignR&rm[1]&!rm[0]&!zero_rem&!sign_rem);
assign mux_mant[0] = (!SignR&rm[0]&!G&!zero_rem&sign_rem) |
(!rm[1]&rm[0]&!G&!zero_rem&sign_rem) |
(SignR&rm[1]&!rm[0]&!G&!zero_rem&sign_rem);
// Which Q?
mux2 #(64) mx1 (q0, q1, q1[63], q);
mux2 #(64) mx2 (qm0, qm1, q1[63], qm);
mux2 #(64) mx3 (qp0, qp1, q1[63], qp);
// Choose Q, Q+1, Q-1
mux3 #(64) mx4 (q, qm, qp, mux_mant, Tmant);
assign Smant = Tmant[62:11];
// Compute the value of the exponent
// exponent is modified if we choose:
// 1.) we choose any qm0, qp0, q0 (since we shift mant)
// 2.) we choose qp and we overflow (for RU)
assign exp_ovf = |{qp[62:40], (qp[39:11] & {29{~P}})};
assign Texp = exp_diff - {{12{vss}}, ~q1[63]} + {{12{vss}}, mux_mant[1]&qp1[63]&~exp_ovf}; // KEP used to be 13{vss}
// Overflow only occurs for double precision, if Texp[10] to Texp[0] are
// all ones. To encourage sharing with single precision overflow detection,
// the lower 7 bits are tested separately.
assign Texp_l7o = Texp[6]&Texp[5]&Texp[4]&Texp[3]&Texp[2]&Texp[1]&Texp[0];
assign OvFlow_DP = (~Texp[12]&Texp[11]) | (Texp[10]&Texp[9]&Texp[8]&Texp[7]&Texp_l7o);
// Overflow occurs for single precision if (Texp[10] is one) and
// ((Texp[9] or Texp[8] or Texp[7]) is one) or (Texp[6] to Texp[0]
// are all ones.
assign OvFlow_SP = Texp[10]&(Texp[9]|Texp[8]|Texp[7]|Texp_l7o);
// Underflow occurs for double precision if (Texp[11]/Texp[10] is one) or
// Texp[10] to Texp[0] are all zeros.
assign Texp_l7z = ~Texp[6]&~Texp[5]&~Texp[4]&~Texp[3]&~Texp[2]&~Texp[1]&~Texp[0];
assign UnFlow_DP = (Texp[12]&Texp[11]) | ~Texp[11]&~Texp[10]&~Texp[9]&~Texp[8]&~Texp[7]&Texp_l7z;
// Underflow occurs for single precision if (Texp[10] is zero) and
// (Texp[9] or Texp[8] or Texp[7]) is zero.
assign UnFlow_SP = ~Texp[10]&(~Texp[9]|~Texp[8]|~Texp[7]|Texp_l7z);
// Set the overflow and underflow flags. They should not be set if
// the input was infinite or NaN or the output of the adder is zero.
// 00 = Valid
// 10 = NaN
assign Valid = (~sel_inv[2]&~sel_inv[1]&~sel_inv[0]);
assign NaN = ~sel_inv[1]& sel_inv[0];
assign UnderFlow = (P & UnFlow_SP | UnFlow_DP) & Valid;
assign OverFlow = (P & OvFlow_SP | OvFlow_DP) & Valid;
assign Div0 = sel_inv[2]&sel_inv[1]&~sel_inv[0];
// The DenormIO is set if underflow has occurred or if their was a
// denormalized input.
assign DenormIO = DenormIn | UnderFlow;
// The final result is Inexact if any rounding occurred ((i.e., R or S
// is one), or (if the result overflows ) or (if the result underflows and the
// underflow trap is not enabled)) and (value of the result was not previous set
// by an exception case).
assign Inexact = (G|~zero_rem|OverFlow|(UnderFlow&~UnEn))&Valid;
// Set the IEEE Exception Flags: Inexact, Underflow, Overflow, Div_By_0,
// Invlalid.
assign Flags = {Inexact, UnderFlow, OverFlow, Div0, Invalid};
// Determine sign
assign Rzero = UnderFlow | (~sel_inv[2]&sel_inv[1]&sel_inv[0]);
assign Rsign = SignR;
// The exponent of the final result is zero if the final result is
// zero or a denorm, all ones if the final result is NaN or Infinite
// or overflow occurred and the magnitude of the number is
// not rounded toward from zero, and all ones with an LSB of zero
// if overflow occurred and the magnitude of the number is
// rounded toward zero. If the result is single precision,
// Texp[7] shoud be inverted. When the Overflow trap is enabled (OvEn = 1)
// and overflow occurs and the operation is not conversion, bits 10 and 9 are
// inverted for double precision, and bits 7 and 6 are inverted for single precision.
assign Round_zero = ~rm[1]&rm[0] | ~SignR&rm[0] | SignR&rm[1]&~rm[0];
assign VeryLarge = OverFlow & ~OvEn;
assign Infinite = (VeryLarge & ~Round_zero) | sel_inv[1];
assign Largest = VeryLarge & Round_zero;
assign Adj_exp = OverFlow & OvEn;
assign Rexp[10:1] = ({10{~Valid}} |
{Texp[10]&~Adj_exp, Texp[9]&~Adj_exp, Texp[8],
(Texp[7]^P)&~(Adj_exp&P), Texp[6]&~(Adj_exp&P), Texp[5:1]} |
{10{VeryLarge}})&{10{~Rzero | NaN}};
assign Rexp[0] = ({~Valid} | Texp[0] | Infinite)&(~Rzero | NaN)&~Largest;
// If the result is zero or infinity, the mantissa is all zeros.
// If the result is NaN, the mantissa is 10...0
// If the result the largest floating point number, the mantissa
// is all ones. Otherwise, the mantissa is not changed.
assign Rmant[51] = Largest | NaN | (Smant[51]&~Infinite&~Rzero);
assign Rmant[50:0] = {51{Largest}} | (Smant[50:0]&{51{~Infinite&Valid&~Rzero}});
// For single precision, the 8 least significant bits of the exponent
// and 23 most significant bits of the mantissa contain bits used
// for the final result. A double precision result is returned if
// overflow has occurred, the overflow trap is enabled, and a conversion
// is being performed.
assign OvCon = OverFlow & OvEn;
assign Result = (P&~OvCon) ? {Rsign, Rexp[7:0], Rmant[51:29], {32{vss}}}
: {Rsign, Rexp, Rmant};
endmodule // rounder