aboutsummaryrefslogtreecommitdiff
path: root/rv64cpu/rtl/core/fpu/fpu_unit.sv
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-11-07 03:14:46 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-11-07 03:14:46 +0800
commit6f57dd79572c177b775a934bee54ceb85a55c28a (patch)
treeb0b26bbbe8d424730afcd437cb5a2220b1fd8542 /rv64cpu/rtl/core/fpu/fpu_unit.sv
parent1410d3309ae9557ab102942bbc4d8449f2206fe5 (diff)
downloadrcc-project-6f57dd79572c177b775a934bee54ceb85a55c28a.tar.gz
rcc-project-6f57dd79572c177b775a934bee54ceb85a55c28a.tar.xz
refactor: rename RTL source files
Diffstat (limited to 'rv64cpu/rtl/core/fpu/fpu_unit.sv')
-rw-r--r--rv64cpu/rtl/core/fpu/fpu_unit.sv2392
1 files changed, 0 insertions, 2392 deletions
diff --git a/rv64cpu/rtl/core/fpu/fpu_unit.sv b/rv64cpu/rtl/core/fpu/fpu_unit.sv
deleted file mode 100644
index a1962e1..0000000
--- a/rv64cpu/rtl/core/fpu/fpu_unit.sv
+++ /dev/null
@@ -1,2392 +0,0 @@
-// Richard CPU
-// Copyright (C) 2026 Richard Qin
-
-// File path: rtl/core/fpu/fpu_unit.sv
-// Description: RV64F/RV64D floating-point execution unit.
-
-module fpu_unit
- import rv64_pkg::*;
-(
- input fp_op_t fp_op,
- input fp_fmt_t fp_fmt,
- input logic [2:0] rm,
- input logic [2:0] funct3,
- input logic [4:0] rs2_addr,
- input logic [XLEN-1:0] fs1_data,
- input logic [XLEN-1:0] fs2_data,
- input logic [XLEN-1:0] fs3_data,
- input logic [XLEN-1:0] int_rs1_data,
-
- output logic [XLEN-1:0] fp_result,
- output logic [XLEN-1:0] int_result,
- output logic [4:0] fflags,
- output logic illegal_instr
-);
-
- localparam logic [31:0] CANONICAL_NAN_S = 32'h7FC0_0000;
- localparam logic [63:0] CANONICAL_NAN_D = 64'h7FF8_0000_0000_0000;
-
- logic [31:0] s1_raw;
- logic [31:0] s2_raw;
- logic [31:0] s3_raw;
- logic [31:0] s1;
- logic [31:0] s2;
- logic [31:0] s3;
- logic [63:0] d1;
- logic [63:0] d2;
- logic [63:0] d3;
-
- assign s1_raw = fs1_data[31:0];
- assign s2_raw = fs2_data[31:0];
- assign s3_raw = fs3_data[31:0];
- assign s1 = (fs1_data[63:32] == 32'hFFFF_FFFF) ? s1_raw : CANONICAL_NAN_S;
- assign s2 = (fs2_data[63:32] == 32'hFFFF_FFFF) ? s2_raw : CANONICAL_NAN_S;
- assign s3 = (fs3_data[63:32] == 32'hFFFF_FFFF) ? s3_raw : CANONICAL_NAN_S;
- assign d1 = fs1_data;
- assign d2 = fs2_data;
- assign d3 = fs3_data;
-
- function automatic logic is_nan_s(input logic [31:0] value);
- return (&value[30:23]) && (|value[22:0]);
- endfunction
-
- function automatic logic is_snan_s(input logic [31:0] value);
- return is_nan_s(value) && (value[22] == 1'b0);
- endfunction
-
- function automatic logic is_nan_d(input logic [63:0] value);
- return (&value[62:52]) && (|value[51:0]);
- endfunction
-
- function automatic logic is_snan_d(input logic [63:0] value);
- return is_nan_d(value) && (value[51] == 1'b0);
- endfunction
-
- function automatic logic [9:0] class_s(input logic [31:0] value);
- logic sign;
- logic [7:0] exp;
- logic [22:0] frac;
- sign = value[31];
- exp = value[30:23];
- frac = value[22:0];
- class_s = '0;
- if (&exp && (frac != '0)) begin
- class_s[is_snan_s(value) ? 8 : 9] = 1'b1;
- end else if (sign && (&exp) && (frac == '0)) begin
- class_s[0] = 1'b1;
- end else if (sign && (exp != '0)) begin
- class_s[1] = 1'b1;
- end else if (sign && (exp == '0) && (frac != '0)) begin
- class_s[2] = 1'b1;
- end else if (sign && (exp == '0) && (frac == '0)) begin
- class_s[3] = 1'b1;
- end else if (!sign && (exp == '0) && (frac == '0)) begin
- class_s[4] = 1'b1;
- end else if (!sign && (exp == '0) && (frac != '0)) begin
- class_s[5] = 1'b1;
- end else if (!sign && (exp != '0) && !(&exp)) begin
- class_s[6] = 1'b1;
- end else if (!sign && (&exp) && (frac == '0)) begin
- class_s[7] = 1'b1;
- end
- endfunction
-
- function automatic logic [9:0] class_d(input logic [63:0] value);
- logic sign;
- logic [10:0] exp;
- logic [51:0] frac;
- sign = value[63];
- exp = value[62:52];
- frac = value[51:0];
- class_d = '0;
- if (&exp && (frac != '0)) begin
- class_d[is_snan_d(value) ? 8 : 9] = 1'b1;
- end else if (sign && (&exp) && (frac == '0)) begin
- class_d[0] = 1'b1;
- end else if (sign && (exp != '0)) begin
- class_d[1] = 1'b1;
- end else if (sign && (exp == '0) && (frac != '0)) begin
- class_d[2] = 1'b1;
- end else if (sign && (exp == '0) && (frac == '0)) begin
- class_d[3] = 1'b1;
- end else if (!sign && (exp == '0) && (frac == '0)) begin
- class_d[4] = 1'b1;
- end else if (!sign && (exp == '0) && (frac != '0)) begin
- class_d[5] = 1'b1;
- end else if (!sign && (exp != '0) && !(&exp)) begin
- class_d[6] = 1'b1;
- end else if (!sign && (&exp) && (frac == '0)) begin
- class_d[7] = 1'b1;
- end
- endfunction
-
- function automatic logic less_s(input logic [31:0] lhs, input logic [31:0] rhs);
- logic lhs_neg;
- logic rhs_neg;
- lhs_neg = lhs[31];
- rhs_neg = rhs[31];
- if ((lhs[30:0] == '0) && (rhs[30:0] == '0)) begin
- return 1'b0;
- end
- if (lhs_neg != rhs_neg) begin
- return lhs_neg;
- end
- return lhs_neg ? (lhs[30:0] > rhs[30:0]) : (lhs[30:0] < rhs[30:0]);
- endfunction
-
- function automatic logic less_d(input logic [63:0] lhs, input logic [63:0] rhs);
- logic lhs_neg;
- logic rhs_neg;
- lhs_neg = lhs[63];
- rhs_neg = rhs[63];
- if ((lhs[62:0] == '0) && (rhs[62:0] == '0)) begin
- return 1'b0;
- end
- if (lhs_neg != rhs_neg) begin
- return lhs_neg;
- end
- return lhs_neg ? (lhs[62:0] > rhs[62:0]) : (lhs[62:0] < rhs[62:0]);
- endfunction
-
- function automatic logic equal_s(input logic [31:0] lhs, input logic [31:0] rhs);
- if ((lhs[30:0] == '0) && (rhs[30:0] == '0)) begin
- return 1'b1;
- end
- return lhs == rhs;
- endfunction
-
- function automatic logic equal_d(input logic [63:0] lhs, input logic [63:0] rhs);
- if ((lhs[62:0] == '0) && (rhs[62:0] == '0)) begin
- return 1'b1;
- end
- return lhs == rhs;
- endfunction
-
- function automatic logic [2:0] effective_rm(input logic [2:0] rm_value);
- effective_rm = (rm_value <= 3'b100) ? rm_value : 3'b000;
- endfunction
-
- function automatic logic round_increment(
- input logic [2:0] round_mode,
- input logic sign,
- input logic [127:0] quotient,
- input logic [127:0] remainder,
- input logic [127:0] half
- );
- logic greater_than_half;
- logic equal_to_half;
-
- greater_than_half = remainder > half;
- equal_to_half = remainder == half;
-
- unique case (effective_rm(round_mode))
- 3'b000: round_increment = greater_than_half || (equal_to_half && quotient[0]); // RNE
- 3'b001: round_increment = 1'b0; // RTZ
- 3'b010: round_increment = sign && (remainder != '0); // RDN
- 3'b011: round_increment = !sign && (remainder != '0); // RUP
- 3'b100: round_increment = greater_than_half || equal_to_half; // RMM
- default: round_increment = 1'b0;
- endcase
- endfunction
-
- function automatic logic [63:0] invalid_integer_result(
- input logic is_signed,
- input logic is_long,
- input logic sign,
- input logic is_nan
- );
- if (is_signed) begin
- if (sign && !is_nan) begin
- invalid_integer_result = is_long ? 64'h8000_0000_0000_0000 : 64'hFFFF_FFFF_8000_0000;
- end else begin
- invalid_integer_result = is_long ? 64'h7FFF_FFFF_FFFF_FFFF : 64'h0000_0000_7FFF_FFFF;
- end
- end else begin
- if (sign && !is_nan) begin
- invalid_integer_result = '0;
- end else begin
- invalid_integer_result = 64'hFFFF_FFFF_FFFF_FFFF;
- end
- end
- endfunction
-
- function automatic logic [63:0] cvt_s_to_int(
- input logic [31:0] value,
- input logic [1:0] int_fmt,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic sign;
- logic [7:0] exp;
- logic [22:0] frac;
- logic [23:0] significand;
- logic signed [12:0] unbiased_exp;
- logic is_signed;
- logic is_long;
- logic invalid;
- logic inexact;
- logic [127:0] magnitude;
- logic [127:0] quotient;
- logic [127:0] remainder;
- logic [127:0] divisor;
- logic [127:0] half;
- logic [127:0] rounded_magnitude;
- logic [63:0] positive_limit;
- logic [63:0] negative_limit;
- logic [63:0] unsigned_limit;
- logic [63:0] integer_value;
- int shift;
-
- sign = value[31];
- exp = value[30:23];
- frac = value[22:0];
- significand = (exp == '0) ? {1'b0, frac} : {1'b1, frac};
- unbiased_exp = $signed({5'b0, exp}) - 13'sd127;
- is_signed = (int_fmt == 2'd0) || (int_fmt == 2'd2);
- is_long = (int_fmt == 2'd2) || (int_fmt == 2'd3);
- invalid = 1'b0;
- inexact = 1'b0;
- magnitude = '0;
- quotient = '0;
- remainder = '0;
- divisor = '0;
- half = '0;
- rounded_magnitude = '0;
- positive_limit = is_long ? 64'h7FFF_FFFF_FFFF_FFFF : 64'h0000_0000_7FFF_FFFF;
- negative_limit = is_long ? 64'h8000_0000_0000_0000 : 64'h0000_0000_8000_0000;
- unsigned_limit = is_long ? 64'hFFFF_FFFF_FFFF_FFFF : 64'h0000_0000_FFFF_FFFF;
- integer_value = '0;
- flags = '0;
-
- if (is_nan_s(value) || (&exp)) begin
- invalid = 1'b1;
- end else if (significand == '0) begin
- rounded_magnitude = '0;
- end else begin
- if (unbiased_exp >= 13'sd23) begin
- shift = int'(unbiased_exp) - 23;
- if (shift >= 104) begin
- invalid = 1'b1;
- end else begin
- rounded_magnitude = {104'b0, significand} << shift;
- end
- end else begin
- shift = 23 - int'(unbiased_exp);
- if (shift > 24) begin
- quotient = '0;
- remainder = {104'b0, significand};
- divisor = '0;
- half = '0;
- inexact = remainder != '0;
- unique case (effective_rm(round_mode))
- 3'b010: rounded_magnitude = (sign && inexact) ? 128'd1 : 128'd0;
- 3'b011: rounded_magnitude = (!sign && inexact) ? 128'd1 : 128'd0;
- default: rounded_magnitude = '0;
- endcase
- end else begin
- divisor = 128'd1 << shift;
- quotient = {104'b0, significand} >> shift;
- remainder = {104'b0, significand} & (divisor - 128'd1);
- half = divisor >> 1;
- inexact = (remainder != '0);
- rounded_magnitude = quotient +
- (round_increment(round_mode, sign, quotient, remainder, half) ? 128'd1 : 128'd0);
- end
- end
- end
-
- if (!invalid) begin
- if (is_signed) begin
- if ((!sign && (rounded_magnitude > {64'b0, positive_limit})) ||
- (sign && (rounded_magnitude > {64'b0, negative_limit}))) begin
- invalid = 1'b1;
- end
- end else begin
- if ((sign && (rounded_magnitude != '0)) ||
- (rounded_magnitude > {64'b0, unsigned_limit})) begin
- invalid = 1'b1;
- end
- end
- end
-
- if (invalid) begin
- flags[4] = 1'b1;
- return invalid_integer_result(is_signed, is_long, sign, is_nan_s(value));
- end
-
- if (inexact) begin
- flags[0] = 1'b1;
- end
-
- integer_value = rounded_magnitude[63:0];
- if (sign) begin
- integer_value = (~integer_value) + 64'd1;
- end
-
- if (!is_long) begin
- return {{32{integer_value[31]}}, integer_value[31:0]};
- end
-
- return integer_value;
- endfunction
-
- function automatic logic [63:0] cvt_d_to_int(
- input logic [63:0] value,
- input logic [1:0] int_fmt,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic sign;
- logic [10:0] exp;
- logic [51:0] frac;
- logic [52:0] significand;
- logic signed [12:0] unbiased_exp;
- logic is_signed;
- logic is_long;
- logic invalid;
- logic inexact;
- logic [127:0] quotient;
- logic [127:0] remainder;
- logic [127:0] divisor;
- logic [127:0] half;
- logic [127:0] rounded_magnitude;
- logic [63:0] positive_limit;
- logic [63:0] negative_limit;
- logic [63:0] unsigned_limit;
- logic [63:0] integer_value;
- int shift;
-
- sign = value[63];
- exp = value[62:52];
- frac = value[51:0];
- significand = (exp == '0) ? {1'b0, frac} : {1'b1, frac};
- unbiased_exp = $signed({2'b0, exp}) - 13'sd1023;
- is_signed = (int_fmt == 2'd0) || (int_fmt == 2'd2);
- is_long = (int_fmt == 2'd2) || (int_fmt == 2'd3);
- invalid = 1'b0;
- inexact = 1'b0;
- quotient = '0;
- remainder = '0;
- divisor = '0;
- half = '0;
- rounded_magnitude = '0;
- positive_limit = is_long ? 64'h7FFF_FFFF_FFFF_FFFF : 64'h0000_0000_7FFF_FFFF;
- negative_limit = is_long ? 64'h8000_0000_0000_0000 : 64'h0000_0000_8000_0000;
- unsigned_limit = is_long ? 64'hFFFF_FFFF_FFFF_FFFF : 64'h0000_0000_FFFF_FFFF;
- integer_value = '0;
- flags = '0;
-
- if (is_nan_d(value) || (&exp)) begin
- invalid = 1'b1;
- end else if (significand == '0) begin
- rounded_magnitude = '0;
- end else begin
- if (unbiased_exp >= 13'sd52) begin
- shift = int'(unbiased_exp) - 52;
- if (shift >= 75) begin
- invalid = 1'b1;
- end else begin
- rounded_magnitude = {75'b0, significand} << shift;
- end
- end else begin
- shift = 52 - int'(unbiased_exp);
- if (shift > 53) begin
- quotient = '0;
- remainder = {75'b0, significand};
- inexact = remainder != '0;
- unique case (effective_rm(round_mode))
- 3'b010: rounded_magnitude = (sign && inexact) ? 128'd1 : 128'd0;
- 3'b011: rounded_magnitude = (!sign && inexact) ? 128'd1 : 128'd0;
- default: rounded_magnitude = '0;
- endcase
- end else begin
- divisor = 128'd1 << shift;
- quotient = {75'b0, significand} >> shift;
- remainder = {75'b0, significand} & (divisor - 128'd1);
- half = divisor >> 1;
- inexact = (remainder != '0);
- rounded_magnitude = quotient +
- (round_increment(round_mode, sign, quotient, remainder, half) ? 128'd1 : 128'd0);
- end
- end
- end
-
- if (!invalid) begin
- if (is_signed) begin
- if ((!sign && (rounded_magnitude > {64'b0, positive_limit})) ||
- (sign && (rounded_magnitude > {64'b0, negative_limit}))) begin
- invalid = 1'b1;
- end
- end else begin
- if ((sign && (rounded_magnitude != '0)) ||
- (rounded_magnitude > {64'b0, unsigned_limit})) begin
- invalid = 1'b1;
- end
- end
- end
-
- if (invalid) begin
- flags[4] = 1'b1;
- return invalid_integer_result(is_signed, is_long, sign, is_nan_d(value));
- end
-
- if (inexact) begin
- flags[0] = 1'b1;
- end
-
- integer_value = rounded_magnitude[63:0];
- if (sign) begin
- integer_value = (~integer_value) + 64'd1;
- end
-
- if (!is_long) begin
- return {{32{integer_value[31]}}, integer_value[31:0]};
- end
-
- return integer_value;
- endfunction
-
- function automatic int highest_bit_64(input logic [63:0] value);
- highest_bit_64 = -1;
- for (int bit_idx = 0; bit_idx < 64; bit_idx++) begin
- if (value[bit_idx]) begin
- highest_bit_64 = bit_idx;
- end
- end
- endfunction
-
- function automatic int highest_bit_53(input logic [52:0] value);
- highest_bit_53 = -1;
- for (int bit_idx = 0; bit_idx < 53; bit_idx++) begin
- if (value[bit_idx]) begin
- highest_bit_53 = bit_idx;
- end
- end
- endfunction
-
- function automatic logic [31:0] overflow_s_result(input logic sign, input logic [2:0] round_mode);
- unique case (effective_rm(round_mode))
- 3'b001: overflow_s_result = {sign, 8'hFE, 23'h7F_FFFF};
- 3'b010: overflow_s_result = sign ? 32'hFF80_0000 : 32'h7F7F_FFFF;
- 3'b011: overflow_s_result = sign ? 32'hFF7F_FFFF : 32'h7F80_0000;
- default: overflow_s_result = {sign, 8'hFF, 23'b0};
- endcase
- endfunction
-
- function automatic logic [63:0] overflow_d_result(input logic sign, input logic [2:0] round_mode);
- unique case (effective_rm(round_mode))
- 3'b001: overflow_d_result = {sign, 11'h7FE, 52'hF_FFFF_FFFF_FFFF};
- 3'b010: overflow_d_result = sign ? 64'hFFF0_0000_0000_0000 : 64'h7FEF_FFFF_FFFF_FFFF;
- 3'b011: overflow_d_result = sign ? 64'hFFEF_FFFF_FFFF_FFFF : 64'h7FF0_0000_0000_0000;
- default: overflow_d_result = {sign, 11'h7FF, 52'b0};
- endcase
- endfunction
-
- function automatic logic [27:0] shift_right_jam_28(
- input logic [27:0] value,
- input int shift
- );
- logic sticky;
-
- if (shift <= 0) begin
- return value;
- end
- if (shift >= 28) begin
- return (value != '0) ? 28'd1 : 28'd0;
- end
-
- sticky = 1'b0;
- for (int bit_idx = 0; bit_idx < 28; bit_idx++) begin
- if (bit_idx < shift) begin
- sticky = sticky | value[bit_idx];
- end
- end
- return (value >> shift) | (sticky ? 28'd1 : 28'd0);
- endfunction
-
- function automatic logic shifted_out_28(
- input logic [27:0] value,
- input int shift
- );
- logic sticky;
-
- if (shift <= 0) begin
- return 1'b0;
- end
- if (shift >= 28) begin
- return value != '0;
- end
-
- sticky = 1'b0;
- for (int bit_idx = 0; bit_idx < 28; bit_idx++) begin
- if (bit_idx < shift) begin
- sticky = sticky | value[bit_idx];
- end
- end
- return sticky;
- endfunction
-
- function automatic logic [27:0] shift_right_jam_48(
- input logic [47:0] value,
- input int shift
- );
- logic sticky;
- logic [27:0] shifted;
-
- if (shift <= 0) begin
- return value[27:0];
- end
- if (shift >= 48) begin
- return (value != '0) ? 28'd1 : 28'd0;
- end
-
- sticky = 1'b0;
- for (int bit_idx = 0; bit_idx < 48; bit_idx++) begin
- if (bit_idx < shift) begin
- sticky = sticky | value[bit_idx];
- end
- end
- shifted = 28'((value >> shift));
- return shifted | (sticky ? 28'd1 : 28'd0);
- endfunction
-
- function automatic logic [56:0] shift_right_jam_57(
- input logic [56:0] value,
- input int shift
- );
- logic sticky;
-
- if (shift <= 0) begin
- return value;
- end
- if (shift >= 57) begin
- return (value != '0) ? 57'd1 : 57'd0;
- end
-
- sticky = 1'b0;
- for (int bit_idx = 0; bit_idx < 57; bit_idx++) begin
- if (bit_idx < shift) begin
- sticky = sticky | value[bit_idx];
- end
- end
- return (value >> shift) | (sticky ? 57'd1 : 57'd0);
- endfunction
-
- function automatic logic [64:0] shift_right_jam_65(
- input logic [64:0] value,
- input int shift
- );
- logic sticky;
-
- if (shift <= 0) begin
- return value;
- end
- if (shift >= 65) begin
- return (value != '0) ? 65'd1 : 65'd0;
- end
-
- sticky = 1'b0;
- for (int bit_idx = 0; bit_idx < 65; bit_idx++) begin
- if (bit_idx < shift) begin
- sticky = sticky | value[bit_idx];
- end
- end
- return (value >> shift) | (sticky ? 65'd1 : 65'd0);
- endfunction
-
- function automatic logic [127:0] shift_right_jam_128(
- input logic [127:0] value,
- input int shift
- );
- logic sticky;
-
- if (shift <= 0) begin
- return value;
- end
- if (shift >= 128) begin
- return (value != '0) ? 128'd1 : 128'd0;
- end
-
- sticky = 1'b0;
- for (int bit_idx = 0; bit_idx < 128; bit_idx++) begin
- if (bit_idx < shift) begin
- sticky = sticky | value[bit_idx];
- end
- end
- return (value >> shift) | (sticky ? 128'd1 : 128'd0);
- endfunction
-
- function automatic logic [56:0] shift_right_jam_128_to_57(
- input logic [127:0] value,
- input int shift
- );
- logic sticky;
- logic [56:0] shifted;
-
- if (shift <= 0) begin
- return value[56:0];
- end
- if (shift >= 128) begin
- return (value != '0) ? 57'd1 : 57'd0;
- end
-
- sticky = 1'b0;
- for (int bit_idx = 0; bit_idx < 128; bit_idx++) begin
- if (bit_idx < shift) begin
- sticky = sticky | value[bit_idx];
- end
- end
- shifted = 57'(value >> shift);
- return shifted | (sticky ? 57'd1 : 57'd0);
- endfunction
-
- function automatic logic [31:0] round_pack_s(
- input logic sign,
- input logic signed [10:0] unbiased_exp,
- input logic [27:0] significand,
- input logic inexact_before_round,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic signed [10:0] result_unbiased_exp;
- logic [27:0] result_sig;
- logic round_any;
- logic round_up;
- logic [24:0] rounded_sig;
- logic [7:0] result_exp;
- logic [22:0] result_frac;
- logic tiny_before_round;
- int subnormal_shift;
-
- flags = '0;
- result_unbiased_exp = unbiased_exp;
- result_sig = significand;
- result_sig[0] = result_sig[0] | inexact_before_round;
- tiny_before_round = 1'b0;
-
- if (result_unbiased_exp < -11'sd126) begin
- tiny_before_round = 1'b1;
- subnormal_shift = -126 - int'(result_unbiased_exp);
- result_sig = shift_right_jam_28(result_sig, subnormal_shift);
- result_unbiased_exp = -11'sd126;
- end
-
- round_any = |result_sig[2:0];
- unique case (effective_rm(round_mode))
- 3'b000: round_up = result_sig[2] && (result_sig[1] || result_sig[0] || result_sig[3]);
- 3'b001: round_up = 1'b0;
- 3'b010: round_up = sign && round_any;
- 3'b011: round_up = !sign && round_any;
- 3'b100: round_up = result_sig[2];
- default: round_up = 1'b0;
- endcase
-
- rounded_sig = {1'b0, result_sig[26:3]} + (round_up ? 25'd1 : 25'd0);
- if (round_any) begin
- flags[0] = 1'b1;
- end
- if (tiny_before_round && flags[0]) begin
- flags[1] = 1'b1;
- end
-
- if (rounded_sig[24]) begin
- rounded_sig = rounded_sig >> 1;
- result_unbiased_exp = result_unbiased_exp + 11'sd1;
- end
-
- if (result_unbiased_exp > 11'sd127) begin
- flags[2] = 1'b1;
- flags[0] = 1'b1;
- return overflow_s_result(sign, round_mode);
- end
-
- if ((result_unbiased_exp == -11'sd126) && !rounded_sig[23]) begin
- result_exp = 8'b0;
- result_frac = rounded_sig[22:0];
- if (flags[0]) begin
- flags[1] = 1'b1;
- end
- end else begin
- result_exp = 8'(result_unbiased_exp + 11'sd127);
- result_frac = rounded_sig[22:0];
- end
-
- return {sign, result_exp, result_frac};
- endfunction
-
- function automatic logic [63:0] round_pack_d(
- input logic sign,
- input logic signed [12:0] unbiased_exp,
- input logic [56:0] significand,
- input logic inexact_before_round,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic signed [12:0] result_unbiased_exp;
- logic [56:0] result_sig;
- logic round_any;
- logic round_up;
- logic [53:0] rounded_sig;
- logic [10:0] result_exp;
- logic [51:0] result_frac;
- logic tiny_before_round;
- int subnormal_shift;
-
- flags = '0;
- result_unbiased_exp = unbiased_exp;
- result_sig = significand;
- result_sig[0] = result_sig[0] | inexact_before_round;
- tiny_before_round = 1'b0;
-
- if (result_unbiased_exp < -13'sd1022) begin
- tiny_before_round = 1'b1;
- subnormal_shift = -1022 - int'(result_unbiased_exp);
- result_sig = shift_right_jam_57(result_sig, subnormal_shift);
- result_unbiased_exp = -13'sd1022;
- end
-
- round_any = |result_sig[2:0];
- unique case (effective_rm(round_mode))
- 3'b000: round_up = result_sig[2] && (result_sig[1] || result_sig[0] || result_sig[3]);
- 3'b001: round_up = 1'b0;
- 3'b010: round_up = sign && round_any;
- 3'b011: round_up = !sign && round_any;
- 3'b100: round_up = result_sig[2];
- default: round_up = 1'b0;
- endcase
-
- rounded_sig = {1'b0, result_sig[55:3]} + (round_up ? 54'd1 : 54'd0);
- if (round_any) begin
- flags[0] = 1'b1;
- end
- if (tiny_before_round && flags[0]) begin
- flags[1] = 1'b1;
- end
-
- if (rounded_sig[53]) begin
- rounded_sig = rounded_sig >> 1;
- result_unbiased_exp = result_unbiased_exp + 13'sd1;
- end
-
- if (result_unbiased_exp > 13'sd1023) begin
- flags[2] = 1'b1;
- flags[0] = 1'b1;
- return overflow_d_result(sign, round_mode);
- end
-
- if ((result_unbiased_exp == -13'sd1022) && !rounded_sig[52]) begin
- result_exp = 11'b0;
- result_frac = rounded_sig[51:0];
- if (flags[0]) begin
- flags[1] = 1'b1;
- end
- end else begin
- result_exp = 11'(result_unbiased_exp + 13'sd1023);
- result_frac = rounded_sig[51:0];
- end
-
- return {sign, result_exp, result_frac};
- endfunction
-
- function automatic logic [31:0] fp_addsub_s(
- input logic [31:0] lhs,
- input logic [31:0] rhs,
- input logic subtract,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic lhs_sign;
- logic rhs_sign;
- logic result_sign;
- logic [7:0] lhs_exp;
- logic [7:0] rhs_exp;
- logic [22:0] lhs_frac;
- logic [22:0] rhs_frac;
- logic lhs_is_zero;
- logic rhs_is_zero;
- logic lhs_is_inf;
- logic rhs_is_inf;
- logic signed [10:0] lhs_unbiased_exp;
- logic signed [10:0] rhs_unbiased_exp;
- logic signed [10:0] result_unbiased_exp;
- logic [27:0] lhs_sig;
- logic [27:0] rhs_sig;
- logic [27:0] result_sig;
- logic [27:0] larger_sig;
- logic [27:0] smaller_sig;
- logic signed [10:0] larger_exp;
- logic signs_match;
- logic alignment_inexact;
- int exp_diff;
-
- flags = '0;
- lhs_sign = lhs[31];
- rhs_sign = rhs[31] ^ subtract;
- lhs_exp = lhs[30:23];
- rhs_exp = rhs[30:23];
- lhs_frac = lhs[22:0];
- rhs_frac = rhs[22:0];
- lhs_is_zero = (lhs[30:0] == '0);
- rhs_is_zero = (rhs[30:0] == '0);
- lhs_is_inf = (&lhs_exp) && (lhs_frac == '0);
- rhs_is_inf = (&rhs_exp) && (rhs_frac == '0);
- signs_match = lhs_sign == rhs_sign;
- alignment_inexact = 1'b0;
-
- if (is_nan_s(lhs) || is_nan_s(rhs)) begin
- flags[4] = is_snan_s(lhs) || is_snan_s(rhs);
- return CANONICAL_NAN_S;
- end
-
- if (lhs_is_inf || rhs_is_inf) begin
- if (lhs_is_inf && rhs_is_inf && !signs_match) begin
- flags[4] = 1'b1;
- return CANONICAL_NAN_S;
- end
- return lhs_is_inf ? {lhs_sign, 8'hFF, 23'b0} : {rhs_sign, 8'hFF, 23'b0};
- end
-
- if (lhs_is_zero && rhs_is_zero) begin
- result_sign = signs_match ? lhs_sign : (effective_rm(round_mode) == 3'b010);
- return {result_sign, 31'b0};
- end
- if (lhs_is_zero) begin
- return {rhs_sign, rhs[30:0]};
- end
- if (rhs_is_zero) begin
- return lhs;
- end
-
- lhs_unbiased_exp = (lhs_exp == '0) ? -11'sd126 : ($signed({3'b0, lhs_exp}) - 11'sd127);
- rhs_unbiased_exp = (rhs_exp == '0) ? -11'sd126 : ($signed({3'b0, rhs_exp}) - 11'sd127);
- lhs_sig = {1'b0, (lhs_exp == '0) ? 1'b0 : 1'b1, lhs_frac, 3'b000};
- rhs_sig = {1'b0, (rhs_exp == '0) ? 1'b0 : 1'b1, rhs_frac, 3'b000};
-
- if ((lhs_unbiased_exp > rhs_unbiased_exp) ||
- ((lhs_unbiased_exp == rhs_unbiased_exp) && (lhs_sig >= rhs_sig))) begin
- exp_diff = int'(lhs_unbiased_exp) - int'(rhs_unbiased_exp);
- larger_sig = lhs_sig;
- alignment_inexact = shifted_out_28(rhs_sig, exp_diff);
- smaller_sig = shift_right_jam_28(rhs_sig, exp_diff);
- larger_exp = lhs_unbiased_exp;
- result_sign = lhs_sign;
- end else begin
- exp_diff = int'(rhs_unbiased_exp) - int'(lhs_unbiased_exp);
- larger_sig = rhs_sig;
- alignment_inexact = shifted_out_28(lhs_sig, exp_diff);
- smaller_sig = shift_right_jam_28(lhs_sig, exp_diff);
- larger_exp = rhs_unbiased_exp;
- result_sign = rhs_sign;
- end
-
- result_unbiased_exp = larger_exp;
- if (signs_match) begin
- result_sig = larger_sig + smaller_sig;
- if (result_sig[27]) begin
- result_sig = shift_right_jam_28(result_sig, 1);
- result_unbiased_exp = result_unbiased_exp + 11'sd1;
- end
- end else begin
- result_sig = larger_sig - smaller_sig;
- if (result_sig == '0) begin
- result_sign = effective_rm(round_mode) == 3'b010;
- return {result_sign, 31'b0};
- end
- while (!result_sig[26] && (result_unbiased_exp > -11'sd126)) begin
- result_sig = result_sig << 1;
- result_unbiased_exp = result_unbiased_exp - 11'sd1;
- end
- end
-
- return round_pack_s(result_sign, result_unbiased_exp, result_sig, alignment_inexact, round_mode, flags);
- endfunction
-
- function automatic logic [63:0] fp_addsub_d(
- input logic [63:0] lhs,
- input logic [63:0] rhs,
- input logic subtract,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic lhs_sign;
- logic rhs_sign;
- logic result_sign;
- logic [10:0] lhs_exp;
- logic [10:0] rhs_exp;
- logic [51:0] lhs_frac;
- logic [51:0] rhs_frac;
- logic lhs_is_zero;
- logic rhs_is_zero;
- logic lhs_is_inf;
- logic rhs_is_inf;
- logic signed [12:0] lhs_unbiased_exp;
- logic signed [12:0] rhs_unbiased_exp;
- logic signed [12:0] result_unbiased_exp;
- logic [56:0] lhs_sig;
- logic [56:0] rhs_sig;
- logic [56:0] result_sig;
- logic [56:0] larger_sig;
- logic [56:0] smaller_sig;
- logic signed [12:0] larger_exp;
- logic signs_match;
- int exp_diff;
-
- flags = '0;
- lhs_sign = lhs[63];
- rhs_sign = rhs[63] ^ subtract;
- lhs_exp = lhs[62:52];
- rhs_exp = rhs[62:52];
- lhs_frac = lhs[51:0];
- rhs_frac = rhs[51:0];
- lhs_is_zero = (lhs[62:0] == '0);
- rhs_is_zero = (rhs[62:0] == '0);
- lhs_is_inf = (&lhs_exp) && (lhs_frac == '0);
- rhs_is_inf = (&rhs_exp) && (rhs_frac == '0);
- signs_match = lhs_sign == rhs_sign;
-
- if (is_nan_d(lhs) || is_nan_d(rhs)) begin
- flags[4] = is_snan_d(lhs) || is_snan_d(rhs);
- return CANONICAL_NAN_D;
- end
-
- if (lhs_is_inf || rhs_is_inf) begin
- if (lhs_is_inf && rhs_is_inf && !signs_match) begin
- flags[4] = 1'b1;
- return CANONICAL_NAN_D;
- end
- return lhs_is_inf ? {lhs_sign, 11'h7FF, 52'b0} : {rhs_sign, 11'h7FF, 52'b0};
- end
-
- if (lhs_is_zero && rhs_is_zero) begin
- result_sign = signs_match ? lhs_sign : (effective_rm(round_mode) == 3'b010);
- return {result_sign, 63'b0};
- end
- if (lhs_is_zero) begin
- return {rhs_sign, rhs[62:0]};
- end
- if (rhs_is_zero) begin
- return lhs;
- end
-
- lhs_unbiased_exp = (lhs_exp == '0) ? -13'sd1022 : ($signed({2'b0, lhs_exp}) - 13'sd1023);
- rhs_unbiased_exp = (rhs_exp == '0) ? -13'sd1022 : ($signed({2'b0, rhs_exp}) - 13'sd1023);
- lhs_sig = {1'b0, (lhs_exp == '0) ? 1'b0 : 1'b1, lhs_frac, 3'b000};
- rhs_sig = {1'b0, (rhs_exp == '0) ? 1'b0 : 1'b1, rhs_frac, 3'b000};
-
- if ((lhs_unbiased_exp > rhs_unbiased_exp) ||
- ((lhs_unbiased_exp == rhs_unbiased_exp) && (lhs_sig >= rhs_sig))) begin
- exp_diff = int'(lhs_unbiased_exp) - int'(rhs_unbiased_exp);
- larger_sig = lhs_sig;
- smaller_sig = shift_right_jam_57(rhs_sig, exp_diff);
- larger_exp = lhs_unbiased_exp;
- result_sign = lhs_sign;
- end else begin
- exp_diff = int'(rhs_unbiased_exp) - int'(lhs_unbiased_exp);
- larger_sig = rhs_sig;
- smaller_sig = shift_right_jam_57(lhs_sig, exp_diff);
- larger_exp = rhs_unbiased_exp;
- result_sign = rhs_sign;
- end
-
- result_unbiased_exp = larger_exp;
- if (signs_match) begin
- result_sig = larger_sig + smaller_sig;
- if (result_sig[56]) begin
- result_sig = shift_right_jam_57(result_sig, 1);
- result_unbiased_exp = result_unbiased_exp + 13'sd1;
- end
- end else begin
- result_sig = larger_sig - smaller_sig;
- if (result_sig == '0) begin
- result_sign = effective_rm(round_mode) == 3'b010;
- return {result_sign, 63'b0};
- end
- while (!result_sig[55] && (result_unbiased_exp > -13'sd1022)) begin
- result_sig = result_sig << 1;
- result_unbiased_exp = result_unbiased_exp - 13'sd1;
- end
- end
-
- return round_pack_d(result_sign, result_unbiased_exp, result_sig, 1'b0, round_mode, flags);
- endfunction
-
- function automatic logic [63:0] fp_mul_d(
- input logic [63:0] lhs,
- input logic [63:0] rhs,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic result_sign;
- logic [10:0] lhs_exp;
- logic [10:0] rhs_exp;
- logic [51:0] lhs_frac;
- logic [51:0] rhs_frac;
- logic lhs_is_zero;
- logic rhs_is_zero;
- logic lhs_is_inf;
- logic rhs_is_inf;
- logic signed [12:0] lhs_unbiased_exp;
- logic signed [12:0] rhs_unbiased_exp;
- logic signed [12:0] result_unbiased_exp;
- logic [52:0] lhs_sig;
- logic [52:0] rhs_sig;
- logic [105:0] product;
- logic [56:0] result_sig;
- int lhs_msb;
- int rhs_msb;
-
- flags = '0;
- result_sign = lhs[63] ^ rhs[63];
- lhs_exp = lhs[62:52];
- rhs_exp = rhs[62:52];
- lhs_frac = lhs[51:0];
- rhs_frac = rhs[51:0];
- lhs_is_zero = (lhs[62:0] == '0);
- rhs_is_zero = (rhs[62:0] == '0);
- lhs_is_inf = (&lhs_exp) && (lhs_frac == '0);
- rhs_is_inf = (&rhs_exp) && (rhs_frac == '0);
-
- if (is_nan_d(lhs) || is_nan_d(rhs)) begin
- flags[4] = is_snan_d(lhs) || is_snan_d(rhs);
- return CANONICAL_NAN_D;
- end
-
- if ((lhs_is_inf && rhs_is_zero) || (rhs_is_inf && lhs_is_zero)) begin
- flags[4] = 1'b1;
- return CANONICAL_NAN_D;
- end
-
- if (lhs_is_inf || rhs_is_inf) begin
- return {result_sign, 11'h7FF, 52'b0};
- end
-
- if (lhs_is_zero || rhs_is_zero) begin
- return {result_sign, 63'b0};
- end
-
- if (lhs_exp == '0) begin
- lhs_msb = highest_bit_53({1'b0, lhs_frac});
- lhs_unbiased_exp = 13'(lhs_msb - 1074);
- lhs_sig = {1'b0, lhs_frac} << (52 - lhs_msb);
- end else begin
- lhs_unbiased_exp = $signed({2'b0, lhs_exp}) - 13'sd1023;
- lhs_sig = {1'b1, lhs_frac};
- end
-
- if (rhs_exp == '0) begin
- rhs_msb = highest_bit_53({1'b0, rhs_frac});
- rhs_unbiased_exp = 13'(rhs_msb - 1074);
- rhs_sig = {1'b0, rhs_frac} << (52 - rhs_msb);
- end else begin
- rhs_unbiased_exp = $signed({2'b0, rhs_exp}) - 13'sd1023;
- rhs_sig = {1'b1, rhs_frac};
- end
-
- product = lhs_sig * rhs_sig;
- if (product[105]) begin
- result_unbiased_exp = lhs_unbiased_exp + rhs_unbiased_exp + 13'sd1;
- result_sig = shift_right_jam_128_to_57({22'b0, product}, 50);
- end else begin
- result_unbiased_exp = lhs_unbiased_exp + rhs_unbiased_exp;
- result_sig = shift_right_jam_128_to_57({22'b0, product}, 49);
- end
-
- return round_pack_d(result_sign, result_unbiased_exp, result_sig, 1'b0, round_mode, flags);
- endfunction
-
- function automatic logic [31:0] fp_mul_s(
- input logic [31:0] lhs,
- input logic [31:0] rhs,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic result_sign;
- logic [7:0] lhs_exp;
- logic [7:0] rhs_exp;
- logic [22:0] lhs_frac;
- logic [22:0] rhs_frac;
- logic lhs_is_zero;
- logic rhs_is_zero;
- logic lhs_is_inf;
- logic rhs_is_inf;
- logic signed [10:0] lhs_unbiased_exp;
- logic signed [10:0] rhs_unbiased_exp;
- logic signed [10:0] result_unbiased_exp;
- logic [23:0] lhs_sig;
- logic [23:0] rhs_sig;
- logic [47:0] product;
- logic [27:0] result_sig;
- int lhs_msb;
- int rhs_msb;
-
- flags = '0;
- result_sign = lhs[31] ^ rhs[31];
- lhs_exp = lhs[30:23];
- rhs_exp = rhs[30:23];
- lhs_frac = lhs[22:0];
- rhs_frac = rhs[22:0];
- lhs_is_zero = (lhs[30:0] == '0);
- rhs_is_zero = (rhs[30:0] == '0);
- lhs_is_inf = (&lhs_exp) && (lhs_frac == '0);
- rhs_is_inf = (&rhs_exp) && (rhs_frac == '0);
-
- if (is_nan_s(lhs) || is_nan_s(rhs)) begin
- flags[4] = is_snan_s(lhs) || is_snan_s(rhs);
- return CANONICAL_NAN_S;
- end
-
- if ((lhs_is_inf && rhs_is_zero) || (rhs_is_inf && lhs_is_zero)) begin
- flags[4] = 1'b1;
- return CANONICAL_NAN_S;
- end
-
- if (lhs_is_inf || rhs_is_inf) begin
- return {result_sign, 8'hFF, 23'b0};
- end
-
- if (lhs_is_zero || rhs_is_zero) begin
- return {result_sign, 31'b0};
- end
-
- if (lhs_exp == '0) begin
- lhs_msb = highest_bit_64({41'b0, lhs_frac});
- lhs_unbiased_exp = 11'(lhs_msb - 149);
- lhs_sig = {1'b0, lhs_frac} << (23 - lhs_msb);
- end else begin
- lhs_unbiased_exp = $signed({3'b0, lhs_exp}) - 11'sd127;
- lhs_sig = {1'b1, lhs_frac};
- end
-
- if (rhs_exp == '0) begin
- rhs_msb = highest_bit_64({41'b0, rhs_frac});
- rhs_unbiased_exp = 11'(rhs_msb - 149);
- rhs_sig = {1'b0, rhs_frac} << (23 - rhs_msb);
- end else begin
- rhs_unbiased_exp = $signed({3'b0, rhs_exp}) - 11'sd127;
- rhs_sig = {1'b1, rhs_frac};
- end
-
- product = lhs_sig * rhs_sig;
- if (product[47]) begin
- result_unbiased_exp = lhs_unbiased_exp + rhs_unbiased_exp + 11'sd1;
- result_sig = shift_right_jam_48(product, 21);
- end else begin
- result_unbiased_exp = lhs_unbiased_exp + rhs_unbiased_exp;
- result_sig = shift_right_jam_48(product, 20);
- end
-
- return round_pack_s(result_sign, result_unbiased_exp, result_sig, 1'b0, round_mode, flags);
- endfunction
-
- function automatic logic [31:0] fp_div_s(
- input logic [31:0] lhs,
- input logic [31:0] rhs,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic result_sign;
- logic [7:0] lhs_exp;
- logic [7:0] rhs_exp;
- logic [22:0] lhs_frac;
- logic [22:0] rhs_frac;
- logic lhs_is_zero;
- logic rhs_is_zero;
- logic lhs_is_inf;
- logic rhs_is_inf;
- logic signed [10:0] lhs_unbiased_exp;
- logic signed [10:0] rhs_unbiased_exp;
- logic signed [10:0] result_unbiased_exp;
- logic [23:0] lhs_sig;
- logic [23:0] rhs_sig;
- logic [63:0] dividend;
- logic [63:0] quotient;
- logic [23:0] remainder;
- logic [27:0] result_sig;
- int lhs_msb;
- int rhs_msb;
-
- flags = '0;
- result_sign = lhs[31] ^ rhs[31];
- lhs_exp = lhs[30:23];
- rhs_exp = rhs[30:23];
- lhs_frac = lhs[22:0];
- rhs_frac = rhs[22:0];
- lhs_is_zero = (lhs[30:0] == '0);
- rhs_is_zero = (rhs[30:0] == '0);
- lhs_is_inf = (&lhs_exp) && (lhs_frac == '0);
- rhs_is_inf = (&rhs_exp) && (rhs_frac == '0);
-
- if (is_nan_s(lhs) || is_nan_s(rhs)) begin
- flags[4] = is_snan_s(lhs) || is_snan_s(rhs);
- return CANONICAL_NAN_S;
- end
-
- if ((lhs_is_zero && rhs_is_zero) || (lhs_is_inf && rhs_is_inf)) begin
- flags[4] = 1'b1;
- return CANONICAL_NAN_S;
- end
-
- if (lhs_is_inf || rhs_is_zero) begin
- if (rhs_is_zero && !lhs_is_zero && !lhs_is_inf) begin
- flags[3] = 1'b1;
- end
- return {result_sign, 8'hFF, 23'b0};
- end
-
- if (lhs_is_zero || rhs_is_inf) begin
- return {result_sign, 31'b0};
- end
-
- if (lhs_exp == '0) begin
- lhs_msb = highest_bit_64({41'b0, lhs_frac});
- lhs_unbiased_exp = 11'(lhs_msb - 149);
- lhs_sig = {1'b0, lhs_frac} << (23 - lhs_msb);
- end else begin
- lhs_unbiased_exp = $signed({3'b0, lhs_exp}) - 11'sd127;
- lhs_sig = {1'b1, lhs_frac};
- end
-
- if (rhs_exp == '0) begin
- rhs_msb = highest_bit_64({41'b0, rhs_frac});
- rhs_unbiased_exp = 11'(rhs_msb - 149);
- rhs_sig = {1'b0, rhs_frac} << (23 - rhs_msb);
- end else begin
- rhs_unbiased_exp = $signed({3'b0, rhs_exp}) - 11'sd127;
- rhs_sig = {1'b1, rhs_frac};
- end
-
- if (lhs_sig >= rhs_sig) begin
- result_unbiased_exp = lhs_unbiased_exp - rhs_unbiased_exp;
- dividend = {40'b0, lhs_sig} << 26;
- end else begin
- result_unbiased_exp = lhs_unbiased_exp - rhs_unbiased_exp - 11'sd1;
- dividend = {40'b0, lhs_sig} << 27;
- end
-
- quotient = dividend / {40'b0, rhs_sig};
- remainder = 24'(dividend % {40'b0, rhs_sig});
- result_sig = 28'(quotient);
- if (remainder != '0) begin
- result_sig[0] = 1'b1;
- end
-
- return round_pack_s(result_sign, result_unbiased_exp, result_sig, 1'b0, round_mode, flags);
- endfunction
-
- function automatic logic [63:0] fp_div_d(
- input logic [63:0] lhs,
- input logic [63:0] rhs,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic result_sign;
- logic [10:0] lhs_exp;
- logic [10:0] rhs_exp;
- logic [51:0] lhs_frac;
- logic [51:0] rhs_frac;
- logic lhs_is_zero;
- logic rhs_is_zero;
- logic lhs_is_inf;
- logic rhs_is_inf;
- logic signed [12:0] lhs_unbiased_exp;
- logic signed [12:0] rhs_unbiased_exp;
- logic signed [12:0] result_unbiased_exp;
- logic [52:0] lhs_sig;
- logic [52:0] rhs_sig;
- logic [127:0] dividend;
- logic [127:0] quotient;
- logic [52:0] remainder;
- logic [56:0] result_sig;
- int lhs_msb;
- int rhs_msb;
-
- flags = '0;
- result_sign = lhs[63] ^ rhs[63];
- lhs_exp = lhs[62:52];
- rhs_exp = rhs[62:52];
- lhs_frac = lhs[51:0];
- rhs_frac = rhs[51:0];
- lhs_is_zero = (lhs[62:0] == '0);
- rhs_is_zero = (rhs[62:0] == '0);
- lhs_is_inf = (&lhs_exp) && (lhs_frac == '0);
- rhs_is_inf = (&rhs_exp) && (rhs_frac == '0);
-
- if (is_nan_d(lhs) || is_nan_d(rhs)) begin
- flags[4] = is_snan_d(lhs) || is_snan_d(rhs);
- return CANONICAL_NAN_D;
- end
-
- if ((lhs_is_zero && rhs_is_zero) || (lhs_is_inf && rhs_is_inf)) begin
- flags[4] = 1'b1;
- return CANONICAL_NAN_D;
- end
-
- if (lhs_is_inf || rhs_is_zero) begin
- if (rhs_is_zero && !lhs_is_zero && !lhs_is_inf) begin
- flags[3] = 1'b1;
- end
- return {result_sign, 11'h7FF, 52'b0};
- end
-
- if (lhs_is_zero || rhs_is_inf) begin
- return {result_sign, 63'b0};
- end
-
- if (lhs_exp == '0) begin
- lhs_msb = highest_bit_53({1'b0, lhs_frac});
- lhs_unbiased_exp = 13'(lhs_msb - 1074);
- lhs_sig = {1'b0, lhs_frac} << (52 - lhs_msb);
- end else begin
- lhs_unbiased_exp = $signed({2'b0, lhs_exp}) - 13'sd1023;
- lhs_sig = {1'b1, lhs_frac};
- end
-
- if (rhs_exp == '0) begin
- rhs_msb = highest_bit_53({1'b0, rhs_frac});
- rhs_unbiased_exp = 13'(rhs_msb - 1074);
- rhs_sig = {1'b0, rhs_frac} << (52 - rhs_msb);
- end else begin
- rhs_unbiased_exp = $signed({2'b0, rhs_exp}) - 13'sd1023;
- rhs_sig = {1'b1, rhs_frac};
- end
-
- if (lhs_sig >= rhs_sig) begin
- result_unbiased_exp = lhs_unbiased_exp - rhs_unbiased_exp;
- dividend = {75'b0, lhs_sig} << 55;
- end else begin
- result_unbiased_exp = lhs_unbiased_exp - rhs_unbiased_exp - 13'sd1;
- dividend = {75'b0, lhs_sig} << 56;
- end
-
- quotient = dividend / {75'b0, rhs_sig};
- remainder = 53'(dividend % {75'b0, rhs_sig});
- result_sig = 57'(quotient);
- if (remainder != '0) begin
- result_sig[0] = 1'b1;
- end
-
- return round_pack_d(result_sign, result_unbiased_exp, result_sig, 1'b0, round_mode, flags);
- endfunction
-
- function automatic logic [31:0] fp_sqrt_s(
- input logic [31:0] value,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic sign;
- logic [7:0] exp;
- logic [22:0] frac;
- logic signed [10:0] unbiased_exp;
- logic signed [10:0] result_unbiased_exp;
- logic [23:0] sig;
- logic [63:0] radicand;
- logic [63:0] trial;
- logic [63:0] root;
- logic [63:0] remainder;
- logic [27:0] result_sig;
- int sig_msb;
-
- flags = '0;
- sign = value[31];
- exp = value[30:23];
- frac = value[22:0];
-
- if (is_nan_s(value)) begin
- flags[4] = is_snan_s(value);
- return CANONICAL_NAN_S;
- end
-
- if ((&exp) && (frac == '0)) begin
- if (sign) begin
- flags[4] = 1'b1;
- return CANONICAL_NAN_S;
- end
- return value;
- end
-
- if (value[30:0] == '0) begin
- return value;
- end
-
- if (sign) begin
- flags[4] = 1'b1;
- return CANONICAL_NAN_S;
- end
-
- if (exp == '0) begin
- sig_msb = highest_bit_64({41'b0, frac});
- unbiased_exp = 11'(sig_msb - 149);
- sig = {1'b0, frac} << (23 - sig_msb);
- end else begin
- unbiased_exp = $signed({3'b0, exp}) - 11'sd127;
- sig = {1'b1, frac};
- end
-
- if (unbiased_exp[0]) begin
- radicand = {39'b0, sig, 1'b0} << 29;
- result_unbiased_exp = (unbiased_exp - 11'sd1) >>> 1;
- end else begin
- radicand = {40'b0, sig} << 29;
- result_unbiased_exp = unbiased_exp >>> 1;
- end
-
- root = '0;
- for (int bit_idx = 26; bit_idx >= 0; bit_idx--) begin
- trial = root | (64'd1 << bit_idx);
- if ((trial * trial) <= radicand) begin
- root = trial;
- end
- end
-
- remainder = radicand - (root * root);
- result_sig = 28'(root);
- if (remainder != '0) begin
- result_sig[0] = 1'b1;
- end
-
- return round_pack_s(1'b0, result_unbiased_exp, result_sig, 1'b0, round_mode, flags);
- endfunction
-
- function automatic logic [63:0] fp_sqrt_d(
- input logic [63:0] value,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic sign;
- logic [10:0] exp;
- logic [51:0] frac;
- logic signed [12:0] unbiased_exp;
- logic signed [12:0] result_unbiased_exp;
- logic [52:0] sig;
- logic [127:0] radicand;
- logic [127:0] trial;
- logic [127:0] root;
- logic [127:0] remainder;
- logic [56:0] result_sig;
- int sig_msb;
-
- flags = '0;
- sign = value[63];
- exp = value[62:52];
- frac = value[51:0];
-
- if (is_nan_d(value)) begin
- flags[4] = is_snan_d(value);
- return CANONICAL_NAN_D;
- end
-
- if ((&exp) && (frac == '0)) begin
- if (sign) begin
- flags[4] = 1'b1;
- return CANONICAL_NAN_D;
- end
- return value;
- end
-
- if (value[62:0] == '0) begin
- return value;
- end
-
- if (sign) begin
- flags[4] = 1'b1;
- return CANONICAL_NAN_D;
- end
-
- if (exp == '0) begin
- sig_msb = highest_bit_53({1'b0, frac});
- unbiased_exp = 13'(sig_msb - 1074);
- sig = {1'b0, frac} << (52 - sig_msb);
- end else begin
- unbiased_exp = $signed({2'b0, exp}) - 13'sd1023;
- sig = {1'b1, frac};
- end
-
- if (unbiased_exp[0]) begin
- radicand = {74'b0, sig, 1'b0} << 58;
- result_unbiased_exp = (unbiased_exp - 13'sd1) >>> 1;
- end else begin
- radicand = {75'b0, sig} << 58;
- result_unbiased_exp = unbiased_exp >>> 1;
- end
-
- root = '0;
- for (int bit_idx = 55; bit_idx >= 0; bit_idx--) begin
- trial = root | (128'd1 << bit_idx);
- if ((trial * trial) <= radicand) begin
- root = trial;
- end
- end
-
- remainder = radicand - (root * root);
- result_sig = 57'(root);
- if (remainder != '0) begin
- result_sig[0] = 1'b1;
- end
-
- return round_pack_d(1'b0, result_unbiased_exp, result_sig, 1'b0, round_mode, flags);
- endfunction
-
- function automatic logic [31:0] fp_fma_s(
- input logic [31:0] mul_lhs,
- input logic [31:0] mul_rhs,
- input logic [31:0] addend,
- input logic negate_product,
- input logic negate_addend,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic lhs_sign;
- logic rhs_sign;
- logic addend_sign;
- logic product_sign;
- logic result_sign;
- logic [7:0] lhs_exp;
- logic [7:0] rhs_exp;
- logic [7:0] addend_exp;
- logic [22:0] lhs_frac;
- logic [22:0] rhs_frac;
- logic [22:0] addend_frac;
- logic lhs_is_zero;
- logic rhs_is_zero;
- logic addend_is_zero;
- logic lhs_is_inf;
- logic rhs_is_inf;
- logic addend_is_inf;
- logic invalid_multiply;
- logic signed [10:0] lhs_unbiased_exp;
- logic signed [10:0] rhs_unbiased_exp;
- logic signed [10:0] addend_unbiased_exp;
- logic signed [10:0] product_unbiased_exp;
- logic signed [10:0] common_unbiased_exp;
- logic signed [10:0] result_unbiased_exp;
- logic [23:0] lhs_sig;
- logic [23:0] rhs_sig;
- logic [23:0] addend_sig;
- logic [47:0] product;
- logic [47:0] normalized_product;
- logic [64:0] product_ext;
- logic [64:0] addend_ext;
- logic [64:0] aligned_product;
- logic [64:0] aligned_addend;
- logic [64:0] result_ext;
- logic [64:0] rounded_source;
- logic [27:0] result_sig;
- int lhs_msb;
- int rhs_msb;
- int addend_msb;
- int exp_diff;
-
- flags = '0;
- lhs_sign = mul_lhs[31];
- rhs_sign = mul_rhs[31];
- addend_sign = addend[31] ^ negate_addend;
- product_sign = lhs_sign ^ rhs_sign ^ negate_product;
- lhs_exp = mul_lhs[30:23];
- rhs_exp = mul_rhs[30:23];
- addend_exp = addend[30:23];
- lhs_frac = mul_lhs[22:0];
- rhs_frac = mul_rhs[22:0];
- addend_frac = addend[22:0];
- lhs_is_zero = (mul_lhs[30:0] == '0);
- rhs_is_zero = (mul_rhs[30:0] == '0);
- addend_is_zero = (addend[30:0] == '0);
- lhs_is_inf = (&lhs_exp) && (lhs_frac == '0);
- rhs_is_inf = (&rhs_exp) && (rhs_frac == '0);
- addend_is_inf = (&addend_exp) && (addend_frac == '0);
- invalid_multiply = (lhs_is_inf && rhs_is_zero) || (rhs_is_inf && lhs_is_zero);
-
- if (is_nan_s(mul_lhs) || is_nan_s(mul_rhs) || is_nan_s(addend) || invalid_multiply) begin
- flags[4] = invalid_multiply || is_snan_s(mul_lhs) || is_snan_s(mul_rhs) || is_snan_s(addend);
- return CANONICAL_NAN_S;
- end
-
- if (lhs_is_inf || rhs_is_inf) begin
- if (addend_is_inf && (product_sign != addend_sign)) begin
- flags[4] = 1'b1;
- return CANONICAL_NAN_S;
- end
- return {product_sign, 8'hFF, 23'b0};
- end
-
- if (addend_is_inf) begin
- return {addend_sign, 8'hFF, 23'b0};
- end
-
- if (lhs_is_zero || rhs_is_zero) begin
- if (addend_is_zero) begin
- result_sign = (product_sign == addend_sign) ? product_sign : (effective_rm(round_mode) == 3'b010);
- return {result_sign, 31'b0};
- end
- return {addend_sign, addend[30:0]};
- end
-
- if (addend_is_zero) begin
- return fp_mul_s({mul_lhs[31] ^ negate_product, mul_lhs[30:0]}, mul_rhs, round_mode, flags);
- end
-
- if (lhs_exp == '0) begin
- lhs_msb = highest_bit_64({41'b0, lhs_frac});
- lhs_unbiased_exp = 11'(lhs_msb - 149);
- lhs_sig = {1'b0, lhs_frac} << (23 - lhs_msb);
- end else begin
- lhs_unbiased_exp = $signed({3'b0, lhs_exp}) - 11'sd127;
- lhs_sig = {1'b1, lhs_frac};
- end
-
- if (rhs_exp == '0) begin
- rhs_msb = highest_bit_64({41'b0, rhs_frac});
- rhs_unbiased_exp = 11'(rhs_msb - 149);
- rhs_sig = {1'b0, rhs_frac} << (23 - rhs_msb);
- end else begin
- rhs_unbiased_exp = $signed({3'b0, rhs_exp}) - 11'sd127;
- rhs_sig = {1'b1, rhs_frac};
- end
-
- if (addend_exp == '0) begin
- addend_msb = highest_bit_64({41'b0, addend_frac});
- addend_unbiased_exp = 11'(addend_msb - 149);
- addend_sig = {1'b0, addend_frac} << (23 - addend_msb);
- end else begin
- addend_unbiased_exp = $signed({3'b0, addend_exp}) - 11'sd127;
- addend_sig = {1'b1, addend_frac};
- end
-
- product = lhs_sig * rhs_sig;
- if (product[47]) begin
- product_unbiased_exp = lhs_unbiased_exp + rhs_unbiased_exp + 11'sd1;
- normalized_product = product;
- end else begin
- product_unbiased_exp = lhs_unbiased_exp + rhs_unbiased_exp;
- normalized_product = product << 1;
- end
-
- product_ext = {4'b0, normalized_product, 13'b0};
- addend_ext = {4'b0, addend_sig, 37'b0};
-
- if (product_unbiased_exp >= addend_unbiased_exp) begin
- common_unbiased_exp = product_unbiased_exp;
- exp_diff = int'(product_unbiased_exp) - int'(addend_unbiased_exp);
- aligned_product = product_ext;
- aligned_addend = shift_right_jam_65(addend_ext, exp_diff);
- end else begin
- common_unbiased_exp = addend_unbiased_exp;
- exp_diff = int'(addend_unbiased_exp) - int'(product_unbiased_exp);
- aligned_product = shift_right_jam_65(product_ext, exp_diff);
- aligned_addend = addend_ext;
- end
-
- result_unbiased_exp = common_unbiased_exp;
- if (product_sign == addend_sign) begin
- result_ext = aligned_product + aligned_addend;
- result_sign = product_sign;
- if (result_ext[61]) begin
- result_ext = shift_right_jam_65(result_ext, 1);
- result_unbiased_exp = result_unbiased_exp + 11'sd1;
- end
- end else if (aligned_product >= aligned_addend) begin
- result_ext = aligned_product - aligned_addend;
- result_sign = product_sign;
- end else begin
- result_ext = aligned_addend - aligned_product;
- result_sign = addend_sign;
- end
-
- if (result_ext == '0) begin
- result_sign = effective_rm(round_mode) == 3'b010;
- return {result_sign, 31'b0};
- end
-
- while (!result_ext[60] && (result_unbiased_exp > -11'sd126)) begin
- result_ext = result_ext << 1;
- result_unbiased_exp = result_unbiased_exp - 11'sd1;
- end
-
- rounded_source = shift_right_jam_65(result_ext, 34);
- result_sig = rounded_source[27:0];
- return round_pack_s(result_sign, result_unbiased_exp, result_sig, 1'b0, round_mode, flags);
- endfunction
-
- function automatic logic [63:0] fp_fma_d(
- input logic [63:0] mul_lhs,
- input logic [63:0] mul_rhs,
- input logic [63:0] addend,
- input logic negate_product,
- input logic negate_addend,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic lhs_sign;
- logic rhs_sign;
- logic addend_sign;
- logic product_sign;
- logic result_sign;
- logic [10:0] lhs_exp;
- logic [10:0] rhs_exp;
- logic [10:0] addend_exp;
- logic [51:0] lhs_frac;
- logic [51:0] rhs_frac;
- logic [51:0] addend_frac;
- logic lhs_is_zero;
- logic rhs_is_zero;
- logic addend_is_zero;
- logic lhs_is_inf;
- logic rhs_is_inf;
- logic addend_is_inf;
- logic invalid_multiply;
- logic signed [12:0] lhs_unbiased_exp;
- logic signed [12:0] rhs_unbiased_exp;
- logic signed [12:0] addend_unbiased_exp;
- logic signed [12:0] product_unbiased_exp;
- logic signed [12:0] common_unbiased_exp;
- logic signed [12:0] result_unbiased_exp;
- logic [52:0] lhs_sig;
- logic [52:0] rhs_sig;
- logic [52:0] addend_sig;
- logic [105:0] product;
- logic [105:0] normalized_product;
- logic [127:0] product_ext;
- logic [127:0] addend_ext;
- logic [127:0] aligned_product;
- logic [127:0] aligned_addend;
- logic [127:0] result_ext;
- logic [127:0] rounded_source;
- logic [56:0] result_sig;
- int lhs_msb;
- int rhs_msb;
- int addend_msb;
- int exp_diff;
-
- flags = '0;
- lhs_sign = mul_lhs[63];
- rhs_sign = mul_rhs[63];
- addend_sign = addend[63] ^ negate_addend;
- product_sign = lhs_sign ^ rhs_sign ^ negate_product;
- lhs_exp = mul_lhs[62:52];
- rhs_exp = mul_rhs[62:52];
- addend_exp = addend[62:52];
- lhs_frac = mul_lhs[51:0];
- rhs_frac = mul_rhs[51:0];
- addend_frac = addend[51:0];
- lhs_is_zero = (mul_lhs[62:0] == '0);
- rhs_is_zero = (mul_rhs[62:0] == '0);
- addend_is_zero = (addend[62:0] == '0);
- lhs_is_inf = (&lhs_exp) && (lhs_frac == '0);
- rhs_is_inf = (&rhs_exp) && (rhs_frac == '0);
- addend_is_inf = (&addend_exp) && (addend_frac == '0);
- invalid_multiply = (lhs_is_inf && rhs_is_zero) || (rhs_is_inf && lhs_is_zero);
-
- if (is_nan_d(mul_lhs) || is_nan_d(mul_rhs) || is_nan_d(addend) || invalid_multiply) begin
- flags[4] = invalid_multiply || is_snan_d(mul_lhs) || is_snan_d(mul_rhs) || is_snan_d(addend);
- return CANONICAL_NAN_D;
- end
-
- if (lhs_is_inf || rhs_is_inf) begin
- if (addend_is_inf && (product_sign != addend_sign)) begin
- flags[4] = 1'b1;
- return CANONICAL_NAN_D;
- end
- return {product_sign, 11'h7FF, 52'b0};
- end
-
- if (addend_is_inf) begin
- return {addend_sign, 11'h7FF, 52'b0};
- end
-
- if (lhs_is_zero || rhs_is_zero) begin
- if (addend_is_zero) begin
- result_sign = (product_sign == addend_sign) ? product_sign : (effective_rm(round_mode) == 3'b010);
- return {result_sign, 63'b0};
- end
- return {addend_sign, addend[62:0]};
- end
-
- if (addend_is_zero) begin
- return fp_mul_d({mul_lhs[63] ^ negate_product, mul_lhs[62:0]}, mul_rhs, round_mode, flags);
- end
-
- if (lhs_exp == '0) begin
- lhs_msb = highest_bit_53({1'b0, lhs_frac});
- lhs_unbiased_exp = 13'(lhs_msb - 1074);
- lhs_sig = {1'b0, lhs_frac} << (52 - lhs_msb);
- end else begin
- lhs_unbiased_exp = $signed({2'b0, lhs_exp}) - 13'sd1023;
- lhs_sig = {1'b1, lhs_frac};
- end
-
- if (rhs_exp == '0) begin
- rhs_msb = highest_bit_53({1'b0, rhs_frac});
- rhs_unbiased_exp = 13'(rhs_msb - 1074);
- rhs_sig = {1'b0, rhs_frac} << (52 - rhs_msb);
- end else begin
- rhs_unbiased_exp = $signed({2'b0, rhs_exp}) - 13'sd1023;
- rhs_sig = {1'b1, rhs_frac};
- end
-
- if (addend_exp == '0) begin
- addend_msb = highest_bit_53({1'b0, addend_frac});
- addend_unbiased_exp = 13'(addend_msb - 1074);
- addend_sig = {1'b0, addend_frac} << (52 - addend_msb);
- end else begin
- addend_unbiased_exp = $signed({2'b0, addend_exp}) - 13'sd1023;
- addend_sig = {1'b1, addend_frac};
- end
-
- product = lhs_sig * rhs_sig;
- if (product[105]) begin
- product_unbiased_exp = lhs_unbiased_exp + rhs_unbiased_exp + 13'sd1;
- normalized_product = product;
- end else begin
- product_unbiased_exp = lhs_unbiased_exp + rhs_unbiased_exp;
- normalized_product = product << 1;
- end
-
- product_ext = {9'b0, normalized_product, 13'b0};
- addend_ext = {9'b0, addend_sig, 66'b0};
-
- if (product_unbiased_exp >= addend_unbiased_exp) begin
- common_unbiased_exp = product_unbiased_exp;
- exp_diff = int'(product_unbiased_exp) - int'(addend_unbiased_exp);
- aligned_product = product_ext;
- aligned_addend = shift_right_jam_128(addend_ext, exp_diff);
- end else begin
- common_unbiased_exp = addend_unbiased_exp;
- exp_diff = int'(addend_unbiased_exp) - int'(product_unbiased_exp);
- aligned_product = shift_right_jam_128(product_ext, exp_diff);
- aligned_addend = addend_ext;
- end
-
- result_unbiased_exp = common_unbiased_exp;
- if (product_sign == addend_sign) begin
- result_ext = aligned_product + aligned_addend;
- result_sign = product_sign;
- if (result_ext[119]) begin
- result_ext = shift_right_jam_128(result_ext, 1);
- result_unbiased_exp = result_unbiased_exp + 13'sd1;
- end
- end else if (aligned_product >= aligned_addend) begin
- result_ext = aligned_product - aligned_addend;
- result_sign = product_sign;
- end else begin
- result_ext = aligned_addend - aligned_product;
- result_sign = addend_sign;
- end
-
- if (result_ext == '0) begin
- result_sign = effective_rm(round_mode) == 3'b010;
- return {result_sign, 63'b0};
- end
-
- while (!result_ext[118] && (result_unbiased_exp > -13'sd1022)) begin
- result_ext = result_ext << 1;
- result_unbiased_exp = result_unbiased_exp - 13'sd1;
- end
-
- rounded_source = shift_right_jam_128(result_ext, 63);
- result_sig = rounded_source[56:0];
- return round_pack_d(result_sign, result_unbiased_exp, result_sig, 1'b0, round_mode, flags);
- endfunction
-
- function automatic logic [63:0] pack_uint_to_s(
- input logic sign,
- input logic [63:0] magnitude,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- int msb_index;
- int shift;
- logic [127:0] quotient;
- logic [127:0] remainder;
- logic [127:0] divisor;
- logic [127:0] half;
- logic [24:0] rounded_sig;
- logic [7:0] exp_field;
- logic [31:0] result_s;
-
- flags = '0;
- if (magnitude == '0) begin
- return {32'hFFFF_FFFF, sign, 31'b0};
- end
-
- msb_index = highest_bit_64(magnitude);
- exp_field = 8'(msb_index + 127);
- if (msb_index <= 23) begin
- rounded_sig = {1'b0, magnitude[23:0] << (23 - msb_index)};
- end else begin
- shift = msb_index - 23;
- divisor = 128'd1 << shift;
- quotient = {64'b0, magnitude} >> shift;
- remainder = {64'b0, magnitude} & (divisor - 128'd1);
- half = divisor >> 1;
- rounded_sig = {1'b0, quotient[23:0]} +
- (round_increment(round_mode, sign, quotient, remainder, half) ? 25'd1 : 25'd0);
- if (remainder != '0) begin
- flags[0] = 1'b1;
- end
- if (rounded_sig[24]) begin
- rounded_sig = rounded_sig >> 1;
- exp_field = exp_field + 8'd1;
- end
- end
-
- result_s = {sign, exp_field, rounded_sig[22:0]};
- return {32'hFFFF_FFFF, result_s};
- endfunction
-
- function automatic logic [63:0] pack_uint_to_d(
- input logic sign,
- input logic [63:0] magnitude,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- int msb_index;
- int shift;
- logic [127:0] quotient;
- logic [127:0] remainder;
- logic [127:0] divisor;
- logic [127:0] half;
- logic [53:0] rounded_sig;
- logic [10:0] exp_field;
-
- flags = '0;
- if (magnitude == '0) begin
- return {sign, 63'b0};
- end
-
- msb_index = highest_bit_64(magnitude);
- exp_field = 11'(msb_index + 1023);
- if (msb_index <= 52) begin
- rounded_sig = {1'b0, magnitude[52:0] << (52 - msb_index)};
- end else begin
- shift = msb_index - 52;
- divisor = 128'd1 << shift;
- quotient = {64'b0, magnitude} >> shift;
- remainder = {64'b0, magnitude} & (divisor - 128'd1);
- half = divisor >> 1;
- rounded_sig = {1'b0, quotient[52:0]} +
- (round_increment(round_mode, sign, quotient, remainder, half) ? 54'd1 : 54'd0);
- if (remainder != '0) begin
- flags[0] = 1'b1;
- end
- if (rounded_sig[53]) begin
- rounded_sig = rounded_sig >> 1;
- exp_field = exp_field + 11'd1;
- end
- end
-
- return {sign, exp_field, rounded_sig[51:0]};
- endfunction
-
- function automatic logic [63:0] cvt_int_to_fp(
- input logic [63:0] int_value,
- input logic [1:0] int_fmt,
- input logic to_double,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic is_signed;
- logic is_long;
- logic sign;
- logic [63:0] source_value;
- logic [63:0] magnitude;
-
- is_signed = (int_fmt == 2'd0) || (int_fmt == 2'd2);
- is_long = (int_fmt == 2'd2) || (int_fmt == 2'd3);
- source_value = is_long ? int_value :
- (is_signed ? {{32{int_value[31]}}, int_value[31:0]} : {32'b0, int_value[31:0]});
- sign = is_signed && source_value[63];
- magnitude = sign ? ((~source_value) + 64'd1) : source_value;
-
- if (to_double) begin
- return pack_uint_to_d(sign, magnitude, round_mode, flags);
- end
-
- return pack_uint_to_s(sign, magnitude, round_mode, flags);
- endfunction
-
- function automatic logic [63:0] cvt_s_to_d(
- input logic [31:0] value,
- output logic [4:0] flags
- );
- logic sign;
- logic [7:0] exp;
- logic [22:0] frac;
- int frac_msb;
- logic [10:0] exp_d;
- logic [51:0] frac_d;
- logic [22:0] subnormal_tail_s;
-
- flags = '0;
- sign = value[31];
- exp = value[30:23];
- frac = value[22:0];
-
- if (is_nan_s(value)) begin
- flags[4] = is_snan_s(value);
- return CANONICAL_NAN_D;
- end
- if (&exp) begin
- return {sign, 11'h7FF, 52'b0};
- end
- if ((exp == '0) && (frac == '0)) begin
- return {sign, 63'b0};
- end
- if (exp == '0) begin
- frac_msb = -1;
- for (int bit_idx = 0; bit_idx < 23; bit_idx++) begin
- if (frac[bit_idx]) begin
- frac_msb = bit_idx;
- end
- end
- exp_d = 11'(frac_msb - 149 + 1023);
- subnormal_tail_s = frac ^ (23'(1) << frac_msb);
- frac_d = {29'b0, subnormal_tail_s} << (52 - frac_msb);
- return {sign, exp_d, frac_d};
- end
-
- exp_d = 11'(int'(exp) - 127 + 1023);
- frac_d = {frac, 29'b0};
- return {sign, exp_d, frac_d};
- endfunction
-
- function automatic logic [63:0] cvt_d_to_s(
- input logic [63:0] value,
- input logic [2:0] round_mode,
- output logic [4:0] flags
- );
- logic sign;
- logic [10:0] exp;
- logic [51:0] frac;
- logic [52:0] significand;
- logic signed [13:0] unbiased_exp;
- int frac_msb;
- int shift;
- logic [127:0] quotient;
- logic [127:0] remainder;
- logic [127:0] divisor;
- logic [127:0] half;
- logic [24:0] rounded_sig;
- logic [7:0] exp_s;
- logic [31:0] result_s;
-
- flags = '0;
- sign = value[63];
- exp = value[62:52];
- frac = value[51:0];
-
- if (is_nan_d(value)) begin
- flags[4] = is_snan_d(value);
- return {32'hFFFF_FFFF, CANONICAL_NAN_S};
- end
- if (&exp) begin
- return {32'hFFFF_FFFF, sign, 8'hFF, 23'b0};
- end
- if ((exp == '0) && (frac == '0)) begin
- return {32'hFFFF_FFFF, sign, 31'b0};
- end
-
- if (exp == '0) begin
- frac_msb = highest_bit_53({1'b0, frac});
- unbiased_exp = 14'(frac_msb - 1074);
- significand = {1'b0, frac} << (52 - frac_msb);
- end else begin
- unbiased_exp = $signed({3'b0, exp}) - 14'sd1023;
- significand = {1'b1, frac};
- end
-
- if (unbiased_exp > 14'sd127) begin
- flags[2] = 1'b1;
- flags[0] = 1'b1;
- return {32'hFFFF_FFFF, overflow_s_result(sign, round_mode)};
- end
-
- if (unbiased_exp >= -14'sd126) begin
- exp_s = 8'(unbiased_exp + 14'sd127);
- shift = 29;
- divisor = 128'd1 << shift;
- quotient = {75'b0, significand} >> shift;
- remainder = {75'b0, significand} & (divisor - 128'd1);
- half = divisor >> 1;
- rounded_sig = {1'b0, quotient[23:0]} +
- (round_increment(round_mode, sign, quotient, remainder, half) ? 25'd1 : 25'd0);
- if (remainder != '0) begin
- flags[0] = 1'b1;
- end
- if (rounded_sig[24]) begin
- rounded_sig = rounded_sig >> 1;
- exp_s = exp_s + 8'd1;
- if (exp_s == 8'hFF) begin
- flags[2] = 1'b1;
- flags[0] = 1'b1;
- return {32'hFFFF_FFFF, overflow_s_result(sign, round_mode)};
- end
- end
- result_s = {sign, exp_s, rounded_sig[22:0]};
- return {32'hFFFF_FFFF, result_s};
- end
-
- shift = 29 + ((-126) - int'(unbiased_exp));
- if (shift >= 128) begin
- quotient = '0;
- remainder = {75'b0, significand};
- rounded_sig = '0;
- if (remainder != '0) begin
- flags[1] = 1'b1;
- flags[0] = 1'b1;
- unique case (effective_rm(round_mode))
- 3'b010: rounded_sig = sign ? 25'd1 : 25'd0;
- 3'b011: rounded_sig = !sign ? 25'd1 : 25'd0;
- default: rounded_sig = '0;
- endcase
- end
- end else begin
- divisor = 128'd1 << shift;
- quotient = {75'b0, significand} >> shift;
- remainder = {75'b0, significand} & (divisor - 128'd1);
- half = divisor >> 1;
- rounded_sig = {1'b0, quotient[23:0]} +
- (round_increment(round_mode, sign, quotient, remainder, half) ? 25'd1 : 25'd0);
- if (remainder != '0) begin
- flags[1] = 1'b1;
- flags[0] = 1'b1;
- end
- end
-
- if (rounded_sig[23]) begin
- result_s = {sign, 8'd1, 23'b0};
- end else begin
- result_s = {sign, 8'b0, rounded_sig[22:0]};
- end
- return {32'hFFFF_FFFF, result_s};
- endfunction
-
- always_comb begin
- logic invalid_s;
- logic invalid_d;
- logic cmp_value;
- logic [31:0] result_s;
- logic [63:0] result_d;
- logic [63:0] result_int;
- logic [4:0] result_flags;
-
- fp_result = '0;
- int_result = '0;
- fflags = '0;
- illegal_instr = 1'b0;
- invalid_s = is_nan_s(s1) || is_nan_s(s2);
- invalid_d = is_nan_d(d1) || is_nan_d(d2);
- cmp_value = 1'b0;
- result_s = '0;
- result_d = '0;
- result_int = '0;
- result_flags = '0;
-
- unique case (fp_op)
- FP_OP_NONE: begin
- fp_result = '0;
- int_result = '0;
- fflags = '0;
- end
-
- FP_OP_ADD, FP_OP_SUB: begin
- if (fp_fmt == FP_FMT_S) begin
- result_s = fp_addsub_s(s1, s2, fp_op == FP_OP_SUB, rm, result_flags);
- fp_result = {32'hFFFF_FFFF, result_s};
- fflags = result_flags;
- end else begin
- result_d = fp_addsub_d(d1, d2, fp_op == FP_OP_SUB, rm, result_flags);
- fp_result = result_d;
- fflags = result_flags;
- end
- end
-
- FP_OP_MUL: begin
- if (fp_fmt == FP_FMT_S) begin
- result_s = fp_mul_s(s1, s2, rm, result_flags);
- fp_result = {32'hFFFF_FFFF, result_s};
- fflags = result_flags;
- end else begin
- result_d = fp_mul_d(d1, d2, rm, result_flags);
- fp_result = result_d;
- fflags = result_flags;
- end
- end
-
- FP_OP_DIV: begin
- if (fp_fmt == FP_FMT_S) begin
- result_s = fp_div_s(s1, s2, rm, result_flags);
- fp_result = {32'hFFFF_FFFF, result_s};
- fflags = result_flags;
- end else begin
- result_d = fp_div_d(d1, d2, rm, result_flags);
- fp_result = result_d;
- fflags = result_flags;
- end
- end
-
- FP_OP_SQRT: begin
- if (fp_fmt == FP_FMT_S) begin
- result_s = fp_sqrt_s(s1, rm, result_flags);
- fp_result = {32'hFFFF_FFFF, result_s};
- fflags = result_flags;
- end else begin
- result_d = fp_sqrt_d(d1, rm, result_flags);
- fp_result = result_d;
- fflags = result_flags;
- end
- end
-
- FP_OP_MADD, FP_OP_MSUB, FP_OP_NMSUB, FP_OP_NMADD: begin
- if (fp_fmt == FP_FMT_S) begin
- unique case (fp_op)
- FP_OP_MADD: result_s = fp_fma_s(s1, s2, s3, 1'b0, 1'b0, rm, result_flags);
- FP_OP_MSUB: result_s = fp_fma_s(s1, s2, s3, 1'b0, 1'b1, rm, result_flags);
- FP_OP_NMSUB: result_s = fp_fma_s(s1, s2, s3, 1'b1, 1'b0, rm, result_flags);
- default: result_s = fp_fma_s(s1, s2, s3, 1'b1, 1'b1, rm, result_flags);
- endcase
- fp_result = {32'hFFFF_FFFF, result_s};
- fflags = result_flags;
- end else begin
- unique case (fp_op)
- FP_OP_MADD: result_d = fp_fma_d(d1, d2, d3, 1'b0, 1'b0, rm, result_flags);
- FP_OP_MSUB: result_d = fp_fma_d(d1, d2, d3, 1'b0, 1'b1, rm, result_flags);
- FP_OP_NMSUB: result_d = fp_fma_d(d1, d2, d3, 1'b1, 1'b0, rm, result_flags);
- default: result_d = fp_fma_d(d1, d2, d3, 1'b1, 1'b1, rm, result_flags);
- endcase
- fp_result = result_d;
- fflags = result_flags;
- end
- end
-
- FP_OP_SGNJ, FP_OP_SGNJN, FP_OP_SGNJX: begin
- if (fp_fmt == FP_FMT_S) begin
- unique case (fp_op)
- FP_OP_SGNJ: fp_result = {32'hFFFF_FFFF, s2[31], s1[30:0]};
- FP_OP_SGNJN: fp_result = {32'hFFFF_FFFF, ~s2[31], s1[30:0]};
- default: fp_result = {32'hFFFF_FFFF, s1[31] ^ s2[31], s1[30:0]};
- endcase
- end else begin
- unique case (fp_op)
- FP_OP_SGNJ: fp_result = {d2[63], d1[62:0]};
- FP_OP_SGNJN: fp_result = {~d2[63], d1[62:0]};
- default: fp_result = {d1[63] ^ d2[63], d1[62:0]};
- endcase
- end
- end
-
- FP_OP_MV_X2F: begin
- fp_result = (fp_fmt == FP_FMT_S) ? {32'hFFFF_FFFF, int_rs1_data[31:0]} : int_rs1_data;
- end
-
- FP_OP_MV_F2X: begin
- int_result = (fp_fmt == FP_FMT_S) ? {{32{s1_raw[31]}}, s1_raw} : d1;
- end
-
- FP_OP_CLASS: begin
- int_result = (fp_fmt == FP_FMT_S) ? {54'b0, class_s(s1)} : {54'b0, class_d(d1)};
- end
-
- FP_OP_EQ, FP_OP_LT, FP_OP_LE: begin
- if (fp_fmt == FP_FMT_S) begin
- if (invalid_s) begin
- fflags[4] = is_snan_s(s1) || is_snan_s(s2) || (fp_op != FP_OP_EQ);
- cmp_value = 1'b0;
- end else begin
- cmp_value = (fp_op == FP_OP_EQ) ? equal_s(s1, s2) :
- (fp_op == FP_OP_LT) ? less_s(s1, s2) :
- (less_s(s1, s2) || equal_s(s1, s2));
- end
- end else begin
- if (invalid_d) begin
- fflags[4] = is_snan_d(d1) || is_snan_d(d2) || (fp_op != FP_OP_EQ);
- cmp_value = 1'b0;
- end else begin
- cmp_value = (fp_op == FP_OP_EQ) ? equal_d(d1, d2) :
- (fp_op == FP_OP_LT) ? less_d(d1, d2) :
- (less_d(d1, d2) || equal_d(d1, d2));
- end
- end
- int_result = {63'b0, cmp_value};
- end
-
- FP_OP_MIN, FP_OP_MAX: begin
- if (fp_fmt == FP_FMT_S) begin
- if (is_nan_s(s1) && is_nan_s(s2)) begin
- fp_result = {32'hFFFF_FFFF, CANONICAL_NAN_S};
- fflags[4] = is_snan_s(s1) || is_snan_s(s2);
- end else if (is_nan_s(s1)) begin
- fp_result = {32'hFFFF_FFFF, s2};
- fflags[4] = is_snan_s(s1);
- end else if (is_nan_s(s2)) begin
- fp_result = {32'hFFFF_FFFF, s1};
- fflags[4] = is_snan_s(s2);
- end else if ((s1[30:0] == '0) && (s2[30:0] == '0)) begin
- fp_result = {32'hFFFF_FFFF, (fp_op == FP_OP_MIN) ? {s1[31] | s2[31], 31'b0} :
- {s1[31] & s2[31], 31'b0}};
- end else if (fp_op == FP_OP_MIN) begin
- fp_result = {32'hFFFF_FFFF, less_s(s1, s2) ? s1 : s2};
- end else begin
- fp_result = {32'hFFFF_FFFF, less_s(s1, s2) ? s2 : s1};
- end
- end else begin
- if (is_nan_d(d1) && is_nan_d(d2)) begin
- fp_result = CANONICAL_NAN_D;
- fflags[4] = is_snan_d(d1) || is_snan_d(d2);
- end else if (is_nan_d(d1)) begin
- fp_result = d2;
- fflags[4] = is_snan_d(d1);
- end else if (is_nan_d(d2)) begin
- fp_result = d1;
- fflags[4] = is_snan_d(d2);
- end else if ((d1[62:0] == '0) && (d2[62:0] == '0)) begin
- fp_result = (fp_op == FP_OP_MIN) ? {d1[63] | d2[63], 63'b0} :
- {d1[63] & d2[63], 63'b0};
- end else if (fp_op == FP_OP_MIN) begin
- fp_result = less_d(d1, d2) ? d1 : d2;
- end else begin
- fp_result = less_d(d1, d2) ? d2 : d1;
- end
- end
- end
-
- FP_OP_CVT_F2I: begin
- if (fp_fmt == FP_FMT_S) begin
- result_int = cvt_s_to_int(s1, rs2_addr[1:0], rm, result_flags);
- end else begin
- result_int = cvt_d_to_int(d1, rs2_addr[1:0], rm, result_flags);
- end
- int_result = result_int;
- fflags = result_flags;
- end
-
- FP_OP_CVT_I2F: begin
- result_d = cvt_int_to_fp(int_rs1_data, rs2_addr[1:0], fp_fmt == FP_FMT_D, rm, result_flags);
- fp_result = result_d;
- fflags = result_flags;
- end
-
- FP_OP_CVT_F2F: begin
- if (fp_fmt == FP_FMT_D) begin
- result_d = cvt_s_to_d(s1, result_flags);
- fp_result = result_d;
- if (is_nan_s(s1)) begin
- result_flags[4] = is_snan_s(s1);
- end
- end else begin
- result_d = cvt_d_to_s(d1, rm, result_flags);
- fp_result = result_d;
- if (is_nan_d(d1)) begin
- result_flags[4] = is_snan_d(d1);
- end
- end
- fflags = result_flags;
- end
-
- default: begin
- fp_result = (fp_fmt == FP_FMT_S) ? {32'hFFFF_FFFF, CANONICAL_NAN_S} : CANONICAL_NAN_D;
- int_result = '0;
- fflags[4] = 1'b1;
- end
- endcase
- end
-
-endmodule