From 33e5a078bf6c7cafc2e5e1d8472e7111685119b6 Mon Sep 17 00:00:00 2001 From: Katherine Parry Date: Thu, 14 Oct 2021 15:25:31 -0700 Subject: [PATCH] cvtfp module documented --- wally-pipelined/src/fpu/cvtfp.sv | 172 ++++++++++++++++++++----------- 1 file changed, 113 insertions(+), 59 deletions(-) diff --git a/wally-pipelined/src/fpu/cvtfp.sv b/wally-pipelined/src/fpu/cvtfp.sv index 9b489efb1..fb9f5cf1f 100644 --- a/wally-pipelined/src/fpu/cvtfp.sv +++ b/wally-pipelined/src/fpu/cvtfp.sv @@ -1,24 +1,42 @@ // `include "wally-config.vh" module cvtfp ( - input logic [10:0] XExpE, - input logic [52:0] XManE, - input logic XSgnE, - input logic XZeroE, - input logic XDenormE, - input logic XInfE, - input logic XNaNE, - input logic XSNaNE, - input logic [2:0] FrmE, - input logic FmtE, - output logic [63:0] CvtFpResE, - output logic [4:0] CvtFpFlgE); + input logic [10:0] XExpE, // input's exponent + input logic [52:0] XManE, // input's mantissa + input logic XSgnE, // input's sign + input logic XZeroE, // is the input zero + input logic XDenormE, // is the input denormalized + input logic XInfE, // is the input infinity + input logic XNaNE, // is the input a NaN + input logic XSNaNE, // is the input a signaling NaN + input logic [2:0] FrmE, // rounding mode 000 = rount to nearest, ties to even 001 = round twords zero 010 = round down 011 = round up 100 = round to nearest, ties to max magnitude + input logic FmtE, // the input's precision (1 = double 0 = single) + output logic [63:0] CvtFpResE, // the fp to fp conversion's result + output logic [4:0] CvtFpFlgE); // the fp to fp conversion's flags - logic [7:0] DExp; - logic [51:0] Frac; - logic Denorm; + logic [12:0] DSExp; // double to single precision exponent + logic Denorm; // is the double to single precision result denormalized + logic Shift; // do you shift the double precision exponent (if single precision result is denormalized) + logic [51:0] SDFrac; // single to double precision fraction + logic [25:0] DSFrac; // double to single precision fraction + logic [77:0] DSFracShifted; // single precision fraction shifted for double precision + logic Sticky, UfSticky, Guard, Round, LSBFrac, UfGuard, UfRound, UfLSBFrac; // rounding bits + logic CalcPlus1, UfCalcPlus1, Plus1, UfPlus1; // do you add one to the result + logic [12:0] DSExpFull; // full double to single exponent + logic [22:0] DSResFrac; // final double to single fraction + logic [7:0] DSResExp; // final double to single exponent + logic [10:0] SDExp; // final single to double precision exponent + logic Overflow, Underflow, Inexact; // flags + logic [31:0] DSRes; // double to single precision result + + /////////////////////////////////////////////////////////////////////////////// + // LZC + /////////////////////////////////////////////////////////////////////////////// + + + // LZC - find the first 1 in the input's mantissa logic [8:0] i,NormCnt; always_comb begin i = 0; @@ -27,42 +45,62 @@ module cvtfp ( end + /////////////////////////////////////////////////////////////////////////////// + // Expoents + /////////////////////////////////////////////////////////////////////////////// + + // convert the single precion exponent to single precision. + // - subtract the double precision exponent (1023) and add the + // single precsision exponent (127) + // - if the input is zero then kill the exponent + + assign DSExp = ({2'b0,XExpE}-13'd1023+13'd127)&{13{~XZeroE}}; + + // is the converted double to single precision exponent in the denormalized range + assign Denorm = $signed(DSExp) <= 0 & $signed(DSExp) > $signed(-(13'd23)); + + + // caluculate the final single to double precsion exponent + // - subtract the single precision bias (127) and add the double + // precision bias (127) + // - if the result is zero or denormalized, kill the exponent + assign SDExp = XExpE-({2'b0,NormCnt&{9{~XZeroE}}})+({11{XDenormE}}&1024-127); //*** seems ineffecient + /////////////////////////////////////////////////////////////////////////////// + // Fraction + /////////////////////////////////////////////////////////////////////////////// + + + // normalize the single precision fraction for double precsion + // - needed for denormal single precsion values + assign SDFrac = XManE[51:0] << NormCnt; + + // check if the double precision mantissa needs to be shifted + // - the mantissa needs to be shifted if the single precision result is denormal + assign Shift = Denorm | (($signed(DSExp) > $signed(-(13'd25))) & DSExp[12]); + // shift the mantissa + assign DSFracShifted = {XManE, 25'b0} >> ((-DSExp+1)&{13{Shift}}); //***might be some optimization here + assign DSFrac = DSFracShifted[76:51]; - logic [12:0] DExpCalc; - // logic Overflow, Underflow; - assign DExpCalc = ({2'b0,XExpE}-13'd1023+13'd127)&{13{~XZeroE}}; - assign Denorm = $signed(DExpCalc) <= 0 & $signed(DExpCalc) > $signed(-(13'd23)); + /////////////////////////////////////////////////////////////////////////////// + // Rounder + /////////////////////////////////////////////////////////////////////////////// - logic [12:0] ShiftCnt; - logic [51:0] SFrac; - logic [25:0] DFrac; - logic [77:0] DFracTmp; - //assign ShiftCnt = FmtE ? -DExpCalc&{13{Denorm}} : NormCnt; - assign SFrac = XManE[51:0] << NormCnt; -logic Shift; -assign Shift = Denorm | (($signed(DExpCalc) > $signed(-(13'd25))) & DExpCalc[12]); - assign DFracTmp = {XManE, 25'b0} >> ((-DExpCalc+1)&{13{Shift}}); -assign DFrac = DFracTmp[76:51]; - - logic Sticky, UfSticky, Guard, Round, LSBFrac, UfGuard, UfRound, UfLSBFrac; - logic CalcPlus1, UfCalcPlus1; - logic Plus1, UfPlus1; // used to determine underflow flag - assign UfSticky = |DFracTmp[50:0]; - assign UfGuard = DFrac[1]; - assign UfRound = DFrac[0]; - assign UfLSBFrac = DFrac[2]; + assign UfSticky = |DSFracShifted[50:0]; + assign UfGuard = DSFrac[1]; + assign UfRound = DSFrac[0]; + assign UfLSBFrac = DSFrac[2]; assign Sticky = UfSticky | UfRound; - assign Guard = DFrac[2]; - assign Round = DFrac[1]; - assign LSBFrac = DFrac[3]; + assign Guard = DSFrac[2]; + assign Round = DSFrac[1]; + assign LSBFrac = DSFrac[3]; always_comb begin @@ -87,32 +125,48 @@ assign DFrac = DFracTmp[76:51]; end - // If an answer is exact don't round + // if an answer is exact don't round assign Plus1 = CalcPlus1 & (Sticky | UfGuard | Guard | Round); assign UfPlus1 = UfCalcPlus1 & (Sticky | UfGuard); - logic [12:0] DExpFull; -logic [22:0] DResFrac; -logic [7:0] DResExp; - assign {DExpFull, DResFrac} = {DExpCalc&{13{~Denorm}}, DFrac[25:3]} + {35'b0,Plus1}; - assign DResExp = DExpFull[7:0]; - logic [10:0] SExp; - assign SExp = XExpE-({2'b0,NormCnt&{9{~XZeroE}}})+({11{XDenormE}}&1024-127); - logic Overflow, Underflow, Inexact; - assign Overflow = $signed(DExpFull) >= $signed({5'b0, {8{1'b1}}}) & ~(XNaNE|XInfE); - assign Underflow = (($signed(DExpFull) <= 0) & ((Sticky|Guard|Round) | (XManE[52]&~|DFrac) | (|DFrac&~Denorm)) | ((DExpFull == 1) & Denorm & ~(UfPlus1&UfLSBFrac))) & ~(XNaNE|XInfE); + + // round the double to single precision result + assign {DSExpFull, DSResFrac} = {DSExp&{13{~Denorm}}, DSFrac[25:3]} + {35'b0,Plus1}; + assign DSResExp = DSExpFull[7:0]; + + + /////////////////////////////////////////////////////////////////////////////// + // Flags + /////////////////////////////////////////////////////////////////////////////// + + // calculate the flags + // - overflow, underflow and inexact can only be set by the double to single precision opperation + // - don't set underflow or overflow if the input is NaN or Infinity + // - don't set the inexact flag if the input is NaN + assign Overflow = $signed(DSExpFull) >= $signed({5'b0, {8{1'b1}}}) & ~(XNaNE|XInfE); + assign Underflow = (($signed(DSExpFull) <= 0) & ((Sticky|Guard|Round) | (XManE[52]&~|DSFrac) | (|DSFrac&~Denorm)) | ((DSExpFull == 1) & Denorm & ~(UfPlus1&UfLSBFrac))) & ~(XNaNE|XInfE); assign Inexact = (Sticky|Guard|Round|Underflow|Overflow) &~(XNaNE); - -logic [31:0] DRes; - assign DRes = XNaNE ? {XSgnE, {8{1'b1}}, 1'b1, XManE[50:29]} : - Underflow & ~Denorm ? {XSgnE, 30'b0, CalcPlus1&(|FrmE[1:0]|Shift)} : - Overflow | XInfE ? ((FrmE[1:0]==2'b01) | (FrmE[1:0]==2'b10&~XSgnE) | (FrmE[1:0]==2'b11&XSgnE)) & ~XInfE ? {XSgnE, 8'hfe, {23{1'b1}}} : - {XSgnE, 8'hff, 23'b0} : - {XSgnE, DResExp, DResFrac}; - assign CvtFpResE = FmtE ? {{32{1'b1}},DRes} : {XSgnE, SExp, SFrac[51]|XNaNE, SFrac[50:0]}; + + // pack the flags together and choose the result based on the opperation assign CvtFpFlgE = FmtE ? {XSNaNE, 1'b0, Overflow, Underflow, Inexact} : {XSNaNE, 4'b0}; + + + /////////////////////////////////////////////////////////////////////////////// + // Result Selection + /////////////////////////////////////////////////////////////////////////////// + + // select the double to single precision result + assign DSRes = XNaNE ? {XSgnE, {8{1'b1}}, 1'b1, XManE[50:29]} : + Underflow & ~Denorm ? {XSgnE, 30'b0, CalcPlus1&(|FrmE[1:0]|Shift)} : + Overflow | XInfE ? ((FrmE[1:0]==2'b01) | (FrmE[1:0]==2'b10&~XSgnE) | (FrmE[1:0]==2'b11&XSgnE)) & ~XInfE ? {XSgnE, 8'hfe, {23{1'b1}}} : + {XSgnE, 8'hff, 23'b0} : + {XSgnE, DSResExp, DSResFrac}; + + // select the final result based on the opperation + assign CvtFpResE = FmtE ? {{32{1'b1}},DSRes} : {XSgnE, SDExp, SDFrac[51]|XNaNE, SDFrac[50:0]}; + endmodule // fpadd