mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
370 lines
20 KiB
Systemverilog
370 lines
20 KiB
Systemverilog
///////////////////////////////////////////
|
|
// specialcase.sv
|
|
//
|
|
// Written: me@KatherineParry.com
|
|
// Modified: 7/5/2022
|
|
//
|
|
// Purpose: special case selection
|
|
//
|
|
// Documentation: RISC-V System on Chip Design
|
|
//
|
|
// A component of the CORE-V-WALLY configurable RISC-V project.
|
|
// https://github.com/openhwgroup/cvw
|
|
//
|
|
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
|
//
|
|
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
|
|
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
|
|
// may obtain a copy of the License at
|
|
//
|
|
// https://solderpad.org/licenses/SHL-2.1/
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, any work distributed under the
|
|
// 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.
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
module specialcase import cvw::*; #(parameter cvw_t P) (
|
|
input logic Xs, // X sign
|
|
input logic [P.NF:0] Xm, Ym, Zm, // input significand's
|
|
input logic XNaN, YNaN, ZNaN, // are the inputs NaN
|
|
input logic [2:0] Frm, // rounding mode
|
|
input logic [P.FMTBITS-1:0] OutFmt, // output format
|
|
input logic InfIn, // are any inputs infinity
|
|
input logic NaNIn, // are any input NaNs
|
|
input logic XInf, YInf, // are X or Y inifnity
|
|
input logic XZero, // is X zero
|
|
input logic Plus1, // do you add one for rounding
|
|
input logic Rs, // the result's sign
|
|
input logic Invalid, Overflow, // flags to choose the result
|
|
input logic [P.NE-1:0] Re, // Result exponent
|
|
input logic [P.NE+1:0] FullRe, // Result full exponent
|
|
input logic [P.NF-1:0] Rf, // Result fraction
|
|
// fma
|
|
input logic FmaOp, // is it a fma operation
|
|
// divsqrt
|
|
input logic DivOp, // is it a divsqrt operation
|
|
input logic DivByZero, // divide by zero flag
|
|
// cvt
|
|
input logic CvtOp, // is it a conversion operation
|
|
input logic IntZero, // is the integer input zero
|
|
input logic IntToFp, // is cvt int -> fp operation
|
|
input logic Int64, // is the integer 64 bits
|
|
input logic Signed, // is the integer signed
|
|
input logic Zfa, // Zfa conversion operation: fcvtmod.w.d
|
|
input logic [P.NE:0] CvtCe, // the calculated expoent for cvt
|
|
input logic IntInvalid, // integer invalid flag to choose the result
|
|
input logic CvtResUf, // does the convert result underflow
|
|
input logic [P.XLEN+1:0] CvtNegRes, // the possibly negated of the integer result
|
|
// outputs
|
|
output logic [P.FLEN-1:0] PostProcRes, // final result
|
|
output logic [P.XLEN-1:0] FCvtIntRes // final integer result
|
|
);
|
|
|
|
logic [P.FLEN-1:0] XNaNRes; // X is NaN result
|
|
logic [P.FLEN-1:0] YNaNRes; // Y is NaN result
|
|
logic [P.FLEN-1:0] ZNaNRes; // Z is NaN result
|
|
logic [P.FLEN-1:0] InvalidRes; // Invalid result result
|
|
logic [P.FLEN-1:0] UfRes; // underflowed result result
|
|
logic [P.FLEN-1:0] OfRes; // overflowed result result
|
|
logic [P.FLEN-1:0] NormRes; // normal result
|
|
logic [P.XLEN-1:0] OfIntRes; // the overflow result for integer output
|
|
logic [P.XLEN-1:0] OfIntRes2; // the overflow result for integer output after accounting for fcvtmod.w.d
|
|
logic [P.XLEN-1:0] Int64Res; // Result for conversion to 64-bit int after accounting for fcvtmod.w.d
|
|
logic OfResMax; // does the of result output maximum norm fp number
|
|
logic KillRes; // kill the result for underflow
|
|
logic SelOfRes; // should the overflow result be selected (excluding convert)
|
|
logic SelCvtOfRes; // select overflow result for convert instruction
|
|
|
|
// does the overflow result output the maximum normalized floating point number
|
|
// output infinity if the input is infinity
|
|
assign OfResMax = (~InfIn|(IntToFp&CvtOp))&~DivByZero&((Frm[1:0]==2'b01) | (Frm[1:0]==2'b10&~Rs) | (Frm[1:0]==2'b11&Rs));
|
|
|
|
// select correct outputs for special cases
|
|
if (P.FPSIZES == 1) begin
|
|
//NaN res selection depending on standard
|
|
if(P.IEEE754) begin
|
|
assign XNaNRes = {1'b0, {P.NE{1'b1}}, 1'b1, Xm[P.NF-2:0]};
|
|
assign YNaNRes = {1'b0, {P.NE{1'b1}}, 1'b1, Ym[P.NF-2:0]};
|
|
assign ZNaNRes = {1'b0, {P.NE{1'b1}}, 1'b1, Zm[P.NF-2:0]};
|
|
assign InvalidRes = {1'b0, {P.NE{1'b1}}, 1'b1, {P.NF-1{1'b0}}};
|
|
end else begin
|
|
assign InvalidRes = {1'b0, {P.NE{1'b1}}, 1'b1, {P.NF-1{1'b0}}};
|
|
end
|
|
|
|
assign OfRes = OfResMax ? {Rs, {P.NE-1{1'b1}}, 1'b0, {P.NF{1'b1}}} : {Rs, {P.NE{1'b1}}, {P.NF{1'b0}}};
|
|
assign UfRes = {Rs, {P.FLEN-2{1'b0}}, Plus1&Frm[1]&~(DivOp&YInf)};
|
|
assign NormRes = {Rs, Re, Rf};
|
|
|
|
end else if (P.FPSIZES == 2) begin
|
|
if(P.IEEE754) begin
|
|
assign XNaNRes = OutFmt ? {1'b0, {P.NE{1'b1}}, 1'b1, Xm[P.NF-2:0]} : {{P.FLEN-P.LEN1{1'b1}}, 1'b0, {P.NE1{1'b1}}, 1'b1, Xm[P.NF-2:P.NF-P.NF1]};
|
|
assign YNaNRes = OutFmt ? {1'b0, {P.NE{1'b1}}, 1'b1, Ym[P.NF-2:0]} : {{P.FLEN-P.LEN1{1'b1}}, 1'b0, {P.NE1{1'b1}}, 1'b1, Ym[P.NF-2:P.NF-P.NF1]};
|
|
assign ZNaNRes = OutFmt ? {1'b0, {P.NE{1'b1}}, 1'b1, Zm[P.NF-2:0]} : {{P.FLEN-P.LEN1{1'b1}}, 1'b0, {P.NE1{1'b1}}, 1'b1, Zm[P.NF-2:P.NF-P.NF1]};
|
|
assign InvalidRes = OutFmt ? {1'b0, {P.NE{1'b1}}, 1'b1, {P.NF-1{1'b0}}} : {{P.FLEN-P.LEN1{1'b1}}, 1'b0, {P.NE1{1'b1}}, 1'b1, (P.NF1-1)'(0)};
|
|
end else begin
|
|
assign InvalidRes = OutFmt ? {1'b0, {P.NE{1'b1}}, 1'b1, {P.NF-1{1'b0}}} : {{P.FLEN-P.LEN1{1'b1}}, 1'b0, {P.NE1{1'b1}}, 1'b1, (P.NF1-1)'(0)};
|
|
end
|
|
|
|
always_comb
|
|
if(OutFmt)
|
|
if(OfResMax) OfRes = {Rs, {P.NE-1{1'b1}}, 1'b0, {P.NF{1'b1}}};
|
|
else OfRes = {Rs, {P.NE{1'b1}}, {P.NF{1'b0}}};
|
|
else
|
|
if(OfResMax) OfRes = {{P.FLEN-P.LEN1{1'b1}}, Rs, {P.NE1-1{1'b1}}, 1'b0, {P.NF1{1'b1}}};
|
|
else OfRes = {{P.FLEN-P.LEN1{1'b1}}, Rs, {P.NE1{1'b1}}, (P.NF1)'(0)};
|
|
assign UfRes = OutFmt ? {Rs, (P.FLEN-2)'(0), Plus1&Frm[1]&~(DivOp&YInf)} : {{P.FLEN-P.LEN1{1'b1}}, Rs, (P.LEN1-2)'(0), Plus1&Frm[1]&~(DivOp&YInf)};
|
|
assign NormRes = OutFmt ? {Rs, Re, Rf} : {{P.FLEN-P.LEN1{1'b1}}, Rs, Re[P.NE1-1:0], Rf[P.NF-1:P.NF-P.NF1]};
|
|
|
|
end else if (P.FPSIZES == 3) begin
|
|
always_comb
|
|
case (OutFmt)
|
|
P.FMT: begin
|
|
if(P.IEEE754) begin
|
|
XNaNRes = {1'b0, {P.NE{1'b1}}, 1'b1, Xm[P.NF-2:0]};
|
|
YNaNRes = {1'b0, {P.NE{1'b1}}, 1'b1, Ym[P.NF-2:0]};
|
|
ZNaNRes = {1'b0, {P.NE{1'b1}}, 1'b1, Zm[P.NF-2:0]};
|
|
InvalidRes = {1'b0, {P.NE{1'b1}}, 1'b1, {P.NF-1{1'b0}}};
|
|
end else begin
|
|
InvalidRes = {1'b0, {P.NE{1'b1}}, 1'b1, {P.NF-1{1'b0}}};
|
|
end
|
|
|
|
OfRes = OfResMax ? {Rs, {P.NE-1{1'b1}}, 1'b0, {P.NF{1'b1}}} : {Rs, {P.NE{1'b1}}, {P.NF{1'b0}}};
|
|
UfRes = {Rs, (P.FLEN-2)'(0), Plus1&Frm[1]&~(DivOp&YInf)};
|
|
NormRes = {Rs, Re, Rf};
|
|
end
|
|
P.FMT1: begin
|
|
if(P.IEEE754) begin
|
|
XNaNRes = {{P.FLEN-P.LEN1{1'b1}}, 1'b0, {P.NE1{1'b1}}, 1'b1, Xm[P.NF-2:P.NF-P.NF1]};
|
|
YNaNRes = {{P.FLEN-P.LEN1{1'b1}}, 1'b0, {P.NE1{1'b1}}, 1'b1, Ym[P.NF-2:P.NF-P.NF1]};
|
|
ZNaNRes = {{P.FLEN-P.LEN1{1'b1}}, 1'b0, {P.NE1{1'b1}}, 1'b1, Zm[P.NF-2:P.NF-P.NF1]};
|
|
InvalidRes = {{P.FLEN-P.LEN1{1'b1}}, 1'b0, {P.NE1{1'b1}}, 1'b1, (P.NF1-1)'(0)};
|
|
end else begin
|
|
InvalidRes = {{P.FLEN-P.LEN1{1'b1}}, 1'b0, {P.NE1{1'b1}}, 1'b1, (P.NF1-1)'(0)};
|
|
end
|
|
OfRes = OfResMax ? {{P.FLEN-P.LEN1{1'b1}}, Rs, {P.NE1-1{1'b1}}, 1'b0, {P.NF1{1'b1}}} : {{P.FLEN-P.LEN1{1'b1}}, Rs, {P.NE1{1'b1}}, (P.NF1)'(0)};
|
|
UfRes = {{P.FLEN-P.LEN1{1'b1}}, Rs, (P.LEN1-2)'(0), Plus1&Frm[1]&~(DivOp&YInf)};
|
|
NormRes = {{P.FLEN-P.LEN1{1'b1}}, Rs, Re[P.NE1-1:0], Rf[P.NF-1:P.NF-P.NF1]};
|
|
end
|
|
P.FMT2: begin
|
|
if(P.IEEE754) begin
|
|
XNaNRes = {{P.FLEN-P.LEN2{1'b1}}, 1'b0, {P.NE2{1'b1}}, 1'b1, Xm[P.NF-2:P.NF-P.NF2]};
|
|
YNaNRes = {{P.FLEN-P.LEN2{1'b1}}, 1'b0, {P.NE2{1'b1}}, 1'b1, Ym[P.NF-2:P.NF-P.NF2]};
|
|
ZNaNRes = {{P.FLEN-P.LEN2{1'b1}}, 1'b0, {P.NE2{1'b1}}, 1'b1, Zm[P.NF-2:P.NF-P.NF2]};
|
|
InvalidRes = {{P.FLEN-P.LEN2{1'b1}}, 1'b0, {P.NE2{1'b1}}, 1'b1, (P.NF2-1)'(0)};
|
|
end else begin
|
|
InvalidRes = {{P.FLEN-P.LEN2{1'b1}}, 1'b0, {P.NE2{1'b1}}, 1'b1, (P.NF2-1)'(0)};
|
|
end
|
|
|
|
OfRes = OfResMax ? {{P.FLEN-P.LEN2{1'b1}}, Rs, {P.NE2-1{1'b1}}, 1'b0, {P.NF2{1'b1}}} : {{P.FLEN-P.LEN2{1'b1}}, Rs, {P.NE2{1'b1}}, (P.NF2)'(0)};
|
|
UfRes = {{P.FLEN-P.LEN2{1'b1}}, Rs, (P.LEN2-2)'(0), Plus1&Frm[1]&~(DivOp&YInf)};
|
|
NormRes = {{P.FLEN-P.LEN2{1'b1}}, Rs, Re[P.NE2-1:0], Rf[P.NF-1:P.NF-P.NF2]};
|
|
end
|
|
default: begin
|
|
if(P.IEEE754) begin
|
|
XNaNRes = (P.FLEN)'(0);
|
|
YNaNRes = (P.FLEN)'(0);
|
|
ZNaNRes = (P.FLEN)'(0);
|
|
InvalidRes = (P.FLEN)'(0);
|
|
end else begin
|
|
InvalidRes = (P.FLEN)'(0);
|
|
end
|
|
OfRes = (P.FLEN)'(0);
|
|
UfRes = (P.FLEN)'(0);
|
|
NormRes = (P.FLEN)'(0);
|
|
end
|
|
endcase
|
|
|
|
end else if (P.FPSIZES == 4) begin
|
|
always_comb
|
|
case (OutFmt)
|
|
2'h3: begin
|
|
if(P.IEEE754) begin
|
|
XNaNRes = {1'b0, {P.NE{1'b1}}, 1'b1, Xm[P.NF-2:0]};
|
|
YNaNRes = {1'b0, {P.NE{1'b1}}, 1'b1, Ym[P.NF-2:0]};
|
|
ZNaNRes = {1'b0, {P.NE{1'b1}}, 1'b1, Zm[P.NF-2:0]};
|
|
InvalidRes = {1'b0, {P.NE{1'b1}}, 1'b1, {P.NF-1{1'b0}}};
|
|
end else begin
|
|
InvalidRes = {1'b0, {P.NE{1'b1}}, 1'b1, {P.NF-1{1'b0}}};
|
|
end
|
|
|
|
OfRes = OfResMax ? {Rs, {P.NE-1{1'b1}}, 1'b0, {P.NF{1'b1}}} : {Rs, {P.NE{1'b1}}, {P.NF{1'b0}}};
|
|
UfRes = {Rs, (P.FLEN-2)'(0), Plus1&Frm[1]&~(DivOp&YInf)};
|
|
NormRes = {Rs, Re, Rf};
|
|
end
|
|
2'h1: begin
|
|
if(P.IEEE754) begin
|
|
XNaNRes = {{P.FLEN-P.D_LEN{1'b1}}, 1'b0, {P.D_NE{1'b1}}, 1'b1, Xm[P.NF-2:P.NF-P.D_NF]};
|
|
YNaNRes = {{P.FLEN-P.D_LEN{1'b1}}, 1'b0, {P.D_NE{1'b1}}, 1'b1, Ym[P.NF-2:P.NF-P.D_NF]};
|
|
ZNaNRes = {{P.FLEN-P.D_LEN{1'b1}}, 1'b0, {P.D_NE{1'b1}}, 1'b1, Zm[P.NF-2:P.NF-P.D_NF]};
|
|
InvalidRes = {{P.FLEN-P.D_LEN{1'b1}}, 1'b0, {P.D_NE{1'b1}}, 1'b1, (P.D_NF-1)'(0)};
|
|
end else begin
|
|
InvalidRes = {{P.FLEN-P.D_LEN{1'b1}}, 1'b0, {P.D_NE{1'b1}}, 1'b1, (P.D_NF-1)'(0)};
|
|
end
|
|
OfRes = OfResMax ? {{P.FLEN-P.D_LEN{1'b1}}, Rs, {P.D_NE-1{1'b1}}, 1'b0, {P.D_NF{1'b1}}} : {{P.FLEN-P.D_LEN{1'b1}}, Rs, {P.D_NE{1'b1}}, (P.D_NF)'(0)};
|
|
UfRes = {{P.FLEN-P.D_LEN{1'b1}}, Rs, (P.D_LEN-2)'(0), Plus1&Frm[1]&~(DivOp&YInf)};
|
|
NormRes = {{P.FLEN-P.D_LEN{1'b1}}, Rs, Re[P.D_NE-1:0], Rf[P.NF-1:P.NF-P.D_NF]};
|
|
end
|
|
2'h0: begin
|
|
if(P.IEEE754) begin
|
|
XNaNRes = {{P.FLEN-P.S_LEN{1'b1}}, 1'b0, {P.S_NE{1'b1}}, 1'b1, Xm[P.NF-2:P.NF-P.S_NF]};
|
|
YNaNRes = {{P.FLEN-P.S_LEN{1'b1}}, 1'b0, {P.S_NE{1'b1}}, 1'b1, Ym[P.NF-2:P.NF-P.S_NF]};
|
|
ZNaNRes = {{P.FLEN-P.S_LEN{1'b1}}, 1'b0, {P.S_NE{1'b1}}, 1'b1, Zm[P.NF-2:P.NF-P.S_NF]};
|
|
InvalidRes = {{P.FLEN-P.S_LEN{1'b1}}, 1'b0, {P.S_NE{1'b1}}, 1'b1, (P.S_NF-1)'(0)};
|
|
end else begin
|
|
InvalidRes = {{P.FLEN-P.S_LEN{1'b1}}, 1'b0, {P.S_NE{1'b1}}, 1'b1, (P.S_NF-1)'(0)};
|
|
end
|
|
|
|
OfRes = OfResMax ? {{P.FLEN-P.S_LEN{1'b1}}, Rs, {P.S_NE-1{1'b1}}, 1'b0, {P.S_NF{1'b1}}} : {{P.FLEN-P.S_LEN{1'b1}}, Rs, {P.S_NE{1'b1}}, (P.S_NF)'(0)};
|
|
UfRes = {{P.FLEN-P.S_LEN{1'b1}}, Rs, (P.S_LEN-2)'(0), Plus1&Frm[1]&~(DivOp&YInf)};
|
|
NormRes = {{P.FLEN-P.S_LEN{1'b1}}, Rs, Re[P.S_NE-1:0], Rf[P.NF-1:P.NF-P.S_NF]};
|
|
end
|
|
2'h2: begin
|
|
if(P.IEEE754) begin
|
|
XNaNRes = {{P.FLEN-P.H_LEN{1'b1}}, 1'b0, {P.H_NE{1'b1}}, 1'b1, Xm[P.NF-2:P.NF-P.H_NF]};
|
|
YNaNRes = {{P.FLEN-P.H_LEN{1'b1}}, 1'b0, {P.H_NE{1'b1}}, 1'b1, Ym[P.NF-2:P.NF-P.H_NF]};
|
|
ZNaNRes = {{P.FLEN-P.H_LEN{1'b1}}, 1'b0, {P.H_NE{1'b1}}, 1'b1, Zm[P.NF-2:P.NF-P.H_NF]};
|
|
InvalidRes = {{P.FLEN-P.H_LEN{1'b1}}, 1'b0, {P.H_NE{1'b1}}, 1'b1, (P.H_NF-1)'(0)};
|
|
end else begin
|
|
InvalidRes = {{P.FLEN-P.H_LEN{1'b1}}, 1'b0, {P.H_NE{1'b1}}, 1'b1, (P.H_NF-1)'(0)};
|
|
end
|
|
|
|
OfRes = OfResMax ? {{P.FLEN-P.H_LEN{1'b1}}, Rs, {P.H_NE-1{1'b1}}, 1'b0, {P.H_NF{1'b1}}} : {{P.FLEN-P.H_LEN{1'b1}}, Rs, {P.H_NE{1'b1}}, (P.H_NF)'(0)};
|
|
// zero is exact if dividing by infinity so don't add 1
|
|
UfRes = {{P.FLEN-P.H_LEN{1'b1}}, Rs, (P.H_LEN-2)'(0), Plus1&Frm[1]&~(DivOp&YInf)};
|
|
NormRes = {{P.FLEN-P.H_LEN{1'b1}}, Rs, Re[P.H_NE-1:0], Rf[P.NF-1:P.NF-P.H_NF]};
|
|
end
|
|
endcase
|
|
end
|
|
|
|
// determine if you shoould kill the res - Cvt
|
|
// - do so if the res underflows, is zero (the exp doesnt calculate correctly). or the integer input is 0
|
|
// - dont set to zero if fp input is zero but not using the fp input
|
|
// - dont set to zero if int input is zero but not using the int input
|
|
assign KillRes = CvtOp ? (CvtResUf|(XZero&~IntToFp)|(IntZero&IntToFp)) : FullRe[P.NE+1] | (((YInf&~XInf)|XZero)&DivOp);//Underflow & ~ResSubnorm & (Re!=1);
|
|
|
|
// calculate if the overflow result should be selected
|
|
assign SelOfRes = Overflow|DivByZero|(InfIn&~(YInf&DivOp));
|
|
|
|
// output infinity with result sign if divide by zero
|
|
if(P.IEEE754)
|
|
always_comb
|
|
if(XNaN&~(IntToFp&CvtOp)) PostProcRes = XNaNRes;
|
|
else if(YNaN&~CvtOp) PostProcRes = YNaNRes;
|
|
else if(ZNaN&FmaOp) PostProcRes = ZNaNRes;
|
|
else if(Invalid) PostProcRes = InvalidRes;
|
|
else if(SelOfRes) PostProcRes = OfRes;
|
|
else if(KillRes) PostProcRes = UfRes;
|
|
else PostProcRes = NormRes;
|
|
else
|
|
always_comb
|
|
if(NaNIn|Invalid) PostProcRes = InvalidRes;
|
|
else if(SelOfRes) PostProcRes = OfRes;
|
|
else if(KillRes) PostProcRes = UfRes;
|
|
else PostProcRes = NormRes;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// integer result selection
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Causes undefined behavior for invalid:
|
|
|
|
// Invalid cases are different for IEEE 754 vs. RISC-V. For RISC-V, typical results are used
|
|
// unsigned: if invalid (e.g., negative fp to unsigned int, result should overflow and
|
|
// overflows to the maximum value
|
|
// signed: if invalid, result should overflow to maximum negative value
|
|
// but is undefined and used for information only
|
|
// Note: The IEEE 754 result comes from values in TestFloat for x86_64
|
|
|
|
// IEEE 754
|
|
// select the overflow integer res
|
|
// - negative infinity and out of range negative input
|
|
// | int | long |
|
|
// signed | -2^31 | -2^63 |
|
|
// unsigned | 2^32-1 | 2^64-1 |
|
|
//
|
|
// - positive infinity and out of range positive input and NaNs
|
|
// | int | long |
|
|
// signed | -2^31 |-2^63 |
|
|
// unsigned | 2^32-1 | 2^64-1 |
|
|
//
|
|
// other: 32 bit unsigned res should be sign extended as if it were a signed number
|
|
|
|
// RISC-V
|
|
// select the overflow integer res
|
|
// - negative infinity and out of range negative input
|
|
// | int | long |
|
|
// signed | -2^31 | -2^63 |
|
|
// unsigned | 0 | 0 |
|
|
//
|
|
// - positive infinity and out of range positive input and NaNs
|
|
// | int | long |
|
|
// signed | 2^31-1 | 2^63-1 |
|
|
// unsigned | 2^32-1 | 2^64-1 |
|
|
//
|
|
// other: 32 bit unsigned res should be sign extended as if it were a signed number
|
|
|
|
if(P.IEEE754) begin
|
|
always_comb
|
|
if(Signed)
|
|
if(Xs&~NaNIn) // signed negative
|
|
if(Int64) OfIntRes = {1'b1, {P.XLEN-1{1'b0}}};
|
|
else OfIntRes = {{P.XLEN-32{1'b1}}, 1'b1, {31{1'b0}}};
|
|
else // signed positive
|
|
if(Int64) OfIntRes = {1'b1, {P.XLEN-1{1'b0}}};
|
|
else OfIntRes = {{P.XLEN-32{1'b1}}, 1'b1, {31{1'b0}}};
|
|
else
|
|
if(Xs&~NaNIn) OfIntRes = {P.XLEN{1'b1}}; // unsigned negative
|
|
else OfIntRes = {P.XLEN{1'b1}}; // unsigned positive
|
|
end else begin
|
|
always_comb
|
|
if(Signed)
|
|
if(Xs&~NaNIn) // signed negative
|
|
if(Int64) OfIntRes = {1'b1, {P.XLEN-1{1'b0}}};
|
|
else OfIntRes = {{P.XLEN-32{1'b1}}, 1'b1, {31{1'b0}}};
|
|
else // signed positive
|
|
if(Int64) OfIntRes = {1'b0, {P.XLEN-1{1'b1}}};
|
|
else OfIntRes = {{P.XLEN-32{1'b0}}, 1'b0, {31{1'b1}}};
|
|
else
|
|
if(Xs&~NaNIn) OfIntRes = {P.XLEN{1'b0}}; // unsigned negative
|
|
else OfIntRes = {P.XLEN{1'b1}}; // unsigned positive
|
|
end
|
|
|
|
// fcvtmod.w.d logic
|
|
// fcvtmod.w.d is like fcvt.w.d excep thtat it takes bits [31:0] and sign extends the rest,
|
|
// and converts +/-inf and NaN to zero.
|
|
|
|
if (P.ZFA_SUPPORTED & P.D_SUPPORTED) // fcvtmod.w.d support
|
|
always_comb begin
|
|
if (Zfa) OfIntRes2 = '0; // fcvtmod.w.d produces 0 on overflow
|
|
else OfIntRes2 = OfIntRes;
|
|
if (Zfa) Int64Res = {{(P.XLEN-32){CvtNegRes[P.XLEN-1]}}, CvtNegRes[31:0]};
|
|
else Int64Res = CvtNegRes[P.XLEN-1:0];
|
|
if (Zfa) SelCvtOfRes = InfIn | NaNIn | (CvtCe > 32 + 52); // fcvtmod.w.d only overflows to 0 on NaN or Infinity, or if the shift is so large that only zeros are left
|
|
else SelCvtOfRes = IntInvalid; // regular fcvt gives an overflow if out of range
|
|
end
|
|
else
|
|
always_comb begin // no fcvtmod.w.d support
|
|
OfIntRes2 = OfIntRes;
|
|
Int64Res = CvtNegRes[P.XLEN-1:0];
|
|
SelCvtOfRes = IntInvalid;
|
|
end
|
|
|
|
// select the integer output
|
|
// - if the input is invalid (out of bounds NaN or Inf) then output overflow res
|
|
// - if the input underflows
|
|
// - if rounding and signed operation and negative input, output -1
|
|
// - otherwise output a rounded 0
|
|
// - otherwise output the normal res (trmined and sign extended if nessisary)
|
|
always_comb
|
|
if(SelCvtOfRes) FCvtIntRes = OfIntRes2;
|
|
else if(CvtCe[P.NE])
|
|
if(Xs&Signed&Plus1) FCvtIntRes = {{P.XLEN{1'b1}}};
|
|
else FCvtIntRes = {{P.XLEN-1{1'b0}}, Plus1};
|
|
else if(Int64) FCvtIntRes = Int64Res;
|
|
else FCvtIntRes = {{P.XLEN-32{CvtNegRes[31]}}, CvtNegRes[31:0]};
|
|
endmodule
|