2021-07-02 16:53:05 +00:00
2022-07-07 23:01:33 +00:00
///////////////////////////////////////////
//
// Written: me@KatherineParry.com
// Modified: 7/5/2022
//
// Purpose: Comparison unit
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// MIT LICENSE
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////
2021-07-02 16:53:05 +00:00
`include " wally-config.vh "
2022-01-01 23:50:23 +00:00
// FOpCtrlE values
2022-06-13 22:47:51 +00:00
// 110 min
2022-01-01 23:50:23 +00:00
// 101 max
// 010 equal
// 001 less than
// 011 less than or equal
2021-07-02 16:53:05 +00:00
2022-01-01 23:50:23 +00:00
module fcmp (
2022-06-02 19:50:28 +00:00
input logic [ `FMTBITS - 1 : 0 ] FmtE , // precision 1 = double 0 = single
2022-05-20 17:19:50 +00:00
input logic [ 2 : 0 ] FOpCtrlE , // see above table
input logic XSgnE , YSgnE , // input signs
input logic [ `NE - 1 : 0 ] XExpE , YExpE , // input exponents
input logic [ `NF : 0 ] XManE , YManE , // input mantissa
input logic XZeroE , YZeroE , // is zero
input logic XNaNE , YNaNE , // is NaN
input logic XSNaNE , YSNaNE , // is signaling NaN
input logic [ `FLEN - 1 : 0 ] FSrcXE , FSrcYE , // original, non-converted to double, inputs
output logic CmpNVE , // invalid flag
2022-06-13 22:47:51 +00:00
output logic [ `FLEN - 1 : 0 ] CmpFpResE , // compare resilt
output logic [ `XLEN - 1 : 0 ] CmpIntResE // compare resilt
2022-01-01 23:50:23 +00:00
) ;
2022-03-29 17:11:28 +00:00
logic LTabs , LT , EQ ; // is X < or > or = Y
2022-05-20 17:19:50 +00:00
logic [ `FLEN - 1 : 0 ] NaNRes ;
2022-06-13 22:47:51 +00:00
logic BothZero , EitherNaN , EitherSNaN ;
2022-03-29 17:11:28 +00:00
assign LTabs = { 1 'b0 , XExpE , XManE } < { 1 'b0 , YExpE , YManE } ; // unsigned comparison, treating FP as integers
assign LT = ( XSgnE & ~ YSgnE ) | ( XSgnE & YSgnE & ~ LTabs & ~ EQ ) | ( ~ XSgnE & ~ YSgnE & LTabs ) ;
2022-05-03 18:32:01 +00:00
// assign LT = {~XSgnE, XExpE, XManE[`NF-1:0]} < {~YSgnE, YExpE, YManE[`NF-1:0]}; // *** James look at whether we can simplify to this, but it fails regression
2022-03-29 17:11:28 +00:00
//assign LT = $signed({XSgnE, XExpE, XManE[`NF-1:0]}) < $signed({YSgnE, YExpE, YManE[`NF-1:0]});
//assign LT = XInt < YInt;
// assign LT = XSgnE^YSgnE ? XSgnE : XExpE==YExpE ? ((XManE<YManE)^XSgnE)&~EQ : (XExpE<YExpE)^XSgnE;
2022-01-01 23:50:23 +00:00
assign EQ = ( FSrcXE = = FSrcYE ) ;
2022-06-13 22:47:51 +00:00
assign BothZero = XZeroE & YZeroE ;
assign EitherNaN = XNaNE | YNaNE ;
assign EitherSNaN = XSNaNE | YSNaNE ;
2022-03-29 17:11:28 +00:00
2022-01-01 23:50:23 +00:00
// flags
// Min/Max - if an input is a signaling NaN set invalid flag
// LT/LE - signaling - sets invalid if NaN input
// EQ - quiet - sets invalid if signaling NaN input
always_comb begin
case ( FOpCtrlE [ 2 : 0 ] )
2022-06-13 22:47:51 +00:00
3 'b110 : CmpNVE = EitherSNaN ; //min
3 'b101 : CmpNVE = EitherSNaN ; //max
3 'b010 : CmpNVE = EitherSNaN ; //equal
3 'b001 : CmpNVE = EitherNaN ; //less than
3 'b011 : CmpNVE = EitherNaN ; //less than or equal
2022-06-14 23:58:39 +00:00
default : CmpNVE = 1 ' bx ;
2022-01-01 23:50:23 +00:00
endcase
end
2021-07-02 16:53:05 +00:00
2022-01-01 23:50:23 +00:00
// Min/Max
// - outputs the min/max of X and Y
// - -0 < 0
// - if both are NaN return quiet X
// - if one is a NaN output the non-NaN
// LT/LE/EQ
// - -0 = 0
// - inf = inf and -inf = -inf
// - return 0 if comparison with NaN (unordered)
2022-03-29 17:11:28 +00:00
// fmin/fmax of two NaNs returns a quiet NaN of the appropriate size
// for IEEE, return the payload of X
// for RISC-V, return the canonical NaN
2022-05-20 17:19:50 +00:00
if ( `FPSIZES = = 1 )
if ( `IEEE754 ) assign NaNRes = { XSgnE , { `NE { 1 'b1 } } , 1 'b1 , XManE [ `NF - 2 : 0 ] } ;
else assign NaNRes = { 1 'b0 , { `NE { 1 'b1 } } , 1 'b1 , { `NF - 1 { 1 'b0 } } } ;
else if ( `FPSIZES = = 2 )
if ( `IEEE754 ) assign NaNRes = FmtE ? { XSgnE , { `NE { 1 'b1 } } , 1 'b1 , XManE [ `NF - 2 : 0 ] } : { { `FLEN - `LEN1 { 1 'b1 } } , XSgnE , { `NE1 { 1 'b1 } } , 1 'b1 , XManE [ `NF - 2 : `NF - `NF1 ] } ;
else assign NaNRes = FmtE ? { 1 'b0 , { `NE { 1 'b1 } } , 1 'b1 , { `NF - 1 { 1 'b0 } } } : { { `FLEN - `LEN1 { 1 'b1 } } , 1 'b0 , { `NE1 { 1 'b1 } } , 1 'b1 , ( `NF1 - 1 ) ' ( 0 ) } ;
else if ( `FPSIZES = = 3 )
always_comb
case ( FmtE )
`FMT :
if ( `IEEE754 ) NaNRes = { XSgnE , { `NE { 1 'b1 } } , 1 'b1 , XManE [ `NF - 2 : 0 ] } ;
else NaNRes = { 1 'b0 , { `NE { 1 'b1 } } , 1 'b1 , { `NF - 1 { 1 'b0 } } } ;
`FMT1 :
if ( `IEEE754 ) NaNRes = { { `FLEN - `LEN1 { 1 'b1 } } , XSgnE , { `NE1 { 1 'b1 } } , 1 'b1 , XManE [ `NF - 2 : `NF - `NF1 ] } ;
else NaNRes = { { `FLEN - `LEN1 { 1 'b1 } } , 1 'b0 , { `NE1 { 1 'b1 } } , 1 'b1 , ( `NF1 - 1 ) ' ( 0 ) } ;
`FMT2 :
if ( `IEEE754 ) NaNRes = { { `FLEN - `LEN2 { 1 'b1 } } , XSgnE , { `NE2 { 1 'b1 } } , 1 'b1 , XManE [ `NF - 2 : `NF - `NF2 ] } ;
else NaNRes = { { `FLEN - `LEN2 { 1 'b1 } } , 1 'b0 , { `NE2 { 1 'b1 } } , 1 'b1 , ( `NF2 - 1 ) ' ( 0 ) } ;
2022-06-14 23:58:39 +00:00
default : NaNRes = { `FLEN { 1 ' bx } } ;
2022-05-20 17:19:50 +00:00
endcase
else if ( `FPSIZES = = 4 )
always_comb
case ( FmtE )
2 'h3 :
if ( `IEEE754 ) NaNRes = { XSgnE , { `NE { 1 'b1 } } , 1 'b1 , XManE [ `NF - 2 : 0 ] } ;
else NaNRes = { 1 'b0 , { `NE { 1 'b1 } } , 1 'b1 , { `NF - 1 { 1 'b0 } } } ;
2 'h1 :
if ( `IEEE754 ) NaNRes = { { `FLEN - `D_LEN { 1 'b1 } } , XSgnE , { `D_NE { 1 'b1 } } , 1 'b1 , XManE [ `NF - 2 : `NF - `D_NF ] } ;
else NaNRes = { { `FLEN - `D_LEN { 1 'b1 } } , 1 'b0 , { `D_NE { 1 'b1 } } , 1 'b1 , ( `D_NF - 1 ) ' ( 0 ) } ;
2 'h0 :
if ( `IEEE754 ) NaNRes = { { `FLEN - `S_LEN { 1 'b1 } } , XSgnE , { `S_NE { 1 'b1 } } , 1 'b1 , XManE [ `NF - 2 : `NF - `S_NF ] } ;
else NaNRes = { { `FLEN - `S_LEN { 1 'b1 } } , 1 'b0 , { `S_NE { 1 'b1 } } , 1 'b1 , ( `S_NF - 1 ) ' ( 0 ) } ;
2 'h2 :
if ( `IEEE754 ) NaNRes = { { `FLEN - `H_LEN { 1 'b1 } } , XSgnE , { `H_NE { 1 'b1 } } , 1 'b1 , XManE [ `NF - 2 : `NF - `H_NF ] } ;
else NaNRes = { { `FLEN - `H_LEN { 1 'b1 } } , 1 'b0 , { `H_NE { 1 'b1 } } , 1 'b1 , ( `H_NF - 1 ) ' ( 0 ) } ;
endcase
2022-04-04 17:17:12 +00:00
// when one input is a NaN -output the non-NaN
2022-06-13 22:47:51 +00:00
assign CmpFpResE = FOpCtrlE [ 0 ] ? XNaNE ? YNaNE ? NaNRes : FSrcYE // Max
: YNaNE ? FSrcXE : LT ? FSrcYE : FSrcXE :
XNaNE ? YNaNE ? NaNRes : FSrcYE // Min
: YNaNE ? FSrcXE : LT ? FSrcXE : FSrcYE ;
assign CmpIntResE = { ( `XLEN - 1 ) ' ( 0 ) , ( ( ( EQ | BothZero ) & FOpCtrlE [ 1 ] ) | ( LT & FOpCtrlE [ 0 ] & ~ BothZero ) ) & ~ EitherNaN } ;
2022-01-01 23:50:23 +00:00
endmodule