feat: add scalar fexp support
This commit is contained in:
@@ -37,6 +37,7 @@ extern "C" {
|
|||||||
|
|
||||||
void dpi_fdiv(bool enable, int dst_fmt, int64_t a, int64_t b, const svBitVecVal* frm, int64_t* result, svBitVecVal* fflags);
|
void dpi_fdiv(bool enable, int dst_fmt, int64_t a, int64_t b, const svBitVecVal* frm, int64_t* result, svBitVecVal* fflags);
|
||||||
void dpi_fsqrt(bool enable, int dst_fmt, int64_t a, const svBitVecVal* frm, int64_t* result, svBitVecVal* fflags);
|
void dpi_fsqrt(bool enable, int dst_fmt, int64_t a, const svBitVecVal* frm, int64_t* result, svBitVecVal* fflags);
|
||||||
|
void dpi_fexp(bool enable, int dst_fmt, int64_t a, int64_t* result, svBitVecVal* fflags);
|
||||||
|
|
||||||
void dpi_ftoi(bool enable, int dst_fmt, int src_fmt, int64_t a, const svBitVecVal* frm, int64_t* result, svBitVecVal* fflags);
|
void dpi_ftoi(bool enable, int dst_fmt, int src_fmt, int64_t a, const svBitVecVal* frm, int64_t* result, svBitVecVal* fflags);
|
||||||
void dpi_ftou(bool enable, int dst_fmt, int src_fmt, int64_t a, const svBitVecVal* frm, int64_t* result, svBitVecVal* fflags);
|
void dpi_ftou(bool enable, int dst_fmt, int src_fmt, int64_t a, const svBitVecVal* frm, int64_t* result, svBitVecVal* fflags);
|
||||||
@@ -83,6 +84,22 @@ inline int64_t check_boxing(int64_t a) {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline float bits_to_float(uint32_t value) {
|
||||||
|
union {
|
||||||
|
uint32_t u;
|
||||||
|
float f;
|
||||||
|
} bits = {value};
|
||||||
|
return bits.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t float_to_bits(float value) {
|
||||||
|
union {
|
||||||
|
float f;
|
||||||
|
uint32_t u;
|
||||||
|
} bits = {value};
|
||||||
|
return bits.u;
|
||||||
|
}
|
||||||
|
|
||||||
void dpi_fadd(bool enable, int dst_fmt, int64_t a, int64_t b, const svBitVecVal* frm, int64_t* result, svBitVecVal* fflags) {
|
void dpi_fadd(bool enable, int dst_fmt, int64_t a, int64_t b, const svBitVecVal* frm, int64_t* result, svBitVecVal* fflags) {
|
||||||
if (!enable)
|
if (!enable)
|
||||||
return;
|
return;
|
||||||
@@ -173,6 +190,38 @@ void dpi_fsqrt(bool enable, int dst_fmt, int64_t a, const svBitVecVal* frm, int6
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dpi_fexp(bool enable, int dst_fmt, int64_t a, int64_t* result, svBitVecVal* fflags) {
|
||||||
|
if (!enable)
|
||||||
|
return;
|
||||||
|
*fflags = 0;
|
||||||
|
if (dst_fmt) {
|
||||||
|
double input;
|
||||||
|
static_assert(sizeof(input) == sizeof(a), "unexpected double size");
|
||||||
|
__builtin_memcpy(&input, &a, sizeof(input));
|
||||||
|
double output = exp(input);
|
||||||
|
__builtin_memcpy(result, &output, sizeof(output));
|
||||||
|
if (isinf(output) && isfinite(input)) {
|
||||||
|
*fflags |= 0x05; // OF | NX
|
||||||
|
} else if (output == 0.0 && input < 0.0 && isfinite(input)) {
|
||||||
|
*fflags |= 0x03; // UF | NX
|
||||||
|
} else if (isfinite(input)) {
|
||||||
|
*fflags |= 0x01; // NX
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint32_t boxed = static_cast<uint32_t>(check_boxing(a));
|
||||||
|
float input = bits_to_float(boxed);
|
||||||
|
float output = expf(input);
|
||||||
|
*result = nan_box(float_to_bits(output));
|
||||||
|
if (isinf(output) && isfinite(input)) {
|
||||||
|
*fflags |= 0x05; // OF | NX
|
||||||
|
} else if (output == 0.0f && input < 0.0f && isfinite(input)) {
|
||||||
|
*fflags |= 0x03; // UF | NX
|
||||||
|
} else if (isfinite(input)) {
|
||||||
|
*fflags |= 0x01; // NX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void dpi_ftoi(bool enable, int dst_fmt, int src_fmt, int64_t a, const svBitVecVal* frm, int64_t* result, svBitVecVal* fflags) {
|
void dpi_ftoi(bool enable, int dst_fmt, int src_fmt, int64_t a, const svBitVecVal* frm, int64_t* result, svBitVecVal* fflags) {
|
||||||
if (!enable)
|
if (!enable)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import "DPI-C" function void dpi_fnmsub(input logic enable, input int dst_fmt, i
|
|||||||
|
|
||||||
import "DPI-C" function void dpi_fdiv(input logic enable, input int dst_fmt, input longint a, input longint b, input bit[2:0] frm, output longint result, output bit[4:0] fflags);
|
import "DPI-C" function void dpi_fdiv(input logic enable, input int dst_fmt, input longint a, input longint b, input bit[2:0] frm, output longint result, output bit[4:0] fflags);
|
||||||
import "DPI-C" function void dpi_fsqrt(input logic enable, input int dst_fmt, input longint a, input bit[2:0] frm, output longint result, output bit[4:0] fflags);
|
import "DPI-C" function void dpi_fsqrt(input logic enable, input int dst_fmt, input longint a, input bit[2:0] frm, output longint result, output bit[4:0] fflags);
|
||||||
|
import "DPI-C" function void dpi_fexp(input logic enable, input int dst_fmt, input longint a, output longint result, output bit[4:0] fflags);
|
||||||
|
|
||||||
import "DPI-C" function void dpi_ftoi(input logic enable, input int dst_fmt, input int src_fmt, input longint a, input bit[2:0] frm, output longint result, output bit[4:0] fflags);
|
import "DPI-C" function void dpi_ftoi(input logic enable, input int dst_fmt, input int src_fmt, input longint a, input bit[2:0] frm, output longint result, output bit[4:0] fflags);
|
||||||
import "DPI-C" function void dpi_ftou(input logic enable, input int dst_fmt, input int src_fmt, input longint a, input bit[2:0] frm, output longint result, output bit[4:0] fflags);
|
import "DPI-C" function void dpi_ftou(input logic enable, input int dst_fmt, input int src_fmt, input longint a, input bit[2:0] frm, output longint result, output bit[4:0] fflags);
|
||||||
|
|||||||
@@ -422,6 +422,11 @@
|
|||||||
`endif
|
`endif
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
|
// FEXP Latency
|
||||||
|
`ifndef LATENCY_FEXP
|
||||||
|
`define LATENCY_FEXP 8
|
||||||
|
`endif
|
||||||
|
|
||||||
// FCVT Latency
|
// FCVT Latency
|
||||||
`ifndef LATENCY_FCVT
|
`ifndef LATENCY_FCVT
|
||||||
`define LATENCY_FCVT 5
|
`define LATENCY_FCVT 5
|
||||||
|
|||||||
@@ -240,6 +240,7 @@
|
|||||||
`define INST_FPU_IS_W(mod) (mod[4])
|
`define INST_FPU_IS_W(mod) (mod[4])
|
||||||
`define INST_FPU_IS_CLASS(op, mod) (op == `INST_FPU_MISC && mod == 3)
|
`define INST_FPU_IS_CLASS(op, mod) (op == `INST_FPU_MISC && mod == 3)
|
||||||
`define INST_FPU_IS_MVXW(op, mod) (op == `INST_FPU_MISC && mod == 4)
|
`define INST_FPU_IS_MVXW(op, mod) (op == `INST_FPU_MISC && mod == 4)
|
||||||
|
`define INST_FPU_IS_EXP(op, mod) (op == `INST_FPU_MISC && mod == 8)
|
||||||
|
|
||||||
`define INST_SFU_TMC 4'h0
|
`define INST_SFU_TMC 4'h0
|
||||||
`define INST_SFU_WSPAWN 4'h1
|
`define INST_SFU_WSPAWN 4'h1
|
||||||
|
|||||||
@@ -538,6 +538,18 @@ module VX_decode #(
|
|||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
`ifdef EXT_F_ENABLE
|
||||||
|
3'h2: begin
|
||||||
|
if (func7 == 7'h30 && rs2 == 5'd0) begin
|
||||||
|
ex_type = `EX_FPU;
|
||||||
|
op_type = `INST_OP_BITS'(`INST_FPU_MISC);
|
||||||
|
op_mod = `INST_MOD_BITS'(8); // FEXP.S
|
||||||
|
use_rd = 1;
|
||||||
|
`USED_FREG (rd);
|
||||||
|
`USED_FREG (rs1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
`endif
|
||||||
default:;
|
default:;
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ module VX_fpu_unit import VX_fpu_pkg::*; #(
|
|||||||
|
|
||||||
.valid_in (fpu_req_valid),
|
.valid_in (fpu_req_valid),
|
||||||
.op_type (execute_if[block_idx].data.op_type),
|
.op_type (execute_if[block_idx].data.op_type),
|
||||||
|
.op_mod (execute_if[block_idx].data.op_mod),
|
||||||
.lane_mask (execute_if[block_idx].data.tmask),
|
.lane_mask (execute_if[block_idx].data.tmask),
|
||||||
.fmt (fpu_fmt),
|
.fmt (fpu_fmt),
|
||||||
.frm (fpu_req_frm),
|
.frm (fpu_req_frm),
|
||||||
@@ -174,6 +175,7 @@ module VX_fpu_unit import VX_fpu_pkg::*; #(
|
|||||||
|
|
||||||
.valid_in (fpu_req_valid),
|
.valid_in (fpu_req_valid),
|
||||||
.op_type (execute_if[block_idx].data.op_type),
|
.op_type (execute_if[block_idx].data.op_type),
|
||||||
|
.op_mod (execute_if[block_idx].data.op_mod),
|
||||||
.lane_mask (execute_if[block_idx].data.tmask),
|
.lane_mask (execute_if[block_idx].data.tmask),
|
||||||
.fmt (fpu_fmt),
|
.fmt (fpu_fmt),
|
||||||
.frm (fpu_req_frm),
|
.frm (fpu_req_frm),
|
||||||
@@ -204,6 +206,7 @@ module VX_fpu_unit import VX_fpu_pkg::*; #(
|
|||||||
.valid_in (fpu_req_valid),
|
.valid_in (fpu_req_valid),
|
||||||
.lane_mask (execute_if[block_idx].data.tmask),
|
.lane_mask (execute_if[block_idx].data.tmask),
|
||||||
.op_type (execute_if[block_idx].data.op_type),
|
.op_type (execute_if[block_idx].data.op_type),
|
||||||
|
.op_mod (execute_if[block_idx].data.op_mod),
|
||||||
.fmt (fpu_fmt),
|
.fmt (fpu_fmt),
|
||||||
.frm (fpu_req_frm),
|
.frm (fpu_req_frm),
|
||||||
.dataa (execute_if[block_idx].data.rs1_data),
|
.dataa (execute_if[block_idx].data.rs1_data),
|
||||||
|
|||||||
@@ -327,6 +327,7 @@ task trace_ex_op(input int level,
|
|||||||
`INST_FPU_MISC: begin
|
`INST_FPU_MISC: begin
|
||||||
if (fdst_d) begin
|
if (fdst_d) begin
|
||||||
case (op_mod)
|
case (op_mod)
|
||||||
|
8: `TRACE(level, ("FEXP.D"));
|
||||||
0: `TRACE(level, ("FSGNJ.D"));
|
0: `TRACE(level, ("FSGNJ.D"));
|
||||||
1: `TRACE(level, ("FSGNJN.D"));
|
1: `TRACE(level, ("FSGNJN.D"));
|
||||||
2: `TRACE(level, ("FSGNJX.D"));
|
2: `TRACE(level, ("FSGNJX.D"));
|
||||||
@@ -338,6 +339,7 @@ task trace_ex_op(input int level,
|
|||||||
endcase
|
endcase
|
||||||
end else begin
|
end else begin
|
||||||
case (op_mod)
|
case (op_mod)
|
||||||
|
8: `TRACE(level, ("FEXP.S"));
|
||||||
0: `TRACE(level, ("FSGNJ.S"));
|
0: `TRACE(level, ("FSGNJ.S"));
|
||||||
1: `TRACE(level, ("FSGNJN.S"));
|
1: `TRACE(level, ("FSGNJN.S"));
|
||||||
2: `TRACE(level, ("FSGNJX.S"));
|
2: `TRACE(level, ("FSGNJX.S"));
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #(
|
|||||||
input wire [TAGW-1:0] tag_in,
|
input wire [TAGW-1:0] tag_in,
|
||||||
|
|
||||||
input wire [`INST_FPU_BITS-1:0] op_type,
|
input wire [`INST_FPU_BITS-1:0] op_type,
|
||||||
|
input wire [`INST_MOD_BITS-1:0] op_mod,
|
||||||
input wire [`INST_FMT_BITS-1:0] fmt,
|
input wire [`INST_FMT_BITS-1:0] fmt,
|
||||||
input wire [`INST_FRM_BITS-1:0] frm,
|
input wire [`INST_FRM_BITS-1:0] frm,
|
||||||
|
|
||||||
@@ -51,7 +52,8 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #(
|
|||||||
localparam FPU_DIVSQRT = 1;
|
localparam FPU_DIVSQRT = 1;
|
||||||
localparam FPU_CVT = 2;
|
localparam FPU_CVT = 2;
|
||||||
localparam FPU_NCP = 3;
|
localparam FPU_NCP = 3;
|
||||||
localparam NUM_FPC = 4;
|
localparam FPU_EXP = 4;
|
||||||
|
localparam NUM_FPC = 5;
|
||||||
localparam FPC_BITS = `LOG2UP(NUM_FPC);
|
localparam FPC_BITS = `LOG2UP(NUM_FPC);
|
||||||
|
|
||||||
localparam RSP_DATAW = (NUM_LANES * `XLEN) + 1 + $bits(fflags_t) + TAGW;
|
localparam RSP_DATAW = (NUM_LANES * `XLEN) + 1 + $bits(fflags_t) + TAGW;
|
||||||
@@ -133,6 +135,7 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #(
|
|||||||
`INST_FPU_I2F: begin core_select = FPU_CVT; is_itof = 1; end
|
`INST_FPU_I2F: begin core_select = FPU_CVT; is_itof = 1; end
|
||||||
`INST_FPU_U2F: begin core_select = FPU_CVT; is_utof = 1; end
|
`INST_FPU_U2F: begin core_select = FPU_CVT; is_utof = 1; end
|
||||||
`INST_FPU_F2F: begin core_select = FPU_CVT; is_f2f = 1; end
|
`INST_FPU_F2F: begin core_select = FPU_CVT; is_f2f = 1; end
|
||||||
|
`INST_FPU_MISC: begin core_select = `INST_FPU_IS_EXP(op_type, op_mod) ? FPU_EXP : FPU_NCP; end
|
||||||
default: begin core_select = FPU_NCP; end
|
default: begin core_select = FPU_NCP; end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
@@ -437,6 +440,45 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #(
|
|||||||
end
|
end
|
||||||
endgenerate
|
endgenerate
|
||||||
|
|
||||||
|
generate
|
||||||
|
begin : fexp
|
||||||
|
|
||||||
|
reg [NUM_LANES-1:0][`XLEN-1:0] result_fexp_r;
|
||||||
|
reg [NUM_LANES-1:0][63:0] result_fexp;
|
||||||
|
fflags_t [NUM_LANES-1:0] fflags_fexp;
|
||||||
|
|
||||||
|
wire fexp_valid = (valid_in && core_select == FPU_EXP);
|
||||||
|
wire fexp_ready = per_core_ready_out[FPU_EXP] || ~per_core_valid_out[FPU_EXP];
|
||||||
|
wire fexp_fire = fexp_valid && fexp_ready;
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
for (integer i = 0; i < NUM_LANES; ++i) begin
|
||||||
|
dpi_fexp(fexp_fire, int'(dst_fmt), operands[0][i], result_fexp[i], fflags_fexp[i]);
|
||||||
|
result_fexp_r[i] = result_fexp[i][`XLEN-1:0];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
fflags_t fflags_merged;
|
||||||
|
`FPU_MERGE_FFLAGS(fflags_merged, fflags_fexp, lane_mask, NUM_LANES);
|
||||||
|
|
||||||
|
VX_shift_register #(
|
||||||
|
.DATAW (1 + TAGW + NUM_LANES * `XLEN + $bits(fflags_t)),
|
||||||
|
.DEPTH (`LATENCY_FEXP),
|
||||||
|
.RESETW (1)
|
||||||
|
) shift_reg (
|
||||||
|
.clk (clk),
|
||||||
|
.reset (reset),
|
||||||
|
.enable (fexp_ready),
|
||||||
|
.data_in ({fexp_valid, tag_in, result_fexp_r, fflags_merged}),
|
||||||
|
.data_out ({per_core_valid_out[FPU_EXP], per_core_tag_out[FPU_EXP], per_core_result[FPU_EXP], per_core_fflags[FPU_EXP]})
|
||||||
|
);
|
||||||
|
|
||||||
|
assign per_core_has_fflags[FPU_EXP] = 1;
|
||||||
|
assign per_core_ready_in[FPU_EXP] = fexp_ready;
|
||||||
|
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
assign per_core_ready_in[FPU_DIVSQRT] = is_div ? div_ready_in : sqrt_ready_in;
|
assign per_core_ready_in[FPU_DIVSQRT] = is_div ? div_ready_in : sqrt_ready_in;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ module VX_fpu_dsp import VX_fpu_pkg::*; #(
|
|||||||
input wire [TAGW-1:0] tag_in,
|
input wire [TAGW-1:0] tag_in,
|
||||||
|
|
||||||
input wire [`INST_FPU_BITS-1:0] op_type,
|
input wire [`INST_FPU_BITS-1:0] op_type,
|
||||||
|
input wire [`INST_MOD_BITS-1:0] op_mod,
|
||||||
input wire [`INST_FMT_BITS-1:0] fmt,
|
input wire [`INST_FMT_BITS-1:0] fmt,
|
||||||
input wire [`INST_FRM_BITS-1:0] frm,
|
input wire [`INST_FRM_BITS-1:0] frm,
|
||||||
|
|
||||||
@@ -51,7 +52,8 @@ module VX_fpu_dsp import VX_fpu_pkg::*; #(
|
|||||||
localparam FPU_DIVSQRT = 1;
|
localparam FPU_DIVSQRT = 1;
|
||||||
localparam FPU_CVT = 2;
|
localparam FPU_CVT = 2;
|
||||||
localparam FPU_NCP = 3;
|
localparam FPU_NCP = 3;
|
||||||
localparam NUM_FPC = 4;
|
localparam FPU_EXP = 4;
|
||||||
|
localparam NUM_FPC = 5;
|
||||||
localparam FPC_BITS = `LOG2UP(NUM_FPC);
|
localparam FPC_BITS = `LOG2UP(NUM_FPC);
|
||||||
|
|
||||||
localparam RSP_DATAW = (NUM_LANES * 32) + 1 + $bits(fflags_t) + TAGW;
|
localparam RSP_DATAW = (NUM_LANES * 32) + 1 + $bits(fflags_t) + TAGW;
|
||||||
@@ -98,6 +100,7 @@ module VX_fpu_dsp import VX_fpu_pkg::*; #(
|
|||||||
`INST_FPU_F2U: begin core_select = FPU_CVT; end
|
`INST_FPU_F2U: begin core_select = FPU_CVT; end
|
||||||
`INST_FPU_I2F: begin core_select = FPU_CVT; is_itof = 1; is_signed = 1; end
|
`INST_FPU_I2F: begin core_select = FPU_CVT; is_itof = 1; is_signed = 1; end
|
||||||
`INST_FPU_U2F: begin core_select = FPU_CVT; is_itof = 1; end
|
`INST_FPU_U2F: begin core_select = FPU_CVT; is_itof = 1; end
|
||||||
|
`INST_FPU_MISC: begin core_select = `INST_FPU_IS_EXP(op_type, op_mod) ? FPU_EXP : FPU_NCP; end
|
||||||
default: begin core_select = FPU_NCP; end
|
default: begin core_select = FPU_NCP; end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
@@ -107,6 +110,7 @@ module VX_fpu_dsp import VX_fpu_pkg::*; #(
|
|||||||
`RESET_RELAY (sqrt_reset, reset);
|
`RESET_RELAY (sqrt_reset, reset);
|
||||||
`RESET_RELAY (cvt_reset, reset);
|
`RESET_RELAY (cvt_reset, reset);
|
||||||
`RESET_RELAY (ncp_reset, reset);
|
`RESET_RELAY (ncp_reset, reset);
|
||||||
|
`RESET_RELAY (exp_reset, reset);
|
||||||
|
|
||||||
wire [NUM_LANES-1:0][31:0] dataa_s;
|
wire [NUM_LANES-1:0][31:0] dataa_s;
|
||||||
wire [NUM_LANES-1:0][31:0] datab_s;
|
wire [NUM_LANES-1:0][31:0] datab_s;
|
||||||
@@ -243,6 +247,25 @@ module VX_fpu_dsp import VX_fpu_pkg::*; #(
|
|||||||
.ready_out (per_core_ready_out[FPU_NCP])
|
.ready_out (per_core_ready_out[FPU_NCP])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
VX_fpu_exp #(
|
||||||
|
.NUM_LANES (NUM_LANES),
|
||||||
|
.TAGW (TAGW)
|
||||||
|
) fpu_exp (
|
||||||
|
.clk (clk),
|
||||||
|
.reset (exp_reset),
|
||||||
|
.valid_in (valid_in && (core_select == FPU_EXP)),
|
||||||
|
.ready_in (per_core_ready_in[FPU_EXP]),
|
||||||
|
.lane_mask (lane_mask),
|
||||||
|
.tag_in (tag_in),
|
||||||
|
.dataa (dataa_s),
|
||||||
|
.has_fflags (per_core_has_fflags[FPU_EXP]),
|
||||||
|
.fflags (per_core_fflags[FPU_EXP]),
|
||||||
|
.result (per_core_result[FPU_EXP]),
|
||||||
|
.tag_out (per_core_tag_out[FPU_EXP]),
|
||||||
|
.valid_out (per_core_valid_out[FPU_EXP]),
|
||||||
|
.ready_out (per_core_ready_out[FPU_EXP])
|
||||||
|
);
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
assign per_core_ready_in[FPU_DIVSQRT] = is_div ? div_ready_in : sqrt_ready_in;
|
assign per_core_ready_in[FPU_DIVSQRT] = is_div ? div_ready_in : sqrt_ready_in;
|
||||||
|
|||||||
92
hw/rtl/fpu/VX_fpu_exp.sv
Normal file
92
hw/rtl/fpu/VX_fpu_exp.sv
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
// Copyright © 2019-2023
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
`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::*; #(
|
||||||
|
parameter NUM_LANES = 1,
|
||||||
|
parameter TAGW = 1
|
||||||
|
) (
|
||||||
|
input wire clk,
|
||||||
|
input wire reset,
|
||||||
|
|
||||||
|
output wire ready_in,
|
||||||
|
input wire valid_in,
|
||||||
|
|
||||||
|
input wire [NUM_LANES-1:0] lane_mask,
|
||||||
|
|
||||||
|
input wire [TAGW-1:0] tag_in,
|
||||||
|
|
||||||
|
input wire [NUM_LANES-1:0][31:0] dataa,
|
||||||
|
output wire [NUM_LANES-1:0][31:0] result,
|
||||||
|
|
||||||
|
output wire has_fflags,
|
||||||
|
output wire [`FP_FLAGS_BITS-1:0] fflags,
|
||||||
|
|
||||||
|
output wire [TAGW-1:0] tag_out,
|
||||||
|
|
||||||
|
input wire ready_out,
|
||||||
|
output wire valid_out
|
||||||
|
);
|
||||||
|
wire stall = ~ready_out && valid_out;
|
||||||
|
wire enable = ~stall;
|
||||||
|
|
||||||
|
fflags_t [NUM_LANES-1:0] per_lane_fflags;
|
||||||
|
wire [NUM_LANES-1:0] lane_mask_out;
|
||||||
|
|
||||||
|
VX_shift_register #(
|
||||||
|
.DATAW (1 + NUM_LANES + TAGW),
|
||||||
|
.DEPTH (`LATENCY_FEXP),
|
||||||
|
.RESETW (1)
|
||||||
|
) shift_reg (
|
||||||
|
.clk (clk),
|
||||||
|
.reset (reset),
|
||||||
|
.enable (enable),
|
||||||
|
.data_in ({valid_in, lane_mask, tag_in}),
|
||||||
|
.data_out ({valid_out, lane_mask_out, tag_out})
|
||||||
|
);
|
||||||
|
|
||||||
|
assign ready_in = enable;
|
||||||
|
|
||||||
|
for (genvar i = 0; i < NUM_LANES; ++i) begin
|
||||||
|
reg [63:0] r;
|
||||||
|
`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 #(
|
||||||
|
.DATAW (32 + $bits(fflags_t)),
|
||||||
|
.DEPTH (`LATENCY_FEXP)
|
||||||
|
) shift_req_dpi (
|
||||||
|
.clk (clk),
|
||||||
|
`UNUSED_PIN (reset),
|
||||||
|
.enable (enable),
|
||||||
|
.data_in ({r[31:0], f}),
|
||||||
|
.data_out ({result[i], per_lane_fflags[i]})
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
assign has_fflags = 1;
|
||||||
|
|
||||||
|
`FPU_MERGE_FFLAGS(fflags, per_lane_fflags, lane_mask_out, NUM_LANES);
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -34,6 +34,7 @@ module VX_fpu_fpnew
|
|||||||
input wire [TAGW-1:0] tag_in,
|
input wire [TAGW-1:0] tag_in,
|
||||||
|
|
||||||
input wire [`INST_FPU_BITS-1:0] op_type,
|
input wire [`INST_FPU_BITS-1:0] op_type,
|
||||||
|
input wire [`INST_MOD_BITS-1:0] op_mod,
|
||||||
input wire [`INST_FMT_BITS-1:0] fmt,
|
input wire [`INST_FMT_BITS-1:0] fmt,
|
||||||
input wire [`INST_FRM_BITS-1:0] frm,
|
input wire [`INST_FRM_BITS-1:0] frm,
|
||||||
|
|
||||||
@@ -104,6 +105,7 @@ module VX_fpu_fpnew
|
|||||||
reg fpu_has_fflags, fpu_has_fflags_out;
|
reg fpu_has_fflags, fpu_has_fflags_out;
|
||||||
fpnew_pkg::fp_format_e fpu_src_fmt, fpu_dst_fmt;
|
fpnew_pkg::fp_format_e fpu_src_fmt, fpu_dst_fmt;
|
||||||
fpnew_pkg::int_format_e fpu_int_fmt;
|
fpnew_pkg::int_format_e fpu_int_fmt;
|
||||||
|
wire is_fexp = `INST_FPU_IS_EXP(op_type, op_mod);
|
||||||
|
|
||||||
`UNUSED_VAR (fmt)
|
`UNUSED_VAR (fmt)
|
||||||
|
|
||||||
@@ -183,7 +185,6 @@ module VX_fpu_fpnew
|
|||||||
end
|
end
|
||||||
|
|
||||||
`ifdef XLEN_64
|
`ifdef XLEN_64
|
||||||
`UNUSED_VAR (lane_mask)
|
|
||||||
for (genvar i = 0; i < NUM_LANES; ++i) begin
|
for (genvar i = 0; i < NUM_LANES; ++i) begin
|
||||||
wire [(TAGW+1)-1:0] fpu_tag;
|
wire [(TAGW+1)-1:0] fpu_tag;
|
||||||
wire fpu_valid_out_uq;
|
wire fpu_valid_out_uq;
|
||||||
@@ -248,8 +249,8 @@ module VX_fpu_fpnew
|
|||||||
.int_fmt_i (fpu_int_fmt),
|
.int_fmt_i (fpu_int_fmt),
|
||||||
.vectorial_op_i (1'b1),
|
.vectorial_op_i (1'b1),
|
||||||
.simd_mask_i (lane_mask),
|
.simd_mask_i (lane_mask),
|
||||||
.tag_i ({fpu_tag_in, fpu_has_fflags}),
|
.tag_i ({fpu_tag_in, fpu_has_fflags}),
|
||||||
.in_valid_i (fpu_valid_in),
|
.in_valid_i (fpu_valid_in),
|
||||||
.in_ready_o (fpu_ready_in),
|
.in_ready_o (fpu_ready_in),
|
||||||
.flush_i (reset),
|
.flush_i (reset),
|
||||||
.result_o (fpu_result),
|
.result_o (fpu_result),
|
||||||
@@ -261,10 +262,70 @@ module VX_fpu_fpnew
|
|||||||
);
|
);
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
assign fpu_valid_in = valid_in;
|
wire exp_ready_in;
|
||||||
assign ready_in = fpu_ready_in;
|
wire exp_valid_out;
|
||||||
|
wire [NUM_LANES-1:0][31:0] exp_dataa;
|
||||||
|
wire [NUM_LANES-1:0][31:0] exp_result_s;
|
||||||
|
wire [NUM_LANES-1:0][`XLEN-1:0] exp_result;
|
||||||
|
wire exp_has_fflags;
|
||||||
|
fflags_t exp_fflags;
|
||||||
|
wire [TAGW-1:0] exp_tag_out;
|
||||||
|
wire exp_ready_out;
|
||||||
|
|
||||||
|
for (genvar i = 0; i < NUM_LANES; ++i) begin
|
||||||
|
assign exp_dataa[i] = dataa[i][31:0];
|
||||||
|
`ifdef FPU_RV64F
|
||||||
|
assign exp_result[i] = {32'hffffffff, exp_result_s[i]};
|
||||||
|
`else
|
||||||
|
assign exp_result[i] = exp_result_s[i];
|
||||||
|
`endif
|
||||||
|
end
|
||||||
|
|
||||||
|
VX_fpu_exp #(
|
||||||
|
.NUM_LANES (NUM_LANES),
|
||||||
|
.TAGW (TAGW)
|
||||||
|
) fpu_exp (
|
||||||
|
.clk (clk),
|
||||||
|
.reset (reset),
|
||||||
|
.valid_in (valid_in && is_fexp),
|
||||||
|
.ready_in (exp_ready_in),
|
||||||
|
.lane_mask (lane_mask),
|
||||||
|
.tag_in (tag_in),
|
||||||
|
.dataa (exp_dataa),
|
||||||
|
.has_fflags (exp_has_fflags),
|
||||||
|
.fflags (exp_fflags),
|
||||||
|
.result (exp_result_s),
|
||||||
|
.tag_out (exp_tag_out),
|
||||||
|
.valid_out (exp_valid_out),
|
||||||
|
.ready_out (exp_ready_out)
|
||||||
|
);
|
||||||
|
|
||||||
|
assign fpu_valid_in = valid_in && !is_fexp;
|
||||||
|
assign ready_in = is_fexp ? exp_ready_in : fpu_ready_in;
|
||||||
assign fpu_tag_in = tag_in;
|
assign fpu_tag_in = tag_in;
|
||||||
|
|
||||||
|
wire [RSP_DATAW-1:0] exp_rsp_data;
|
||||||
|
wire exp_rsp_valid;
|
||||||
|
wire exp_rsp_ready;
|
||||||
|
wire [RSP_DATAW-1:0] fpu_rsp_data;
|
||||||
|
wire fpu_rsp_valid;
|
||||||
|
wire fpu_rsp_ready;
|
||||||
|
|
||||||
|
VX_elastic_buffer #(
|
||||||
|
.DATAW (RSP_DATAW),
|
||||||
|
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG)),
|
||||||
|
.OUT_REG (`OUT_REG_TO_EB_REG(OUT_REG))
|
||||||
|
) exp_rsp_buf (
|
||||||
|
.clk (clk),
|
||||||
|
.reset (reset),
|
||||||
|
.valid_in (exp_valid_out),
|
||||||
|
.ready_in (exp_ready_out),
|
||||||
|
.data_in ({exp_result, exp_has_fflags, exp_fflags, exp_tag_out}),
|
||||||
|
.data_out (exp_rsp_data),
|
||||||
|
.valid_out (exp_rsp_valid),
|
||||||
|
.ready_out (exp_rsp_ready)
|
||||||
|
);
|
||||||
|
|
||||||
VX_elastic_buffer #(
|
VX_elastic_buffer #(
|
||||||
.DATAW (RSP_DATAW),
|
.DATAW (RSP_DATAW),
|
||||||
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG)),
|
.SIZE (`OUT_REG_TO_EB_SIZE(OUT_REG)),
|
||||||
@@ -275,9 +336,26 @@ module VX_fpu_fpnew
|
|||||||
.valid_in (fpu_valid_out),
|
.valid_in (fpu_valid_out),
|
||||||
.ready_in (fpu_ready_out),
|
.ready_in (fpu_ready_out),
|
||||||
.data_in ({fpu_result, fpu_has_fflags_out, fpu_status, fpu_tag_out}),
|
.data_in ({fpu_result, fpu_has_fflags_out, fpu_status, fpu_tag_out}),
|
||||||
|
.data_out (fpu_rsp_data),
|
||||||
|
.valid_out (fpu_rsp_valid),
|
||||||
|
.ready_out (fpu_rsp_ready)
|
||||||
|
);
|
||||||
|
|
||||||
|
VX_stream_arb #(
|
||||||
|
.NUM_INPUTS (2),
|
||||||
|
.DATAW (RSP_DATAW),
|
||||||
|
.ARBITER ("R"),
|
||||||
|
.OUT_REG (0)
|
||||||
|
) rsp_arb (
|
||||||
|
.clk (clk),
|
||||||
|
.reset (reset),
|
||||||
|
.valid_in ({exp_rsp_valid, fpu_rsp_valid}),
|
||||||
|
.ready_in ({exp_rsp_ready, fpu_rsp_ready}),
|
||||||
|
.data_in ({exp_rsp_data, fpu_rsp_data}),
|
||||||
.data_out ({result, has_fflags, fflags, tag_out}),
|
.data_out ({result, has_fflags, fflags, tag_out}),
|
||||||
.valid_out (valid_out),
|
.valid_out (valid_out),
|
||||||
.ready_out (ready_out)
|
.ready_out (ready_out),
|
||||||
|
`UNUSED_PIN (sel_out)
|
||||||
);
|
);
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
@@ -402,6 +402,11 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// FEXP Latency
|
||||||
|
#ifndef LATENCY_FEXP
|
||||||
|
#define LATENCY_FEXP 8
|
||||||
|
#endif
|
||||||
|
|
||||||
// FCVT Latency
|
// FCVT Latency
|
||||||
#ifndef LATENCY_FCVT
|
#ifndef LATENCY_FCVT
|
||||||
#define LATENCY_FCVT 5
|
#define LATENCY_FCVT 5
|
||||||
|
|||||||
Reference in New Issue
Block a user