Loading files
import OpFormatTypes::*;
import BasicTypes::*;
function automatic [5:0] leading_zeros_count(
input logic [31:0] x
);
for(leading_zeros_count = 0; leading_zeros_count <= 31; leading_zeros_count = leading_zeros_count + 1)
if(x >> (31-leading_zeros_count) != 0) break;
endfunction
function automatic void FP32CVT_I2F(
input
logic [31:0] lhs,
logic fmt_unsigned,
Rounding_Mode rm,
output
logic [31:0] result,
FFlags_Path fflags
);
logic is_exact, is_valid, lhs_is_neg;
logic [5:0] lzc;
logic [31:0] abs_lhs, shifted_lhs; // hidden 1(1) + mantissa(23) + lower_bits(8)
logic [7:0] expo;
logic [22:0] mant;
logic round_up, exp_plus_one;
logic lsb, guard, sticky;
lhs_is_neg = ~fmt_unsigned & lhs[31];
abs_lhs = lhs_is_neg ? -lhs : lhs;
lzc = leading_zeros_count(abs_lhs);
shifted_lhs = abs_lhs << lzc;
mant = shifted_lhs[30:8];
expo = (abs_lhs == '0) ? 0 : 8'd127 + 8'd31 - lzc;
{lsb, guard, sticky} = {shifted_lhs[8:7], |shifted_lhs[6:0]};
case (rm)
RM_RNE: round_up = guard & (lsb | sticky);
RM_RTZ: round_up = FALSE;
RM_RDN: round_up = (guard | sticky) & lhs_is_neg;
RM_RUP: round_up = (guard | sticky) & ~lhs_is_neg;
RM_RMM: round_up = guard;
default: round_up = FALSE; // RTZ
endcase
exp_plus_one = round_up & (&mant); // 1.111111.. + round_up
expo = expo + {7'h0, exp_plus_one};
mant = mant + {22'h0, round_up};
result = {lhs_is_neg, expo, mant};
// fflag update
fflags = '0;
if (guard | sticky) begin
fflags.NX = TRUE;
end
endfunction
function automatic void FP32CVT_F2I(
input
logic [31:0] lhs,
logic fmt_unsigned,
Rounding_Mode rm,
output
logic [31:0] result,
FFlags_Path fflags
);
logic sign;
logic [7:0] expo;
logic [22:0] mant;
logic [4:0] shift_amount;
logic [31:0] int_result, abs_result;
logic [22:0] lower_bits;
logic round_up;
logic lsb, guard, sticky;
logic is_invalid, lhs_is_neg, lhs_is_nan;
{sign, expo, mant} = lhs;
/* verilator lint_off WIDTH */
shift_amount = 158 - expo;
/* verilator lint_on WIDTH */
lhs_is_neg = sign;
lhs_is_nan = expo == 8'hff & mant != 0;
if (expo <= 126) begin // e < 0
int_result = 0;
lsb = 0;
guard = (expo == 126) ? 1 : 0;
sticky = (expo == 0 || expo == 126) ? |mant : 1;
end
else if (expo <= 157) begin // 0 <= e <= 30
{int_result, lower_bits} = {1'b1, mant, 31'h0} >> shift_amount;
lsb = int_result[0];
{guard, sticky} = {lower_bits[22], |lower_bits[21:0]};
end
else if (expo == 158) begin // e = 31
if (fmt_unsigned) begin
int_result = lhs_is_neg ? 32'h00000000 : {1'b1, mant, 8'h0};
end
else begin
int_result = lhs_is_neg ? 32'h80000000 : 32'h7fffffff;
end
end
else begin // e > 31(overflow)
if(fmt_unsigned) begin
int_result = (~lhs_is_nan & lhs_is_neg) ? 32'h00000000 : 32'hffffffff;
end
else begin
int_result = (~lhs_is_nan & lhs_is_neg) ? 32'h80000000 : 32'h7fffffff;
end
end
// rounding
case (rm)
RM_RNE: round_up = guard & (lsb | sticky);
RM_RTZ: round_up = FALSE;
RM_RDN: round_up = (guard | sticky) & lhs_is_neg;
RM_RUP: round_up = (guard | sticky) & ~lhs_is_neg;
RM_RMM: round_up = guard;
default: round_up = FALSE; // RTZ
endcase
if (expo <= 157) begin
int_result = int_result + {31'h0, round_up};
result = lhs_is_neg ? (fmt_unsigned ? 32'h0 : -int_result): int_result;
end
else begin
//result = (fmt_unsigned & lhs_is_neg & ~lhs_is_nan) ? 32'h0 : int_result;
result = int_result;
end
fflags = '0;
// fflag update
is_invalid = expo >= 159 | // overflow or nan/inf
(~fmt_unsigned & expo == 158 & (~lhs_is_neg | (lhs_is_neg & mant != 0))) | // overflow in signed conversino
(fmt_unsigned & lhs_is_neg & (expo >= 127 | round_up)); // rounded result is negative in unsigned conversion
if (is_invalid) begin
fflags.NV = TRUE;
end
else if (guard | sticky) begin
fflags.NX = TRUE;
end
endfunction
module FP32PipelinedOther #(parameter PIPELINE_DEPTH = 5)(
input
logic clk,
logic [31:0] lhs,
logic [31:0] rhs,
FPU_Code fpuCode,
Rounding_Mode rm,
output
logic [31:0] result,
FFlags_Path fflags
);
logic [31:0] resultOut;
FFlags_Path fflagsOut;
typedef struct packed {
logic [31:0] result;
FFlags_Path fflags;
} PipeRegPath;
PipeRegPath pipeReg[PIPELINE_DEPTH - 1];
// just a buffer
always_comb begin
if( PIPELINE_DEPTH > 1) begin
{result, fflags} = pipeReg[0];
end else begin
{result, fflags} = {resultOut, fflagsOut};
end
end
always_ff @(posedge clk) begin
if (PIPELINE_DEPTH > 1) begin
pipeReg[PIPELINE_DEPTH-2] <= {resultOut, fflagsOut};
for (int i=1; i < PIPELINE_DEPTH - 1; ++i) begin
pipeReg[i-1] <= pipeReg[i];
end
end
end
// exec unit
logic lhs_sign, rhs_sign;
logic [7:0] lhs_expo, rhs_expo;
logic [22:0] lhs_mant, rhs_mant;
logic lhs_is_zero, rhs_is_zero, lhs_is_inf, rhs_is_inf, lhs_is_nan, rhs_is_nan;
logic lhs_is_snan, rhs_is_snan, lhs_is_subnormal, lhs_is_normal;
logic lhs_is_smaller, lhs_equal_rhs;
logic fmt_unsigned;
always_comb begin
{lhs_sign, lhs_expo, lhs_mant} = lhs;
{rhs_sign, rhs_expo, rhs_mant} = rhs;
lhs_is_zero = lhs_expo == 8'h00 & lhs_mant == 0;
rhs_is_zero = rhs_expo == 8'h00 & rhs_mant == 0;
lhs_is_inf = lhs_expo == 8'hff & lhs_mant == 0;
rhs_is_inf = rhs_expo == 8'hff & rhs_mant == 0;
lhs_is_nan = lhs_expo == 8'hff & lhs_mant != 0;
rhs_is_nan = rhs_expo == 8'hff & rhs_mant != 0;
lhs_is_snan = lhs_is_nan & lhs_mant[22] == 0;
rhs_is_snan = rhs_is_nan & rhs_mant[22] == 0;
lhs_is_subnormal = lhs_expo == 0 & lhs_mant != 0;
lhs_is_normal = ~(lhs_is_zero | lhs_is_inf | lhs_is_nan | lhs_is_subnormal);
lhs_is_smaller = (lhs < rhs) ^ ( lhs_sign | rhs_sign);
// +0 normally compares as equal to -0
lhs_equal_rhs = (lhs == rhs) | (lhs_is_zero && rhs_is_zero);
fmt_unsigned = fpuCode inside {FC_FCVT_SWU, FC_FCVT_WUS};
fflagsOut = '0;
unique case(fpuCode)
FC_SGNJ: begin
resultOut = {rhs_sign, lhs_expo, lhs_mant};
end
FC_SGNJN: begin
resultOut = {~rhs_sign, lhs_expo, lhs_mant};
end
FC_SGNJX: begin
resultOut = {lhs_sign ^ rhs_sign, lhs_expo, lhs_mant};
end
FC_FMIN: begin
if (lhs_is_nan & rhs_is_nan) begin
resultOut = 32'h7fc00000;
end
else if (lhs_is_nan) begin
resultOut = rhs;
end
else if (rhs_is_nan) begin
resultOut = lhs;
end
else begin
resultOut = lhs_is_smaller ? lhs : rhs;
end
// update fflags
if (lhs_is_snan || rhs_is_snan) begin
fflagsOut.NV = TRUE;
end
end
FC_FMAX: begin
if (lhs_is_nan & rhs_is_nan) begin
resultOut = 32'h7fc00000;
end
else if (lhs_is_nan) begin
resultOut = rhs;
end
else if (rhs_is_nan) begin
resultOut = lhs;
end
else begin
resultOut = lhs_is_smaller ? rhs : lhs;
end
if (lhs_is_snan || rhs_is_snan) begin
fflagsOut.NV = TRUE;
end
end
FC_FMV_WX, FC_FMV_XW: begin
resultOut = lhs;
end
FC_FCVT_SW, FC_FCVT_SWU: begin
FP32CVT_I2F(lhs, fmt_unsigned, rm, resultOut, fflagsOut);
end
FC_FCVT_WS, FC_FCVT_WUS: begin
FP32CVT_F2I(lhs, fmt_unsigned, rm, resultOut, fflagsOut);
end
FC_FEQ: begin
if (lhs_is_nan || rhs_is_nan) begin
resultOut = 0;
end
else begin
resultOut = lhs_equal_rhs;
end
// quiet comparsion
if (lhs_is_snan || rhs_is_snan) begin
fflagsOut.NV = TRUE;
end
end
FC_FLT: begin
if (lhs_is_nan || rhs_is_nan) begin
resultOut = 0;
fflagsOut.NV = TRUE;
end
else begin
//flt.s -0, +0 = 0
resultOut = lhs_is_smaller & ~lhs_equal_rhs;
end
end
FC_FLE: begin
if (lhs_is_nan || rhs_is_nan) begin
resultOut = 0;
fflagsOut.NV = TRUE;
end
else begin
resultOut = lhs_is_smaller | lhs_equal_rhs;
end
end
FC_FCLASS: begin
resultOut = {
22'h0,
lhs_is_nan & ~lhs_is_snan, // quiet NaN
lhs_is_snan, // signaling NaN
~lhs_sign & lhs_is_inf, // +inf
~lhs_sign & lhs_is_normal, // +subnormal
~lhs_sign & lhs_is_subnormal, // +normal
~lhs_sign & lhs_is_zero, // +0
lhs_sign & lhs_is_zero, // -0
lhs_sign & lhs_is_subnormal, // -subnormal
lhs_sign & lhs_is_normal, // -normal
lhs_sign & lhs_is_inf // -inf
};
end
default: begin
resultOut = '0;
fflagsOut = '0;
end
endcase
end
endmodule
dbfa8e081This file is pinned to the selected release. Download the original to open it in your design tool.