118 lines
3.9 KiB
Systemverilog
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
|
|
|