HWDigSys-II/src/exception_mult.sv

118 lines
3.9 KiB
Systemverilog

// exception_mult.sv
// Handles the exceptional cases
`include "round_modes.sv"
module exception_mult (
input logic [31:0] a, b,
input logic [31:0] z_calc,
input logic ovf, unf, inexact,
input logic [2:0] round,
output logic [31:0] z,
output logic zero_f, inf_f, nan_f, tiny_f, huge_f, inexact_f
);
// === ENUM DECLARATION ===
typedef enum logic [2:0] {
ZERO,
INF,
NORM,
MIN_NORM,
MAX_NORM
} interp_t;
// === num_interp FUNCTION ===
function interp_t num_interp(input logic [31:0] x);
automatic logic [7:0] exp = x[30:23];
automatic logic [22:0] mant = x[22:0];
if (exp == 8'd255)
return INF;
else if (exp == 8'd0)
return ZERO;
else if (exp == 8'd1 && mant == 0)
return MIN_NORM;
else if (exp == 8'd254 && mant == 23'h7FFFFF)
return MAX_NORM;
else
return NORM;
endfunction
// === z_num FUNCTION ===
function logic [30:0] z_num(input interp_t kind);
case (kind)
ZERO: return 31'd0;
INF: return {8'd255, 23'd0};
MIN_NORM: return {8'd1, 23'd0};
MAX_NORM: return {8'd254, 23'h7FFFFF};
default: return 31'd0;
endcase
endfunction
// === MAIN LOGIC ===
interp_t a_class, b_class;
logic sign;
always_comb begin
a_class = num_interp(a);
b_class = num_interp(b);
sign = z_calc[31];
// Default flags
{zero_f, inf_f, nan_f, tiny_f, huge_f, inexact_f} = '0;
z = z_calc;
case ({a_class, b_class})
{ZERO, ZERO}, {ZERO, NORM}, {NORM, ZERO}:
begin
z = {sign, z_num(ZERO)};
zero_f = 1;
end
{ZERO, INF}, {INF, ZERO}:
begin
z = {sign, z_num(INF)};
nan_f = 1;
end
{INF, INF}, {NORM, INF}, {INF, NORM}:
begin
z = {sign, z_num(INF)};
inf_f = 1;
end
default: begin // {NORM, NORM}
if (ovf) begin
case (round)
RND_IEEE_NEAREST_EVEN: z = {sign, z_num(MAX_NORM)};
RND_IEEE_ZERO: z = {sign, z_num(MAX_NORM)};
RND_IEEE_PINF: z = (sign == 0) ? {1'b0, z_num(INF)} : {1'b1, z_num(MAX_NORM)};
RND_IEEE_NINF: z = (sign == 1) ? {1'b1, z_num(INF)} : {1'b0, z_num(MAX_NORM)};
RND_NEAR_UP: z = (sign == 0) ? {1'b1, z_num(INF)} : {1'b0, z_num(MIN_NORM)};
RND_AWAY_ZERO: z = {sign, z_num(MAX_NORM)};
default: z = {sign, z_num(MAX_NORM)};
endcase
huge_f = 1;
end
else if (unf) begin
case (round)
RND_IEEE_NEAREST_EVEN: z = {sign, z_num(MIN_NORM)};
RND_IEEE_ZERO: z = {sign, z_num(ZERO)};
RND_IEEE_PINF: z = (sign == 0) ? {1'b0, z_num(MIN_NORM)} : {1'b1, z_num(ZERO)};
RND_IEEE_NINF: z = (sign == 1) ? {1'b1, z_num(MIN_NORM)} : {1'b0, z_num(ZERO)};
RND_NEAR_UP: z = (sign == 1) ? {1'b1, z_num(ZERO)} : {1'b0, z_num(MIN_NORM)};
RND_AWAY_ZERO: z = {sign, z_num(MIN_NORM)};
default: z = {sign, z_num(MIN_NORM)};
endcase
tiny_f = 1;
end
inf_f = (z[30:0] == z_num(INF));
zero_f = (z[30:0] == z_num(ZERO));
inexact_f = inexact || ovf || unf;
end
endcase
end
endmodule