feat: make blackwell fexp synthesis-ready
This commit is contained in:
@@ -32,10 +32,27 @@
|
|||||||
`define DCACHE_DISABLE
|
`define DCACHE_DISABLE
|
||||||
|
|
||||||
`ifdef SYNTHESIS
|
`ifdef SYNTHESIS
|
||||||
`define NUM_BARRIERS 8
|
`ifndef NUM_BARRIERS
|
||||||
`define NUM_CORES 4
|
`define NUM_BARRIERS 4
|
||||||
`define NUM_THREADS 8
|
`endif
|
||||||
`define NUM_WARPS 8
|
`ifndef NUM_CORES
|
||||||
|
`define NUM_CORES 1
|
||||||
|
`endif
|
||||||
|
`ifndef NUM_THREADS
|
||||||
|
`define NUM_THREADS 4
|
||||||
|
`endif
|
||||||
|
`ifndef NUM_WARPS
|
||||||
|
`define NUM_WARPS 4
|
||||||
|
`endif
|
||||||
|
`ifndef NUM_TENSOR_WARPS
|
||||||
|
`define NUM_TENSOR_WARPS 2
|
||||||
|
`endif
|
||||||
|
`ifndef LSUQ_SIZE
|
||||||
|
`define LSUQ_SIZE 32
|
||||||
|
`endif
|
||||||
|
`ifndef EXT_T_BLACKWELL
|
||||||
|
`define EXT_T_BLACKWELL
|
||||||
|
`endif
|
||||||
|
|
||||||
`define FPU_FPNEW
|
`define FPU_FPNEW
|
||||||
// `define FIRESIM
|
// `define FIRESIM
|
||||||
|
|||||||
@@ -12,11 +12,6 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
`include "VX_fpu_define.vh"
|
`include "VX_fpu_define.vh"
|
||||||
`ifdef SV_DPI
|
|
||||||
`include "float_dpi.vh"
|
|
||||||
`else
|
|
||||||
`ERROR(("VX_fpu_exp requires SV_DPI; replace dpi_fexp with synthesizable exp RTL for synthesis"))
|
|
||||||
`endif
|
|
||||||
|
|
||||||
module VX_fpu_exp import VX_fpu_pkg::*; #(
|
module VX_fpu_exp import VX_fpu_pkg::*; #(
|
||||||
parameter NUM_LANES = 1,
|
parameter NUM_LANES = 1,
|
||||||
@@ -49,6 +44,163 @@ module VX_fpu_exp import VX_fpu_pkg::*; #(
|
|||||||
fflags_t [NUM_LANES-1:0] per_lane_fflags;
|
fflags_t [NUM_LANES-1:0] per_lane_fflags;
|
||||||
wire [NUM_LANES-1:0] lane_mask_out;
|
wire [NUM_LANES-1:0] lane_mask_out;
|
||||||
|
|
||||||
|
// Convert finite FP32 to signed Q12. Values outside the useful FP32 exp
|
||||||
|
// input range are saturated; the range-reduction logic below will turn
|
||||||
|
// them into the appropriate overflow or underflow result.
|
||||||
|
function automatic signed [23:0] f32_to_q12;
|
||||||
|
input [31:0] value;
|
||||||
|
reg [7:0] exponent;
|
||||||
|
reg [23:0] mantissa;
|
||||||
|
reg [63:0] magnitude;
|
||||||
|
integer shift;
|
||||||
|
begin
|
||||||
|
exponent = value[30:23];
|
||||||
|
mantissa = {1'b1, value[22:0]};
|
||||||
|
magnitude = 0;
|
||||||
|
if (exponent == 0) begin
|
||||||
|
f32_to_q12 = 24'sd0;
|
||||||
|
end else begin
|
||||||
|
shift = integer'(exponent) - 138;
|
||||||
|
if (shift >= 0) begin
|
||||||
|
if (shift < 40)
|
||||||
|
magnitude = {40'd0, mantissa} << shift;
|
||||||
|
else
|
||||||
|
magnitude = 64'h7fffff;
|
||||||
|
end else if (shift > -64) begin
|
||||||
|
magnitude = {40'd0, mantissa} >> (-shift);
|
||||||
|
end
|
||||||
|
if (magnitude > 64'h7fffff)
|
||||||
|
magnitude = 64'h7fffff;
|
||||||
|
f32_to_q12 = value[31]
|
||||||
|
? -$signed({1'b0, magnitude[22:0]})
|
||||||
|
: $signed({1'b0, magnitude[22:0]});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// Q20 samples of exp(index / 16). The same LUT/interpolation structure is
|
||||||
|
// used by the TMEM softmax engine. Range reduction guarantees index <= 11.
|
||||||
|
function automatic [23:0] exp_frac_lut;
|
||||||
|
input [3:0] index;
|
||||||
|
begin
|
||||||
|
case (index)
|
||||||
|
4'd0: exp_frac_lut = 24'd1048576;
|
||||||
|
4'd1: exp_frac_lut = 24'd1116203;
|
||||||
|
4'd2: exp_frac_lut = 24'd1188192;
|
||||||
|
4'd3: exp_frac_lut = 24'd1264824;
|
||||||
|
4'd4: exp_frac_lut = 24'd1346398;
|
||||||
|
4'd5: exp_frac_lut = 24'd1433233;
|
||||||
|
4'd6: exp_frac_lut = 24'd1525669;
|
||||||
|
4'd7: exp_frac_lut = 24'd1624066;
|
||||||
|
4'd8: exp_frac_lut = 24'd1728810;
|
||||||
|
4'd9: exp_frac_lut = 24'd1840308;
|
||||||
|
4'd10: exp_frac_lut = 24'd1958998;
|
||||||
|
4'd11: exp_frac_lut = 24'd2085342;
|
||||||
|
default: exp_frac_lut = 24'd2219835;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [23:0] interpolate_exp_frac;
|
||||||
|
input [3:0] index;
|
||||||
|
input [7:0] remainder;
|
||||||
|
reg [23:0] lower;
|
||||||
|
reg [23:0] upper;
|
||||||
|
reg [31:0] delta;
|
||||||
|
reg [31:0] product;
|
||||||
|
reg [31:0] interpolated;
|
||||||
|
begin
|
||||||
|
lower = exp_frac_lut(index);
|
||||||
|
upper = exp_frac_lut(index + 1'b1);
|
||||||
|
delta = {8'd0, upper} - {8'd0, lower};
|
||||||
|
product = delta * remainder;
|
||||||
|
interpolated = {8'd0, lower} + ((product + 32'd128) >> 8);
|
||||||
|
interpolate_exp_frac = interpolated[23:0];
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// Synthesizable FP32 exponential approximation.
|
||||||
|
//
|
||||||
|
// x = k*ln(2) + r, 0 <= r < ln(2)
|
||||||
|
// exp(x) = 2^k * exp(r)
|
||||||
|
//
|
||||||
|
// r is evaluated using the softmax-style Q12/LUT/interpolation datapath.
|
||||||
|
// The packed return value is {NV,DZ,OF,UF,NX,result[31:0]}.
|
||||||
|
function automatic [36:0] exp_approx_f32;
|
||||||
|
input [31:0] value;
|
||||||
|
reg signed [23:0] x_q12;
|
||||||
|
integer signed k;
|
||||||
|
integer signed rem_q12;
|
||||||
|
integer signed exp_field;
|
||||||
|
integer shift;
|
||||||
|
reg [23:0] exp_r_q20;
|
||||||
|
reg [23:0] significand;
|
||||||
|
reg [23:0] shifted;
|
||||||
|
reg [23:0] discarded_mask;
|
||||||
|
reg [23:0] discarded;
|
||||||
|
reg [23:0] halfway;
|
||||||
|
reg [22:0] mantissa;
|
||||||
|
reg [31:0] fp_result;
|
||||||
|
reg [4:0] fp_flags;
|
||||||
|
begin
|
||||||
|
fp_result = 32'h3f800000;
|
||||||
|
fp_flags = 5'b00000;
|
||||||
|
|
||||||
|
if (value[30:23] == 8'hff) begin
|
||||||
|
if (value[22:0] != 0) begin
|
||||||
|
fp_result = 32'h7fc00000;
|
||||||
|
fp_flags[4] = ~value[22];
|
||||||
|
end else if (value[31]) begin
|
||||||
|
fp_result = 32'h00000000;
|
||||||
|
end else begin
|
||||||
|
fp_result = 32'h7f800000;
|
||||||
|
end
|
||||||
|
end else if (value[30:0] != 0) begin
|
||||||
|
x_q12 = f32_to_q12(value);
|
||||||
|
k = integer'($signed(x_q12)) / 2839;
|
||||||
|
rem_q12 = integer'($signed(x_q12)) - k * 2839;
|
||||||
|
if (rem_q12 < 0) begin
|
||||||
|
k = k - 1;
|
||||||
|
rem_q12 = rem_q12 + 2839;
|
||||||
|
end
|
||||||
|
|
||||||
|
exp_r_q20 = interpolate_exp_frac(
|
||||||
|
4'(rem_q12 >> 8), 8'(rem_q12));
|
||||||
|
significand = {1'b1, exp_r_q20[19:0], 3'b000};
|
||||||
|
exp_field = 127 + k;
|
||||||
|
fp_flags[0] = 1'b1;
|
||||||
|
|
||||||
|
if (exp_field >= 255) begin
|
||||||
|
fp_result = 32'h7f800000;
|
||||||
|
fp_flags[2] = 1'b1;
|
||||||
|
end else if (exp_field > 0) begin
|
||||||
|
mantissa = significand[22:0];
|
||||||
|
fp_result = {1'b0, 8'(exp_field), mantissa};
|
||||||
|
end else begin
|
||||||
|
shift = 1 - exp_field;
|
||||||
|
fp_flags[1] = 1'b1;
|
||||||
|
if (shift >= 25) begin
|
||||||
|
fp_result = 32'h00000000;
|
||||||
|
end else begin
|
||||||
|
shifted = significand >> shift;
|
||||||
|
discarded_mask = (24'd1 << shift) - 1'b1;
|
||||||
|
discarded = significand & discarded_mask;
|
||||||
|
halfway = 24'd1 << (shift - 1);
|
||||||
|
if ((discarded > halfway)
|
||||||
|
|| ((discarded == halfway) && shifted[0]))
|
||||||
|
shifted = shifted + 1'b1;
|
||||||
|
if (shifted[23])
|
||||||
|
fp_result = 32'h00800000;
|
||||||
|
else
|
||||||
|
fp_result = {9'd0, shifted[22:0]};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
exp_approx_f32 = {fp_flags, fp_result};
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
VX_shift_register #(
|
VX_shift_register #(
|
||||||
.DATAW (1 + NUM_LANES + TAGW),
|
.DATAW (1 + NUM_LANES + TAGW),
|
||||||
.DEPTH (`LATENCY_FEXP),
|
.DEPTH (`LATENCY_FEXP),
|
||||||
@@ -64,23 +216,16 @@ module VX_fpu_exp import VX_fpu_pkg::*; #(
|
|||||||
assign ready_in = enable;
|
assign ready_in = enable;
|
||||||
|
|
||||||
for (genvar i = 0; i < NUM_LANES; ++i) begin
|
for (genvar i = 0; i < NUM_LANES; ++i) begin
|
||||||
reg [63:0] r;
|
wire [36:0] exp_approx = exp_approx_f32(dataa[i]);
|
||||||
`UNUSED_VAR (r)
|
|
||||||
|
|
||||||
fflags_t f;
|
|
||||||
|
|
||||||
always @(*) begin
|
|
||||||
dpi_fexp(enable && valid_in, int'(0), {32'hffffffff, dataa[i]}, r, f);
|
|
||||||
end
|
|
||||||
|
|
||||||
VX_shift_register #(
|
VX_shift_register #(
|
||||||
.DATAW (32 + $bits(fflags_t)),
|
.DATAW (32 + $bits(fflags_t)),
|
||||||
.DEPTH (`LATENCY_FEXP)
|
.DEPTH (`LATENCY_FEXP)
|
||||||
) shift_req_dpi (
|
) shift_req_exp (
|
||||||
.clk (clk),
|
.clk (clk),
|
||||||
`UNUSED_PIN (reset),
|
`UNUSED_PIN (reset),
|
||||||
.enable (enable),
|
.enable (enable),
|
||||||
.data_in ({r[31:0], f}),
|
.data_in ({exp_approx[31:0], exp_approx[36:32]}),
|
||||||
.data_out ({result[i], per_lane_fflags[i]})
|
.data_out ({result[i], per_lane_fflags[i]})
|
||||||
);
|
);
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user