blob: 590abe969bddccabe201f2a15ae8a40d14032c95 [file] [log] [blame]
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the “License”); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
////////////////////////////////////////////////////////////////////////////////
// Company: IIS @ ETHZ - Federal Institute of Technology //
// //
// Engineers: Lei Li lile@iis.ee.ethz.ch //
// //
// Additional contributions by: //
// //
// //
// //
// Create Date: 09/03/2018 //
// Design Name: FPU //
// Module Name: norm_div_sqrt_mvp.sv //
// Project Name: //
// Language: SystemVerilog //
// //
// Description: Floating point Normalizer/Rounding unit //
// Since this module is design as a combinatinal logic, it can//
// be added arbinary register stages for different frequency //
// in the wrapper module. //
// //
// //
// //
// Revision Date: 12/04/2018 //
// Lei Li //
// To address some requirements by Stefan //
// //
// //
// //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
import defs_div_sqrt_mvp::*;
module norm_div_sqrt_mvp
(//Inputs
input logic [C_MANT_FP64+4:0] Mant_in_DI, // Include the needed 4-bit for rounding and hidden bit
input logic signed [C_EXP_FP64+1:0] Exp_in_DI,
input logic Sign_in_DI,
input logic Div_enable_SI,
input logic Sqrt_enable_SI,
input logic Inf_a_SI,
input logic Inf_b_SI,
input logic Zero_a_SI,
input logic Zero_b_SI,
input logic NaN_a_SI,
input logic NaN_b_SI,
input logic SNaN_SI,
input logic [C_RM-1:0] RM_SI,
input logic Full_precision_SI,
input logic FP32_SI,
input logic FP64_SI,
input logic FP16_SI,
input logic FP16ALT_SI,
//Outputs
output logic [C_EXP_FP64+C_MANT_FP64:0] Result_DO,
output logic [4:0] Fflags_SO //{NV,DZ,OF,UF,NX}
);
logic Sign_res_D;
logic NV_OP_S;
logic Exp_OF_S;
logic Exp_UF_S;
logic Div_Zero_S;
logic In_Exact_S;
/////////////////////////////////////////////////////////////////////////////
// Normalization //
/////////////////////////////////////////////////////////////////////////////
logic [C_MANT_FP64:0] Mant_res_norm_D;
logic [C_EXP_FP64-1:0] Exp_res_norm_D;
/////////////////////////////////////////////////////////////////////////////
// Right shift operations for negtive exponents //
/////////////////////////////////////////////////////////////////////////////
logic [C_EXP_FP64+1:0] Exp_Max_RS_FP64_D;
logic [C_EXP_FP32+1:0] Exp_Max_RS_FP32_D;
logic [C_EXP_FP16+1:0] Exp_Max_RS_FP16_D;
logic [C_EXP_FP16ALT+1:0] Exp_Max_RS_FP16ALT_D;
//
assign Exp_Max_RS_FP64_D=Exp_in_DI[C_EXP_FP64:0]+C_MANT_FP64+1; // to check exponent after (C_MANT_FP64+1)-bit >> when Exp_in_DI is negative
assign Exp_Max_RS_FP32_D=Exp_in_DI[C_EXP_FP32:0]+C_MANT_FP32+1; // to check exponent after (C_MANT_FP32+1)-bit >> when Exp_in_DI is negative
assign Exp_Max_RS_FP16_D=Exp_in_DI[C_EXP_FP16:0]+C_MANT_FP16+1; // to check exponent after (C_MANT_FP16+1)-bit >> when Exp_in_DI is negative
assign Exp_Max_RS_FP16ALT_D=Exp_in_DI[C_EXP_FP16ALT:0]+C_MANT_FP16ALT+1; // to check exponent after (C_MANT_FP16ALT+1)-bit >> when Exp_in_DI is negative
logic [C_EXP_FP64+1:0] Num_RS_D;
assign Num_RS_D=~Exp_in_DI+1+1; // How many right shifts(RS) are needed to generate a denormal number? >> is need only when Exp_in_DI is negative
logic [C_MANT_FP64:0] Mant_RS_D;
logic [C_MANT_FP64+4:0] Mant_forsticky_D;
assign {Mant_RS_D,Mant_forsticky_D} ={Mant_in_DI,{(C_MANT_FP64+1){1'b0}} } >>(Num_RS_D); //
//
logic [C_EXP_FP64+1:0] Exp_subOne_D;
assign Exp_subOne_D = Exp_in_DI -1;
//normalization
logic [1:0] Mant_lower_D;
logic Mant_sticky_bit_D;
logic [C_MANT_FP64+4:0] Mant_forround_D;
always_comb
begin
if(NaN_a_SI) // if a is NaN, return NaN
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b0;
Mant_res_norm_D={1'b0,C_MANT_NAN_FP64};
Exp_res_norm_D='1;
Mant_forround_D='0;
Sign_res_D=1'b0;
NV_OP_S = SNaN_SI;
end
else if(NaN_b_SI) //if b is NaN, return NaN
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b0;
Mant_res_norm_D={1'b0,C_MANT_NAN_FP64};
Exp_res_norm_D='1;
Mant_forround_D='0;
Sign_res_D=1'b0;
NV_OP_S = SNaN_SI;
end
else if(Inf_a_SI)
begin
if(Div_enable_SI&&Inf_b_SI) //Inf/Inf, retrurn NaN
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b0;
Mant_res_norm_D={1'b0,C_MANT_NAN_FP64};
Exp_res_norm_D='1;
Mant_forround_D='0;
Sign_res_D=1'b0;
NV_OP_S = 1'b1;
end
else if (Sqrt_enable_SI && Sign_in_DI) begin // catch sqrt(-inf)
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b0;
Mant_res_norm_D={1'b0,C_MANT_NAN_FP64};
Exp_res_norm_D='1;
Mant_forround_D='0;
Sign_res_D=1'b0;
NV_OP_S = 1'b1;
end else begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b1;
Exp_UF_S=1'b0;
Mant_res_norm_D= '0;
Exp_res_norm_D='1;
Mant_forround_D='0;
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
end
else if(Div_enable_SI&&Inf_b_SI)
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b1;
Exp_UF_S=1'b0;
Mant_res_norm_D= '0;
Exp_res_norm_D='0;
Mant_forround_D='0;
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
else if(Zero_a_SI)
begin
if(Div_enable_SI&&Zero_b_SI)
begin
Div_Zero_S=1'b1;
Exp_OF_S=1'b0;
Exp_UF_S=1'b0;
Mant_res_norm_D={1'b0,C_MANT_NAN_FP64};
Exp_res_norm_D='1;
Mant_forround_D='0;
Sign_res_D=1'b0;
NV_OP_S = 1'b1;
end
else
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b0;
Mant_res_norm_D='0;
Exp_res_norm_D='0;
Mant_forround_D='0;
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
end
else if(Div_enable_SI&&(Zero_b_SI)) //div Zero
begin
Div_Zero_S=1'b1;
Exp_OF_S=1'b0;
Exp_UF_S=1'b0;
Mant_res_norm_D='0;
Exp_res_norm_D='1;
Mant_forround_D='0;
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
else if(Sign_in_DI&&Sqrt_enable_SI) //sqrt(-a)
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b0;
Mant_res_norm_D={1'b0,C_MANT_NAN_FP64};
Exp_res_norm_D='1;
Mant_forround_D='0;
Sign_res_D=1'b0;
NV_OP_S = 1'b1;
end
else if((Exp_in_DI[C_EXP_FP64:0]=='0))
begin
if(Mant_in_DI!='0) //Exp=0, Mant!=0, it is denormal
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b1;
Mant_res_norm_D={1'b0,Mant_in_DI[C_MANT_FP64+4:5]};
Exp_res_norm_D='0;
Mant_forround_D={Mant_in_DI[4:0],{(C_MANT_FP64){1'b0}} };
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
else // Zero
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b0;
Mant_res_norm_D='0;
Exp_res_norm_D='0;
Mant_forround_D='0;
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
end
else if((Exp_in_DI[C_EXP_FP64:0]==C_EXP_ONE_FP64)&&(~Mant_in_DI[C_MANT_FP64+4])) //denormal
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b1;
Mant_res_norm_D=Mant_in_DI[C_MANT_FP64+4:4];
Exp_res_norm_D='0;
Mant_forround_D={Mant_in_DI[3:0],{(C_MANT_FP64+1){1'b0}}};
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
else if(Exp_in_DI[C_EXP_FP64+1]) //minus //consider format
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b1;
Mant_res_norm_D={Mant_RS_D[C_MANT_FP64:0]};
Exp_res_norm_D='0;
Mant_forround_D={Mant_forsticky_D[C_MANT_FP64+4:0]}; //??
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
else if( (Exp_in_DI[C_EXP_FP32]&&FP32_SI) | (Exp_in_DI[C_EXP_FP64]&&FP64_SI) | (Exp_in_DI[C_EXP_FP16]&&FP16_SI) | (Exp_in_DI[C_EXP_FP16ALT]&&FP16ALT_SI) ) //OF
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b1;
Exp_UF_S=1'b0;
Mant_res_norm_D='0;
Exp_res_norm_D='1;
Mant_forround_D='0;
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
else if( ((Exp_in_DI[C_EXP_FP32-1:0]=='1)&&FP32_SI) | ((Exp_in_DI[C_EXP_FP64-1:0]=='1)&&FP64_SI) | ((Exp_in_DI[C_EXP_FP16-1:0]=='1)&&FP16_SI) | ((Exp_in_DI[C_EXP_FP16ALT-1:0]=='1)&&FP16ALT_SI) )//255
begin
if(~Mant_in_DI[C_MANT_FP64+4]) // MSB=0
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b0;
Mant_res_norm_D=Mant_in_DI[C_MANT_FP64+3:3];
Exp_res_norm_D=Exp_subOne_D;
Mant_forround_D={Mant_in_DI[2:0],{(C_MANT_FP64+2){1'b0}}};
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
else if(Mant_in_DI!='0) //NaN
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b1;
Exp_UF_S=1'b0;
Mant_res_norm_D= '0;
Exp_res_norm_D='1;
Mant_forround_D='0;
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
else //infinity
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b1;
Exp_UF_S=1'b0;
Mant_res_norm_D= '0;
Exp_res_norm_D='1;
Mant_forround_D='0;
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
end
else if(Mant_in_DI[C_MANT_FP64+4]) //normal numbers with 1.XXX
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b0;
Mant_res_norm_D= Mant_in_DI[C_MANT_FP64+4:4];
Exp_res_norm_D=Exp_in_DI[C_EXP_FP64-1:0];
Mant_forround_D={Mant_in_DI[3:0],{(C_MANT_FP64+1){1'b0}}};
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
else //normal numbers with 0.1XX
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b0;
Mant_res_norm_D=Mant_in_DI[C_MANT_FP64+3:3];
Exp_res_norm_D=Exp_subOne_D;
Mant_forround_D={Mant_in_DI[2:0],{(C_MANT_FP64+2){1'b0}}};
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
end
/////////////////////////////////////////////////////////////////////////////
// Rounding enable only for full precision (Full_precision_SI==1'b1) //
/////////////////////////////////////////////////////////////////////////////
logic [C_MANT_FP64:0] Mant_upper_D;
logic [C_MANT_FP64+1:0] Mant_upperRounded_D;
logic Mant_roundUp_S;
logic Mant_rounded_S;
always_comb //determine which bits for Mant_lower_D and Mant_sticky_bit_D
begin
if(FP32_SI)
begin
Mant_upper_D = {Mant_res_norm_D[C_MANT_FP64:C_MANT_FP64-C_MANT_FP32], {(C_MANT_FP64-C_MANT_FP32){1'b0}} };
Mant_lower_D = Mant_res_norm_D[C_MANT_FP64-C_MANT_FP32-1:C_MANT_FP64-C_MANT_FP32-2];
Mant_sticky_bit_D = | Mant_res_norm_D[C_MANT_FP64-C_MANT_FP32-3:0];
end
else if(FP64_SI)
begin
Mant_upper_D = Mant_res_norm_D[C_MANT_FP64:0];
Mant_lower_D = Mant_forround_D[C_MANT_FP64+4:C_MANT_FP64+3];
Mant_sticky_bit_D = | Mant_forround_D[C_MANT_FP64+3:0];
end
else if(FP16_SI)
begin
Mant_upper_D = {Mant_res_norm_D[C_MANT_FP64:C_MANT_FP64-C_MANT_FP16], {(C_MANT_FP64-C_MANT_FP16){1'b0}} };
Mant_lower_D = Mant_res_norm_D[C_MANT_FP64-C_MANT_FP16-1:C_MANT_FP64-C_MANT_FP16-2];
Mant_sticky_bit_D = | Mant_res_norm_D[C_MANT_FP64-C_MANT_FP16-3:30];
end
else //FP16ALT
begin
Mant_upper_D = {Mant_res_norm_D[C_MANT_FP64:C_MANT_FP64-C_MANT_FP16ALT], {(C_MANT_FP64-C_MANT_FP16ALT){1'b0}} };
Mant_lower_D = Mant_res_norm_D[C_MANT_FP64-C_MANT_FP16ALT-1:C_MANT_FP64-C_MANT_FP16ALT-2];
Mant_sticky_bit_D = | Mant_res_norm_D[C_MANT_FP64-C_MANT_FP16ALT-3:30];
end
end
assign Mant_rounded_S = (|(Mant_lower_D))| Mant_sticky_bit_D;
always_comb //determine whether to round up or not
begin
Mant_roundUp_S = 1'b0;
case (RM_SI)
C_RM_NEAREST :
Mant_roundUp_S = Mant_lower_D[1] && ((Mant_lower_D[0] | Mant_sticky_bit_D )| ( (FP32_SI&&Mant_upper_D[C_MANT_FP64-C_MANT_FP32]) | (FP64_SI&&Mant_upper_D[0]) | (FP16_SI&&Mant_upper_D[C_MANT_FP64-C_MANT_FP16]) | (FP16ALT_SI&&Mant_upper_D[C_MANT_FP64-C_MANT_FP16ALT]) ) );
C_RM_TRUNC :
Mant_roundUp_S = 0;
C_RM_PLUSINF :
Mant_roundUp_S = Mant_rounded_S & ~Sign_in_DI;
C_RM_MINUSINF:
Mant_roundUp_S = Mant_rounded_S & Sign_in_DI;
default :
Mant_roundUp_S = 0;
endcase // case (RM_DI)
end // always_comb begin
logic Mant_renorm_S;
logic [C_MANT_FP64:0] Mant_roundUp_Vector_S; // for all the formats
assign Mant_roundUp_Vector_S={7'h0,(FP16ALT_SI&&Mant_roundUp_S),2'h0,(FP16_SI&&Mant_roundUp_S),12'h0,(FP32_SI&&Mant_roundUp_S),28'h0,(FP64_SI&&Mant_roundUp_S)};
assign Mant_upperRounded_D = Mant_upper_D + Mant_roundUp_Vector_S;
assign Mant_renorm_S = Mant_upperRounded_D[C_MANT_FP64+1];
/////////////////////////////////////////////////////////////////////////////
// Renormalization for Rounding //
/////////////////////////////////////////////////////////////////////////////
logic [C_MANT_FP64-1:0] Mant_res_round_D;
logic [C_EXP_FP64-1:0] Exp_res_round_D;
assign Mant_res_round_D = (Mant_renorm_S)?Mant_upperRounded_D[C_MANT_FP64:1]:Mant_upperRounded_D[C_MANT_FP64-1:0]; // including the process of the hidden bit
assign Exp_res_round_D = Exp_res_norm_D+Mant_renorm_S;
/////////////////////////////////////////////////////////////////////////////
// Output Assignments //
/////////////////////////////////////////////////////////////////////////////
logic [C_MANT_FP64-1:0] Mant_before_format_ctl_D;
logic [C_EXP_FP64-1:0] Exp_before_format_ctl_D;
assign Mant_before_format_ctl_D = Full_precision_SI ? Mant_res_round_D : Mant_res_norm_D;
assign Exp_before_format_ctl_D = Full_precision_SI ? Exp_res_round_D : Exp_res_norm_D;
always_comb //NaN Boxing
begin //
if(FP32_SI)
begin
Result_DO ={32'hffff_ffff,Sign_res_D,Exp_before_format_ctl_D[C_EXP_FP32-1:0],Mant_before_format_ctl_D[C_MANT_FP64-1:C_MANT_FP64-C_MANT_FP32]};
end
else if(FP64_SI)
begin
Result_DO ={Sign_res_D,Exp_before_format_ctl_D[C_EXP_FP64-1:0],Mant_before_format_ctl_D[C_MANT_FP64-1:0]};
end
else if(FP16_SI)
begin
Result_DO ={48'hffff_ffff_ffff,Sign_res_D,Exp_before_format_ctl_D[C_EXP_FP16-1:0],Mant_before_format_ctl_D[C_MANT_FP64-1:C_MANT_FP64-C_MANT_FP16]};
end
else
begin
Result_DO ={48'hffff_ffff_ffff,Sign_res_D,Exp_before_format_ctl_D[C_EXP_FP16ALT-1:0],Mant_before_format_ctl_D[C_MANT_FP64-1:C_MANT_FP64-C_MANT_FP16ALT]};
end
end
assign In_Exact_S = (~Full_precision_SI) | Mant_rounded_S;
assign Fflags_SO = {NV_OP_S,Div_Zero_S,Exp_OF_S,Exp_UF_S,In_Exact_S}; //{NV,DZ,OF,UF,NX}
endmodule // norm_div_sqrt_mvp