Compare commits
4 Commits
abee301b6e
...
331c4decaa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
331c4decaa | ||
|
|
dff1107bf5 | ||
|
|
9251ba0a24 | ||
|
|
97a1eff701 |
@@ -12,6 +12,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -37,6 +38,11 @@ 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);
|
||||||
|
int dpi_f32_max(bool enable, int a_bits, int b_bits);
|
||||||
|
int dpi_softmax_exp_acc(bool enable, int score_bits, int max_bits, int accum_bits);
|
||||||
|
int dpi_softmax_prob_to_f16x2(bool enable, int score_bits, int max_bits, int denom_bits);
|
||||||
|
int dpi_softmax_prob_to_fp8e4m3x4(bool enable, int score_bits, int max_bits, int denom_bits);
|
||||||
|
|
||||||
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 +89,89 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dpi_f32_max(bool enable, int a_bits, int b_bits) {
|
||||||
|
if (!enable)
|
||||||
|
return 0;
|
||||||
|
float a = bits_to_float(static_cast<uint32_t>(a_bits));
|
||||||
|
float b = bits_to_float(static_cast<uint32_t>(b_bits));
|
||||||
|
return static_cast<int>(float_to_bits(a > b ? a : b));
|
||||||
|
}
|
||||||
|
|
||||||
|
int dpi_softmax_exp_acc(bool enable, int score_bits, int max_bits, int accum_bits) {
|
||||||
|
if (!enable)
|
||||||
|
return 0;
|
||||||
|
float score = bits_to_float(static_cast<uint32_t>(score_bits));
|
||||||
|
float row_max = bits_to_float(static_cast<uint32_t>(max_bits));
|
||||||
|
float accum = bits_to_float(static_cast<uint32_t>(accum_bits));
|
||||||
|
return static_cast<int>(float_to_bits(accum + expf(score - row_max)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int dpi_softmax_prob_to_f16x2(bool enable, int score_bits, int max_bits, int denom_bits) {
|
||||||
|
if (!enable)
|
||||||
|
return 0;
|
||||||
|
float score = bits_to_float(static_cast<uint32_t>(score_bits));
|
||||||
|
float row_max = bits_to_float(static_cast<uint32_t>(max_bits));
|
||||||
|
float denom = bits_to_float(static_cast<uint32_t>(denom_bits));
|
||||||
|
float prob = denom == 0.0f ? 0.0f : expf(score - row_max) / denom;
|
||||||
|
half_float::half half_prob(prob);
|
||||||
|
uint16_t half_bits;
|
||||||
|
static_assert(sizeof(half_bits) == sizeof(half_prob), "unexpected half size");
|
||||||
|
__builtin_memcpy(&half_bits, &half_prob, sizeof(half_bits));
|
||||||
|
return static_cast<int>(half_bits | (uint32_t(half_bits) << 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
static float fp8e4m3_positive_to_float(uint8_t bits) {
|
||||||
|
const int exp = (bits >> 3) & 0xf;
|
||||||
|
const int frac = bits & 0x7;
|
||||||
|
if (exp == 0) {
|
||||||
|
return frac == 0 ? 0.0f : ldexpf(static_cast<float>(frac) / 8.0f, -6);
|
||||||
|
}
|
||||||
|
return ldexpf(1.0f + static_cast<float>(frac) / 8.0f, exp - 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t float_to_fp8e4m3_positive(float value) {
|
||||||
|
if (!(value > 0.0f))
|
||||||
|
return 0;
|
||||||
|
uint8_t best = 0;
|
||||||
|
float best_diff = fabsf(value);
|
||||||
|
for (uint32_t bits = 1; bits < 0x80; ++bits) {
|
||||||
|
const float candidate = fp8e4m3_positive_to_float(static_cast<uint8_t>(bits));
|
||||||
|
const float diff = fabsf(candidate - value);
|
||||||
|
if (diff < best_diff || (diff == best_diff && ((bits & 1u) == 0u))) {
|
||||||
|
best = static_cast<uint8_t>(bits);
|
||||||
|
best_diff = diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dpi_softmax_prob_to_fp8e4m3x4(bool enable, int score_bits, int max_bits, int denom_bits) {
|
||||||
|
if (!enable)
|
||||||
|
return 0;
|
||||||
|
float score = bits_to_float(static_cast<uint32_t>(score_bits));
|
||||||
|
float row_max = bits_to_float(static_cast<uint32_t>(max_bits));
|
||||||
|
float denom = bits_to_float(static_cast<uint32_t>(denom_bits));
|
||||||
|
float prob = denom == 0.0f ? 0.0f : expf(score - row_max) / denom;
|
||||||
|
uint32_t fp8 = float_to_fp8e4m3_positive(prob);
|
||||||
|
return static_cast<int>(fp8 | (fp8 << 8) | (fp8 << 16) | (fp8 << 24));
|
||||||
|
}
|
||||||
|
|
||||||
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 +262,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,11 @@ 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 int dpi_f32_max(input logic enable, input int a_bits, input int b_bits);
|
||||||
|
import "DPI-C" function int dpi_softmax_exp_acc(input logic enable, input int score_bits, input int max_bits, input int accum_bits);
|
||||||
|
import "DPI-C" function int dpi_softmax_prob_to_f16x2(input logic enable, input int score_bits, input int max_bits, input int denom_bits);
|
||||||
|
import "DPI-C" function int dpi_softmax_prob_to_fp8e4m3x4(input logic enable, input int score_bits, input int max_bits, input int denom_bits);
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -104,6 +104,15 @@ module Vortex import VX_gpu_pkg::*; #(
|
|||||||
output [NUM_TENSOR_CORES*9-1:0] tc_tmem_C_waddr,
|
output [NUM_TENSOR_CORES*9-1:0] tc_tmem_C_waddr,
|
||||||
output [NUM_TENSOR_CORES*`NUM_THREADS*`XLEN-1:0] tc_tmem_C_wdata,
|
output [NUM_TENSOR_CORES*`NUM_THREADS*`XLEN-1:0] tc_tmem_C_wdata,
|
||||||
output [NUM_TENSOR_CORES*`NUM_THREADS*`XLEN/8-1:0] tc_tmem_C_mask,
|
output [NUM_TENSOR_CORES*`NUM_THREADS*`XLEN/8-1:0] tc_tmem_C_mask,
|
||||||
|
output sc_tmem_ren,
|
||||||
|
input sc_tmem_rready,
|
||||||
|
output [8:0] sc_tmem_raddr,
|
||||||
|
input [`NUM_THREADS*`XLEN-1:0] sc_tmem_rdata,
|
||||||
|
output sc_tmem_wen,
|
||||||
|
input sc_tmem_wready,
|
||||||
|
output [8:0] sc_tmem_waddr,
|
||||||
|
output [`NUM_THREADS*`XLEN-1:0] sc_tmem_wdata,
|
||||||
|
output [`NUM_THREADS*`XLEN/8-1:0] sc_tmem_mask,
|
||||||
|
|
||||||
// gbar ------------------------------------------------
|
// gbar ------------------------------------------------
|
||||||
|
|
||||||
@@ -514,6 +523,15 @@ module Vortex import VX_gpu_pkg::*; #(
|
|||||||
.tensor_tmem_C_waddr(tc_tmem_C_waddr),
|
.tensor_tmem_C_waddr(tc_tmem_C_waddr),
|
||||||
.tensor_tmem_C_wdata(tc_tmem_C_wdata),
|
.tensor_tmem_C_wdata(tc_tmem_C_wdata),
|
||||||
.tensor_tmem_C_mask(tc_tmem_C_mask),
|
.tensor_tmem_C_mask(tc_tmem_C_mask),
|
||||||
|
.scalar_tmem_ren(sc_tmem_ren),
|
||||||
|
.scalar_tmem_rready(sc_tmem_rready),
|
||||||
|
.scalar_tmem_raddr(sc_tmem_raddr),
|
||||||
|
.scalar_tmem_rdata(sc_tmem_rdata),
|
||||||
|
.scalar_tmem_wen(sc_tmem_wen),
|
||||||
|
.scalar_tmem_wready(sc_tmem_wready),
|
||||||
|
.scalar_tmem_waddr(sc_tmem_waddr),
|
||||||
|
.scalar_tmem_wdata(sc_tmem_wdata),
|
||||||
|
.scalar_tmem_mask(sc_tmem_mask),
|
||||||
.tensor_smem_B_if (tc_p2_bus_if),
|
.tensor_smem_B_if (tc_p2_bus_if),
|
||||||
`else
|
`else
|
||||||
.tensor_tmem_A_ren(tc_tmem_A_ren),
|
.tensor_tmem_A_ren(tc_tmem_A_ren),
|
||||||
@@ -529,6 +547,15 @@ module Vortex import VX_gpu_pkg::*; #(
|
|||||||
.tensor_tmem_C_waddr(tc_tmem_C_waddr),
|
.tensor_tmem_C_waddr(tc_tmem_C_waddr),
|
||||||
.tensor_tmem_C_wdata(tc_tmem_C_wdata),
|
.tensor_tmem_C_wdata(tc_tmem_C_wdata),
|
||||||
.tensor_tmem_C_mask(tc_tmem_C_mask),
|
.tensor_tmem_C_mask(tc_tmem_C_mask),
|
||||||
|
.scalar_tmem_ren(sc_tmem_ren),
|
||||||
|
.scalar_tmem_rready(sc_tmem_rready),
|
||||||
|
.scalar_tmem_raddr(sc_tmem_raddr),
|
||||||
|
.scalar_tmem_rdata(sc_tmem_rdata),
|
||||||
|
.scalar_tmem_wen(sc_tmem_wen),
|
||||||
|
.scalar_tmem_wready(sc_tmem_wready),
|
||||||
|
.scalar_tmem_waddr(sc_tmem_waddr),
|
||||||
|
.scalar_tmem_wdata(sc_tmem_wdata),
|
||||||
|
.scalar_tmem_mask(sc_tmem_mask),
|
||||||
.tensor_smem_B_if (tc_p2_bus_if),
|
.tensor_smem_B_if (tc_p2_bus_if),
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
|
|||||||
@@ -206,9 +206,12 @@
|
|||||||
`define INST_LSU_LWU 4'b0110 // new for RV64I LWU
|
`define INST_LSU_LWU 4'b0110 // new for RV64I LWU
|
||||||
`define INST_LSU_SB 4'b1000
|
`define INST_LSU_SB 4'b1000
|
||||||
`define INST_LSU_SH 4'b1001
|
`define INST_LSU_SH 4'b1001
|
||||||
`define INST_LSU_SW 4'b1010
|
`define INST_LSU_SW 4'b1010
|
||||||
`define INST_LSU_SD 4'b1011 // new for RV64I SD
|
`define INST_LSU_SD 4'b1011 // new for RV64I SD
|
||||||
`define INST_LSU_FENCE 4'b1111
|
`define INST_LSU_TMEM_LD 4'b1100
|
||||||
|
`define INST_LSU_TMEM_ST 4'b1101
|
||||||
|
`define INST_LSU_TMEM_SOFTMAX 4'b1110
|
||||||
|
`define INST_LSU_FENCE 4'b1111
|
||||||
`define INST_LSU_BITS 4
|
`define INST_LSU_BITS 4
|
||||||
`define INST_LSU_FMT(op) op[2:0]
|
`define INST_LSU_FMT(op) op[2:0]
|
||||||
`define INST_LSU_WSIZE(op) op[1:0]
|
`define INST_LSU_WSIZE(op) op[1:0]
|
||||||
@@ -225,7 +228,7 @@
|
|||||||
`define INST_FPU_SQRT 4'b0100
|
`define INST_FPU_SQRT 4'b0100
|
||||||
`define INST_FPU_CMP 4'b0101 // mod: LE=0, LT=1, EQ=2
|
`define INST_FPU_CMP 4'b0101 // mod: LE=0, LT=1, EQ=2
|
||||||
`define INST_FPU_F2F 4'b0110
|
`define INST_FPU_F2F 4'b0110
|
||||||
`define INST_FPU_MISC 4'b0111 // mod: SGNJ=0, SGNJN=1, SGNJX=2, CLASS=3, MVXW=4, MVWX=5, FMIN=6, FMAX=7
|
`define INST_FPU_MISC 4'b0111 // mod: SGNJ=0, SGNJN=1, SGNJX=2, CLASS=3, MVXW=4, MVWX=5, FMIN=6, FMAX=7
|
||||||
`define INST_FPU_F2I 4'b1000
|
`define INST_FPU_F2I 4'b1000
|
||||||
`define INST_FPU_F2U 4'b1001
|
`define INST_FPU_F2U 4'b1001
|
||||||
`define INST_FPU_I2F 4'b1010
|
`define INST_FPU_I2F 4'b1010
|
||||||
@@ -234,10 +237,11 @@
|
|||||||
`define INST_FPU_MSUB 4'b1101
|
`define INST_FPU_MSUB 4'b1101
|
||||||
`define INST_FPU_NMSUB 4'b1110
|
`define INST_FPU_NMSUB 4'b1110
|
||||||
`define INST_FPU_NMADD 4'b1111
|
`define INST_FPU_NMADD 4'b1111
|
||||||
`define INST_FPU_BITS 4
|
`define INST_FPU_BITS 4
|
||||||
`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
|
||||||
|
|||||||
@@ -54,6 +54,15 @@ module VX_core import VX_gpu_pkg::*; #(
|
|||||||
output logic [NUM_TENSOR_CORES*9-1:0] tensor_tmem_C_waddr,
|
output logic [NUM_TENSOR_CORES*9-1:0] tensor_tmem_C_waddr,
|
||||||
output logic [NUM_TENSOR_CORES*`NUM_THREADS*`XLEN-1:0] tensor_tmem_C_wdata,
|
output logic [NUM_TENSOR_CORES*`NUM_THREADS*`XLEN-1:0] tensor_tmem_C_wdata,
|
||||||
output logic [NUM_TENSOR_CORES*`NUM_THREADS*`XLEN/8-1:0] tensor_tmem_C_mask,
|
output logic [NUM_TENSOR_CORES*`NUM_THREADS*`XLEN/8-1:0] tensor_tmem_C_mask,
|
||||||
|
output logic scalar_tmem_ren,
|
||||||
|
input logic scalar_tmem_rready,
|
||||||
|
output logic [8:0] scalar_tmem_raddr,
|
||||||
|
input logic [`NUM_THREADS*`XLEN-1:0] scalar_tmem_rdata,
|
||||||
|
output logic scalar_tmem_wen,
|
||||||
|
input logic scalar_tmem_wready,
|
||||||
|
output logic [8:0] scalar_tmem_waddr,
|
||||||
|
output logic [`NUM_THREADS*`XLEN-1:0] scalar_tmem_wdata,
|
||||||
|
output logic [`NUM_THREADS*`XLEN/8-1:0] scalar_tmem_mask,
|
||||||
VX_tc_bus_if.master tensor_smem_B_if[NUM_TENSOR_CORES],
|
VX_tc_bus_if.master tensor_smem_B_if[NUM_TENSOR_CORES],
|
||||||
|
|
||||||
`ifdef GBAR_ENABLE
|
`ifdef GBAR_ENABLE
|
||||||
@@ -410,7 +419,16 @@ module VX_core import VX_gpu_pkg::*; #(
|
|||||||
.tensor_tmem_C_waddr(tensor_tmem_C_waddr),
|
.tensor_tmem_C_waddr(tensor_tmem_C_waddr),
|
||||||
.tensor_tmem_C_wdata(tensor_tmem_C_wdata),
|
.tensor_tmem_C_wdata(tensor_tmem_C_wdata),
|
||||||
.tensor_tmem_C_mask(tensor_tmem_C_mask),
|
.tensor_tmem_C_mask(tensor_tmem_C_mask),
|
||||||
.tensor_smem_B_if (tensor_smem_B_if),
|
.scalar_tmem_ren(scalar_tmem_ren),
|
||||||
|
.scalar_tmem_rready(scalar_tmem_rready),
|
||||||
|
.scalar_tmem_raddr(scalar_tmem_raddr),
|
||||||
|
.scalar_tmem_rdata(scalar_tmem_rdata),
|
||||||
|
.scalar_tmem_wen(scalar_tmem_wen),
|
||||||
|
.scalar_tmem_wready(scalar_tmem_wready),
|
||||||
|
.scalar_tmem_waddr(scalar_tmem_waddr),
|
||||||
|
.scalar_tmem_wdata(scalar_tmem_wdata),
|
||||||
|
.scalar_tmem_mask(scalar_tmem_mask),
|
||||||
|
.tensor_smem_B_if (tensor_smem_B_if),
|
||||||
`endif
|
`endif
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
|
|||||||
@@ -508,9 +508,24 @@ module VX_decode #(
|
|||||||
end
|
end
|
||||||
`INST_EXT2: begin
|
`INST_EXT2: begin
|
||||||
case (func3)
|
case (func3)
|
||||||
|
3'h0: begin
|
||||||
|
if (func7 == 7'h30) begin
|
||||||
|
ex_type = `EX_LSU;
|
||||||
|
op_type = `INST_LSU_TMEM_LD;
|
||||||
|
use_rd = 1;
|
||||||
|
`USED_IREG (rd);
|
||||||
|
`USED_IREG (rs1);
|
||||||
|
end
|
||||||
|
end
|
||||||
3'h1: begin
|
3'h1: begin
|
||||||
case (func2)
|
if (func7 == 7'h30) begin
|
||||||
2'h0: begin // CMOV
|
ex_type = `EX_LSU;
|
||||||
|
op_type = `INST_LSU_TMEM_ST;
|
||||||
|
`USED_IREG (rs1);
|
||||||
|
`USED_IREG (rs2);
|
||||||
|
end else begin
|
||||||
|
case (func2)
|
||||||
|
2'h0: begin // CMOV
|
||||||
ex_type = `EX_SFU;
|
ex_type = `EX_SFU;
|
||||||
op_type = `INST_OP_BITS'(`INST_SFU_CMOV);
|
op_type = `INST_OP_BITS'(`INST_SFU_CMOV);
|
||||||
use_rd = 1;
|
use_rd = 1;
|
||||||
@@ -518,9 +533,32 @@ module VX_decode #(
|
|||||||
`USED_IREG (rs1);
|
`USED_IREG (rs1);
|
||||||
`USED_IREG (rs2);
|
`USED_IREG (rs2);
|
||||||
`USED_IREG (rs3);
|
`USED_IREG (rs3);
|
||||||
end
|
end
|
||||||
default:;
|
default:;
|
||||||
endcase
|
endcase
|
||||||
|
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
|
||||||
|
3'h3: begin
|
||||||
|
if (func7 == 7'h30) begin
|
||||||
|
ex_type = `EX_LSU;
|
||||||
|
op_type = `INST_LSU_TMEM_SOFTMAX;
|
||||||
|
use_rd = 1;
|
||||||
|
`USED_IREG (rd);
|
||||||
|
`USED_IREG (rs1);
|
||||||
|
`USED_IREG (rs2);
|
||||||
|
end
|
||||||
end
|
end
|
||||||
default:;
|
default:;
|
||||||
endcase
|
endcase
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
`include "VX_define.vh"
|
`include "VX_define.vh"
|
||||||
|
`ifdef SV_DPI
|
||||||
|
`include "float_dpi.vh"
|
||||||
|
`endif
|
||||||
|
|
||||||
module VX_execute import VX_gpu_pkg::*; #(
|
module VX_execute import VX_gpu_pkg::*; #(
|
||||||
parameter CORE_ID = 0,
|
parameter CORE_ID = 0,
|
||||||
@@ -92,6 +95,16 @@ module VX_execute import VX_gpu_pkg::*; #(
|
|||||||
`endif
|
`endif
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
|
output logic scalar_tmem_ren,
|
||||||
|
input logic scalar_tmem_rready,
|
||||||
|
output logic [8:0] scalar_tmem_raddr,
|
||||||
|
input logic [`NUM_THREADS*`XLEN-1:0] scalar_tmem_rdata,
|
||||||
|
output logic scalar_tmem_wen,
|
||||||
|
input logic scalar_tmem_wready,
|
||||||
|
output logic [8:0] scalar_tmem_waddr,
|
||||||
|
output logic [`NUM_THREADS*`XLEN-1:0] scalar_tmem_wdata,
|
||||||
|
output logic [`NUM_THREADS*`XLEN/8-1:0] scalar_tmem_mask,
|
||||||
|
|
||||||
// simulation helper signals
|
// simulation helper signals
|
||||||
output wire sim_ebreak,
|
output wire sim_ebreak,
|
||||||
|
|
||||||
@@ -286,8 +299,39 @@ module VX_execute import VX_gpu_pkg::*; #(
|
|||||||
|
|
||||||
`SCOPE_IO_SWITCH (1)
|
`SCOPE_IO_SWITCH (1)
|
||||||
|
|
||||||
|
VX_dispatch_if scalar_mem_lsu_dispatch_if[`ISSUE_WIDTH]();
|
||||||
|
VX_commit_if scalar_mem_lsu_commit_if[`ISSUE_WIDTH]();
|
||||||
|
VX_commit_if scalar_tmem_commit_if[`ISSUE_WIDTH]();
|
||||||
VX_commit_if lsu_scalar_commit_if[`ISSUE_WIDTH]();
|
VX_commit_if lsu_scalar_commit_if[`ISSUE_WIDTH]();
|
||||||
|
|
||||||
|
wire [`ISSUE_WIDTH-1:0] scalar_tmem_dispatch;
|
||||||
|
wire [`ISSUE_WIDTH-1:0] scalar_tmem_ld_dispatch;
|
||||||
|
wire [`ISSUE_WIDTH-1:0] scalar_tmem_st_dispatch;
|
||||||
|
wire [`ISSUE_WIDTH-1:0] scalar_tmem_softmax_dispatch;
|
||||||
|
wire [`ISSUE_WIDTH-1:0] scalar_tmem_dispatch_ready;
|
||||||
|
wire [`ISSUE_WIDTH-1:0] scalar_tmem_dispatch_fire;
|
||||||
|
wire [`ISSUE_WIDTH-1:0] scalar_tmem_commit_ready;
|
||||||
|
`UNUSED_VAR (scalar_tmem_dispatch_fire)
|
||||||
|
|
||||||
|
for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin : g_scalar_lsu_split
|
||||||
|
assign scalar_tmem_ld_dispatch[i] = lsu_dispatch_if[i].valid
|
||||||
|
&& (lsu_dispatch_if[i].data.op_type == `INST_LSU_TMEM_LD);
|
||||||
|
assign scalar_tmem_st_dispatch[i] = lsu_dispatch_if[i].valid
|
||||||
|
&& (lsu_dispatch_if[i].data.op_type == `INST_LSU_TMEM_ST);
|
||||||
|
assign scalar_tmem_softmax_dispatch[i] = lsu_dispatch_if[i].valid
|
||||||
|
&& (lsu_dispatch_if[i].data.op_type == `INST_LSU_TMEM_SOFTMAX);
|
||||||
|
assign scalar_tmem_dispatch[i] = scalar_tmem_ld_dispatch[i]
|
||||||
|
|| scalar_tmem_st_dispatch[i]
|
||||||
|
|| scalar_tmem_softmax_dispatch[i];
|
||||||
|
|
||||||
|
assign scalar_mem_lsu_dispatch_if[i].valid = lsu_dispatch_if[i].valid && !scalar_tmem_dispatch[i];
|
||||||
|
assign scalar_mem_lsu_dispatch_if[i].data = lsu_dispatch_if[i].data;
|
||||||
|
assign lsu_dispatch_if[i].ready = scalar_tmem_dispatch[i] ? scalar_tmem_dispatch_ready[i]
|
||||||
|
: scalar_mem_lsu_dispatch_if[i].ready;
|
||||||
|
|
||||||
|
assign scalar_tmem_dispatch_fire[i] = scalar_tmem_dispatch[i] && scalar_tmem_dispatch_ready[i];
|
||||||
|
end
|
||||||
|
|
||||||
VX_mem_bus_if #(
|
VX_mem_bus_if #(
|
||||||
.DATA_SIZE (DCACHE_WORD_SIZE),
|
.DATA_SIZE (DCACHE_WORD_SIZE),
|
||||||
.TAG_WIDTH (DCACHE_TAG_WIDTH)
|
.TAG_WIDTH (DCACHE_TAG_WIDTH)
|
||||||
@@ -301,10 +345,300 @@ module VX_execute import VX_gpu_pkg::*; #(
|
|||||||
.reset (lsu_reset),
|
.reset (lsu_reset),
|
||||||
.downstream_mem_busy (downstream_mem_busy),
|
.downstream_mem_busy (downstream_mem_busy),
|
||||||
.cache_bus_if (scalar_lsu_bus_if),
|
.cache_bus_if (scalar_lsu_bus_if),
|
||||||
.dispatch_if (lsu_dispatch_if),
|
.dispatch_if (scalar_mem_lsu_dispatch_if),
|
||||||
.commit_if (lsu_scalar_commit_if)
|
.commit_if (scalar_mem_lsu_commit_if)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
wire scalar_tmem_pending;
|
||||||
|
reg [`ISSUE_WIDTH-1:0] scalar_tmem_grant;
|
||||||
|
reg [`ISSUE_WIDTH-1:0] scalar_tmem_grant_r;
|
||||||
|
reg scalar_tmem_load_pending;
|
||||||
|
reg scalar_tmem_store_pending;
|
||||||
|
reg scalar_tmem_commit_pending;
|
||||||
|
reg scalar_tmem_softmax_active;
|
||||||
|
reg [5:0] scalar_tmem_softmax_read_index;
|
||||||
|
reg scalar_tmem_softmax_reads_issued;
|
||||||
|
reg scalar_tmem_softmax_read_response_valid;
|
||||||
|
reg [5:0] scalar_tmem_softmax_read_response_index;
|
||||||
|
reg [8:0] scalar_tmem_softmax_score_base_r;
|
||||||
|
reg [8:0] scalar_tmem_softmax_p_base_r;
|
||||||
|
reg [`UUID_WIDTH-1:0] scalar_tmem_uuid_r;
|
||||||
|
reg [`NW_WIDTH-1:0] scalar_tmem_wid_r;
|
||||||
|
reg [`NUM_THREADS-1:0] scalar_tmem_tmask_r;
|
||||||
|
reg [`XLEN-1:0] scalar_tmem_pc_r;
|
||||||
|
reg [`NR_BITS-1:0] scalar_tmem_rd_r;
|
||||||
|
reg [`NUM_THREADS*`XLEN-1:0] scalar_tmem_rdata_r;
|
||||||
|
reg scalar_tmem_rdata_valid_r;
|
||||||
|
wire [`ISSUE_WIDTH-1:0][8:0] scalar_tmem_req_addr;
|
||||||
|
wire [`ISSUE_WIDTH-1:0][`NUM_THREADS*`XLEN-1:0] scalar_tmem_req_wdata;
|
||||||
|
wire [`ISSUE_WIDTH-1:0][`UUID_WIDTH-1:0] scalar_tmem_req_uuid;
|
||||||
|
wire [`ISSUE_WIDTH-1:0][`NW_WIDTH-1:0] scalar_tmem_req_wid;
|
||||||
|
wire [`ISSUE_WIDTH-1:0][`NUM_THREADS-1:0] scalar_tmem_req_tmask;
|
||||||
|
wire [`ISSUE_WIDTH-1:0][`XLEN-1:0] scalar_tmem_req_pc;
|
||||||
|
wire [`ISSUE_WIDTH-1:0][`NR_BITS-1:0] scalar_tmem_req_rd;
|
||||||
|
wire [`ISSUE_WIDTH-1:0][8:0] scalar_tmem_req_softmax_p_addr;
|
||||||
|
|
||||||
|
localparam [5:0] SCALAR_TMEM_SOFTMAX_ROW_LAST = 6'd31;
|
||||||
|
localparam [5:0] SCALAR_TMEM_SOFTMAX_TILE_LAST = 6'd63;
|
||||||
|
|
||||||
|
assign scalar_tmem_pending = |scalar_tmem_dispatch;
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
scalar_tmem_grant = '0;
|
||||||
|
for (integer i = `ISSUE_WIDTH-1; i >= 0; --i) begin
|
||||||
|
if (scalar_tmem_dispatch[i]) begin
|
||||||
|
scalar_tmem_grant = '0;
|
||||||
|
scalar_tmem_grant[i] = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
wire scalar_tmem_grant_valid = scalar_tmem_pending && !scalar_tmem_load_pending
|
||||||
|
&& !scalar_tmem_store_pending && !scalar_tmem_commit_pending
|
||||||
|
&& !scalar_tmem_softmax_active;
|
||||||
|
wire scalar_tmem_grant_is_load = |(scalar_tmem_grant & scalar_tmem_ld_dispatch);
|
||||||
|
wire scalar_tmem_grant_is_store = |(scalar_tmem_grant & scalar_tmem_st_dispatch);
|
||||||
|
wire scalar_tmem_grant_is_softmax = |(scalar_tmem_grant & scalar_tmem_softmax_dispatch);
|
||||||
|
wire scalar_tmem_req_ready = scalar_tmem_grant_is_softmax ? 1'b1 :
|
||||||
|
scalar_tmem_grant_is_load ? scalar_tmem_rready : scalar_tmem_wready;
|
||||||
|
wire scalar_tmem_req_fire = scalar_tmem_grant_valid && scalar_tmem_req_ready;
|
||||||
|
wire scalar_tmem_softmax_read_valid = scalar_tmem_softmax_active
|
||||||
|
&& !scalar_tmem_softmax_reads_issued;
|
||||||
|
wire scalar_tmem_softmax_read_issue = scalar_tmem_softmax_read_valid && scalar_tmem_rready;
|
||||||
|
wire [8:0] scalar_tmem_softmax_read_addr = scalar_tmem_softmax_score_base_r
|
||||||
|
+ 9'(scalar_tmem_softmax_read_index[4:0]);
|
||||||
|
|
||||||
|
wire scalar_tmem_softmax_vector_busy;
|
||||||
|
wire scalar_tmem_softmax_vector_out_valid;
|
||||||
|
wire [5:0] scalar_tmem_softmax_vector_out_index;
|
||||||
|
wire [`NUM_THREADS*`XLEN-1:0] scalar_tmem_softmax_vector_out_data;
|
||||||
|
wire scalar_tmem_softmax_vector_done;
|
||||||
|
wire scalar_tmem_softmax_vector_out_ready = scalar_tmem_softmax_active && scalar_tmem_wready;
|
||||||
|
wire scalar_tmem_softmax_write_valid = scalar_tmem_softmax_active
|
||||||
|
&& scalar_tmem_softmax_vector_out_valid;
|
||||||
|
wire scalar_tmem_softmax_write_issue = scalar_tmem_softmax_write_valid && scalar_tmem_wready;
|
||||||
|
wire [8:0] scalar_tmem_softmax_write_addr = scalar_tmem_softmax_p_base_r
|
||||||
|
+ 9'(scalar_tmem_softmax_vector_out_index);
|
||||||
|
wire [`NUM_THREADS*`XLEN-1:0] scalar_tmem_softmax_wdata =
|
||||||
|
scalar_tmem_softmax_vector_out_data;
|
||||||
|
wire scalar_tmem_softmax_commit = scalar_tmem_commit_pending
|
||||||
|
&& !scalar_tmem_load_pending
|
||||||
|
&& !scalar_tmem_store_pending;
|
||||||
|
wire [`XLEN-1:0] scalar_tmem_softmax_token = `XLEN'(scalar_tmem_softmax_p_base_r);
|
||||||
|
|
||||||
|
VX_tmem_softmax_unit #(
|
||||||
|
.NUM_LANES (`NUM_THREADS),
|
||||||
|
.ROW_SIZE (32)
|
||||||
|
) tmem_softmax_unit (
|
||||||
|
.clk (clk),
|
||||||
|
.reset (reset),
|
||||||
|
.start (scalar_tmem_req_fire && scalar_tmem_grant_is_softmax),
|
||||||
|
.load_valid (scalar_tmem_softmax_read_response_valid),
|
||||||
|
.load_data (scalar_tmem_rdata),
|
||||||
|
.load_last (scalar_tmem_softmax_read_response_index == SCALAR_TMEM_SOFTMAX_ROW_LAST),
|
||||||
|
.busy (scalar_tmem_softmax_vector_busy),
|
||||||
|
.out_valid (scalar_tmem_softmax_vector_out_valid),
|
||||||
|
.out_ready (scalar_tmem_softmax_vector_out_ready),
|
||||||
|
.out_index (scalar_tmem_softmax_vector_out_index),
|
||||||
|
.out_data (scalar_tmem_softmax_vector_out_data),
|
||||||
|
.done (scalar_tmem_softmax_vector_done)
|
||||||
|
);
|
||||||
|
`UNUSED_VAR (scalar_tmem_softmax_vector_busy)
|
||||||
|
|
||||||
|
for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin : g_scalar_tmem_ready
|
||||||
|
assign scalar_tmem_dispatch_ready[i] = scalar_tmem_grant_valid && scalar_tmem_grant[i] && scalar_tmem_req_ready;
|
||||||
|
assign scalar_tmem_req_addr[i] = lsu_dispatch_if[i].data.rs1_data[0][8:0];
|
||||||
|
assign scalar_tmem_req_wdata[i] = lsu_dispatch_if[i].data.rs2_data;
|
||||||
|
assign scalar_tmem_req_uuid[i] = lsu_dispatch_if[i].data.uuid;
|
||||||
|
assign scalar_tmem_req_wid[i] = wis_to_wid(lsu_dispatch_if[i].data.wis, ISSUE_ISW_W'(i));
|
||||||
|
assign scalar_tmem_req_tmask[i] = lsu_dispatch_if[i].data.tmask;
|
||||||
|
assign scalar_tmem_req_pc[i] = lsu_dispatch_if[i].data.PC;
|
||||||
|
assign scalar_tmem_req_rd[i] = lsu_dispatch_if[i].data.rd;
|
||||||
|
assign scalar_tmem_req_softmax_p_addr[i] = lsu_dispatch_if[i].data.rs2_data[0][8:0];
|
||||||
|
|
||||||
|
assign scalar_tmem_commit_if[i].valid = scalar_tmem_commit_pending && scalar_tmem_grant_r[i];
|
||||||
|
assign scalar_tmem_commit_if[i].data.uuid = scalar_tmem_uuid_r;
|
||||||
|
assign scalar_tmem_commit_if[i].data.wid = scalar_tmem_wid_r;
|
||||||
|
assign scalar_tmem_commit_if[i].data.tmask = scalar_tmem_tmask_r;
|
||||||
|
assign scalar_tmem_commit_if[i].data.PC = scalar_tmem_pc_r;
|
||||||
|
assign scalar_tmem_commit_if[i].data.wb = scalar_tmem_load_pending || scalar_tmem_softmax_commit;
|
||||||
|
assign scalar_tmem_commit_if[i].data.rd = (scalar_tmem_load_pending || scalar_tmem_softmax_commit) ? scalar_tmem_rd_r : '0;
|
||||||
|
assign scalar_tmem_commit_if[i].data.data =
|
||||||
|
scalar_tmem_load_pending
|
||||||
|
? (scalar_tmem_rdata_valid_r ? scalar_tmem_rdata_r : scalar_tmem_rdata)
|
||||||
|
: {`NUM_THREADS{scalar_tmem_softmax_token}};
|
||||||
|
assign scalar_tmem_commit_if[i].data.tensor = 1'b0;
|
||||||
|
assign scalar_tmem_commit_if[i].data.pid = '0;
|
||||||
|
assign scalar_tmem_commit_if[i].data.sop = 1'b1;
|
||||||
|
assign scalar_tmem_commit_if[i].data.eop = 1'b1;
|
||||||
|
assign scalar_tmem_commit_ready[i] = scalar_tmem_commit_if[i].ready;
|
||||||
|
end
|
||||||
|
|
||||||
|
function automatic [`NUM_THREADS*`XLEN/8-1:0] scalar_tmem_expand_tmask;
|
||||||
|
input [`NUM_THREADS-1:0] tmask;
|
||||||
|
begin
|
||||||
|
scalar_tmem_expand_tmask = '0;
|
||||||
|
for (integer lane = 0; lane < `NUM_THREADS; ++lane) begin
|
||||||
|
scalar_tmem_expand_tmask[lane * (`XLEN / 8) +: (`XLEN / 8)] =
|
||||||
|
{(`XLEN / 8){tmask[lane]}};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
`ifdef DBG_TRACE_CORE_PIPELINE_VCS
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (!reset && ($time > `TRACE_STARTTIME) && (CORE_ID == 0)) begin
|
||||||
|
if (scalar_tmem_req_fire && scalar_tmem_grant_is_softmax) begin
|
||||||
|
`TRACE(1, ("%d: core%0d-scalar-tmem-softmax-start: grant=%b wid=%0d PC=0x%0h rd=%0d score=%0d prob=%0d tmask=%b (#%0d)\n",
|
||||||
|
$time, CORE_ID, scalar_tmem_grant, scalar_tmem_req_wid[0], scalar_tmem_req_pc[0],
|
||||||
|
scalar_tmem_req_rd[0], scalar_tmem_req_addr[0], scalar_tmem_req_softmax_p_addr[0],
|
||||||
|
scalar_tmem_req_tmask[0], scalar_tmem_req_uuid[0]));
|
||||||
|
end
|
||||||
|
if (scalar_tmem_softmax_read_issue && (scalar_tmem_softmax_read_index == 6'd0 || scalar_tmem_softmax_read_index == SCALAR_TMEM_SOFTMAX_ROW_LAST)) begin
|
||||||
|
`TRACE(1, ("%d: core%0d-scalar-tmem-softmax-read: index=%0d addr=%0d rready=%b PC=0x%0h rd=%0d\n",
|
||||||
|
$time, CORE_ID, scalar_tmem_softmax_read_index,
|
||||||
|
scalar_tmem_softmax_read_addr, scalar_tmem_rready, scalar_tmem_pc_r, scalar_tmem_rd_r));
|
||||||
|
end
|
||||||
|
if (scalar_tmem_softmax_write_issue && (scalar_tmem_softmax_vector_out_index == 6'd0 || scalar_tmem_softmax_vector_out_index == SCALAR_TMEM_SOFTMAX_TILE_LAST)) begin
|
||||||
|
`TRACE(1, ("%d: core%0d-scalar-tmem-softmax-write: index=%0d addr=%0d wready=%b PC=0x%0h rd=%0d\n",
|
||||||
|
$time, CORE_ID, scalar_tmem_softmax_vector_out_index, scalar_tmem_softmax_write_addr,
|
||||||
|
scalar_tmem_wready, scalar_tmem_pc_r, scalar_tmem_rd_r));
|
||||||
|
end
|
||||||
|
if (scalar_tmem_commit_pending && scalar_tmem_pc_r == 32'h80000318) begin
|
||||||
|
`TRACE(1, ("%d: core%0d-scalar-tmem-softmax-commit-pending: grant_r=%b ready=%b valid0=%b wb0=%0d rd=%0d PC=0x%0h token=0x%0h\n",
|
||||||
|
$time, CORE_ID, scalar_tmem_grant_r, scalar_tmem_commit_ready,
|
||||||
|
scalar_tmem_commit_if[0].valid, scalar_tmem_commit_if[0].data.wb,
|
||||||
|
scalar_tmem_commit_if[0].data.rd, scalar_tmem_commit_if[0].data.PC,
|
||||||
|
scalar_tmem_softmax_token));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
`endif
|
||||||
|
|
||||||
|
always @(*) begin
|
||||||
|
scalar_tmem_ren = (scalar_tmem_grant_valid && scalar_tmem_grant_is_load)
|
||||||
|
|| scalar_tmem_softmax_read_valid;
|
||||||
|
scalar_tmem_wen = (scalar_tmem_grant_valid && scalar_tmem_grant_is_store)
|
||||||
|
|| scalar_tmem_softmax_write_valid;
|
||||||
|
scalar_tmem_raddr = '0;
|
||||||
|
scalar_tmem_waddr = '0;
|
||||||
|
scalar_tmem_wdata = '0;
|
||||||
|
scalar_tmem_mask = '0;
|
||||||
|
for (integer i = 0; i < `ISSUE_WIDTH; ++i) begin
|
||||||
|
if (scalar_tmem_grant[i]) begin
|
||||||
|
scalar_tmem_raddr = scalar_tmem_req_addr[i];
|
||||||
|
scalar_tmem_waddr = scalar_tmem_req_addr[i];
|
||||||
|
scalar_tmem_wdata = scalar_tmem_req_wdata[i];
|
||||||
|
scalar_tmem_mask = scalar_tmem_expand_tmask(scalar_tmem_req_tmask[i])
|
||||||
|
& {(`NUM_THREADS * (`XLEN / 8)){scalar_tmem_grant_is_store}};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if (scalar_tmem_softmax_read_valid) begin
|
||||||
|
scalar_tmem_raddr = scalar_tmem_softmax_read_addr;
|
||||||
|
end
|
||||||
|
if (scalar_tmem_softmax_write_valid) begin
|
||||||
|
scalar_tmem_waddr = scalar_tmem_softmax_write_addr;
|
||||||
|
scalar_tmem_wdata = scalar_tmem_softmax_wdata;
|
||||||
|
scalar_tmem_mask = scalar_tmem_expand_tmask(scalar_tmem_tmask_r);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (reset) begin
|
||||||
|
scalar_tmem_grant_r <= '0;
|
||||||
|
scalar_tmem_load_pending <= 1'b0;
|
||||||
|
scalar_tmem_store_pending <= 1'b0;
|
||||||
|
scalar_tmem_commit_pending <= 1'b0;
|
||||||
|
scalar_tmem_softmax_active <= 1'b0;
|
||||||
|
scalar_tmem_softmax_read_index <= '0;
|
||||||
|
scalar_tmem_softmax_reads_issued <= 1'b0;
|
||||||
|
scalar_tmem_softmax_read_response_valid <= 1'b0;
|
||||||
|
scalar_tmem_softmax_read_response_index <= '0;
|
||||||
|
scalar_tmem_softmax_score_base_r <= '0;
|
||||||
|
scalar_tmem_softmax_p_base_r <= '0;
|
||||||
|
scalar_tmem_uuid_r <= '0;
|
||||||
|
scalar_tmem_wid_r <= '0;
|
||||||
|
scalar_tmem_tmask_r <= '0;
|
||||||
|
scalar_tmem_pc_r <= '0;
|
||||||
|
scalar_tmem_rd_r <= '0;
|
||||||
|
scalar_tmem_rdata_r <= '0;
|
||||||
|
scalar_tmem_rdata_valid_r <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
if (scalar_tmem_req_fire) begin
|
||||||
|
scalar_tmem_grant_r <= scalar_tmem_grant;
|
||||||
|
scalar_tmem_load_pending <= scalar_tmem_grant_is_load;
|
||||||
|
scalar_tmem_store_pending <= scalar_tmem_grant_is_store;
|
||||||
|
scalar_tmem_commit_pending <= !scalar_tmem_grant_is_softmax;
|
||||||
|
scalar_tmem_rdata_valid_r <= 1'b0;
|
||||||
|
for (integer i = 0; i < `ISSUE_WIDTH; ++i) begin
|
||||||
|
if (scalar_tmem_grant[i]) begin
|
||||||
|
scalar_tmem_uuid_r <= scalar_tmem_req_uuid[i];
|
||||||
|
scalar_tmem_wid_r <= scalar_tmem_req_wid[i];
|
||||||
|
scalar_tmem_tmask_r <= scalar_tmem_req_tmask[i];
|
||||||
|
scalar_tmem_pc_r <= scalar_tmem_req_pc[i];
|
||||||
|
scalar_tmem_rd_r <= scalar_tmem_req_rd[i];
|
||||||
|
if (scalar_tmem_grant_is_softmax) begin
|
||||||
|
scalar_tmem_softmax_active <= 1'b1;
|
||||||
|
scalar_tmem_softmax_read_index <= '0;
|
||||||
|
scalar_tmem_softmax_reads_issued <= 1'b0;
|
||||||
|
scalar_tmem_softmax_read_response_valid <= 1'b0;
|
||||||
|
scalar_tmem_softmax_read_response_index <= '0;
|
||||||
|
scalar_tmem_softmax_score_base_r <= scalar_tmem_req_addr[i];
|
||||||
|
scalar_tmem_softmax_p_base_r <= scalar_tmem_req_softmax_p_addr[i];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end else if (scalar_tmem_load_pending && scalar_tmem_commit_pending && !scalar_tmem_rdata_valid_r) begin
|
||||||
|
scalar_tmem_rdata_r <= scalar_tmem_rdata;
|
||||||
|
scalar_tmem_rdata_valid_r <= 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
scalar_tmem_softmax_read_response_valid <= scalar_tmem_softmax_read_issue;
|
||||||
|
if (scalar_tmem_softmax_read_issue) begin
|
||||||
|
scalar_tmem_softmax_read_response_index <= scalar_tmem_softmax_read_index;
|
||||||
|
if (scalar_tmem_softmax_read_index == SCALAR_TMEM_SOFTMAX_ROW_LAST) begin
|
||||||
|
scalar_tmem_softmax_reads_issued <= 1'b1;
|
||||||
|
end else begin
|
||||||
|
scalar_tmem_softmax_read_index <= scalar_tmem_softmax_read_index + 6'd1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (scalar_tmem_softmax_vector_done) begin
|
||||||
|
scalar_tmem_softmax_active <= 1'b0;
|
||||||
|
scalar_tmem_commit_pending <= 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (scalar_tmem_commit_pending && (|(scalar_tmem_grant_r & scalar_tmem_commit_ready))) begin
|
||||||
|
scalar_tmem_grant_r <= '0;
|
||||||
|
scalar_tmem_load_pending <= 1'b0;
|
||||||
|
scalar_tmem_store_pending <= 1'b0;
|
||||||
|
scalar_tmem_commit_pending <= 1'b0;
|
||||||
|
scalar_tmem_rdata_valid_r <= 1'b0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
localparam SCALAR_LSU_COMMIT_DATAW = `UUID_WIDTH + `NW_WIDTH + `NUM_THREADS + `XLEN + 1 + `NR_BITS + (`NUM_THREADS * `XLEN) + 1 + 1 + 1 + 1;
|
||||||
|
|
||||||
|
for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin : g_scalar_lsu_commit
|
||||||
|
VX_stream_arb #(
|
||||||
|
.NUM_INPUTS (2),
|
||||||
|
.DATAW (SCALAR_LSU_COMMIT_DATAW),
|
||||||
|
.ARBITER ("R"),
|
||||||
|
.OUT_REG (1)
|
||||||
|
) scalar_lsu_commit_arb (
|
||||||
|
.clk (clk),
|
||||||
|
.reset (reset),
|
||||||
|
.valid_in ({scalar_tmem_commit_if[i].valid, scalar_mem_lsu_commit_if[i].valid}),
|
||||||
|
.ready_in ({scalar_tmem_commit_if[i].ready, scalar_mem_lsu_commit_if[i].ready}),
|
||||||
|
.data_in ({scalar_tmem_commit_if[i].data, scalar_mem_lsu_commit_if[i].data}),
|
||||||
|
.data_out (lsu_scalar_commit_if[i].data),
|
||||||
|
.valid_out (lsu_scalar_commit_if[i].valid),
|
||||||
|
.ready_out (lsu_scalar_commit_if[i].ready),
|
||||||
|
`UNUSED_PIN (sel_out)
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
`ifdef EXT_T_ENABLE
|
`ifdef EXT_T_ENABLE
|
||||||
VX_commit_if lsu_tensor_commit_if[`ISSUE_WIDTH]();
|
VX_commit_if lsu_tensor_commit_if[`ISSUE_WIDTH]();
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
383
hw/rtl/core/VX_tmem_softmax_unit.sv
Normal file
383
hw/rtl/core/VX_tmem_softmax_unit.sv
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
// Streaming, synthesizable softmax engine for the Blackwell TMEM path.
|
||||||
|
// Four independent lane streams are processed in parallel; each stream has
|
||||||
|
// ROW_SIZE elements. The exponential datapath is pipelined with II=1.
|
||||||
|
module VX_tmem_softmax_unit #(
|
||||||
|
parameter integer NUM_LANES = 4,
|
||||||
|
parameter integer ROW_SIZE = 32
|
||||||
|
) (
|
||||||
|
input wire clk,
|
||||||
|
input wire reset,
|
||||||
|
input wire start,
|
||||||
|
input wire load_valid,
|
||||||
|
input wire [NUM_LANES-1:0][31:0] load_data,
|
||||||
|
input wire load_last,
|
||||||
|
output wire busy,
|
||||||
|
output reg out_valid,
|
||||||
|
input wire out_ready,
|
||||||
|
output reg [5:0] out_index,
|
||||||
|
output reg [NUM_LANES-1:0][31:0] out_data,
|
||||||
|
output reg done
|
||||||
|
);
|
||||||
|
localparam [2:0] STATE_IDLE = 3'd0;
|
||||||
|
localparam [2:0] STATE_LOAD = 3'd1;
|
||||||
|
localparam [2:0] STATE_EXP = 3'd2;
|
||||||
|
localparam [2:0] STATE_RECIP = 3'd3;
|
||||||
|
localparam [2:0] STATE_NORM = 3'd4;
|
||||||
|
|
||||||
|
reg [2:0] state;
|
||||||
|
reg [$clog2(ROW_SIZE)-1:0] load_index;
|
||||||
|
reg [$clog2(ROW_SIZE)-1:0] exp_feed_index;
|
||||||
|
reg exp_feed_done;
|
||||||
|
reg [1:0] reciprocal_lane;
|
||||||
|
reg [5:0] norm_index;
|
||||||
|
|
||||||
|
reg [31:0] scores [0:ROW_SIZE-1][0:NUM_LANES-1];
|
||||||
|
reg [31:0] max_bits [0:NUM_LANES-1];
|
||||||
|
reg [23:0] exp_values [0:ROW_SIZE-1][0:NUM_LANES-1];
|
||||||
|
reg [29:0] exp_sums [0:NUM_LANES-1];
|
||||||
|
reg [31:0] reciprocals [0:NUM_LANES-1];
|
||||||
|
|
||||||
|
reg [2:0] exp_pipe_valid;
|
||||||
|
reg [$clog2(ROW_SIZE)-1:0] exp_pipe_index [0:2];
|
||||||
|
reg [3:0] exp_int_stage0 [0:NUM_LANES-1];
|
||||||
|
reg [3:0] exp_frac_stage0 [0:NUM_LANES-1];
|
||||||
|
reg [7:0] exp_rem_stage0 [0:NUM_LANES-1];
|
||||||
|
reg [3:0] exp_int_stage1 [0:NUM_LANES-1];
|
||||||
|
reg [23:0] exp_frac_stage1 [0:NUM_LANES-1];
|
||||||
|
reg [23:0] exp_stage2 [0:NUM_LANES-1];
|
||||||
|
|
||||||
|
assign busy = state != STATE_IDLE;
|
||||||
|
|
||||||
|
function automatic f32_greater;
|
||||||
|
input [31:0] a;
|
||||||
|
input [31:0] b;
|
||||||
|
begin
|
||||||
|
if ((a[30:0] == 0) && (b[30:0] == 0)) begin
|
||||||
|
f32_greater = 1'b0;
|
||||||
|
end else if (a[31] != b[31]) begin
|
||||||
|
f32_greater = !a[31];
|
||||||
|
end else if (!a[31]) begin
|
||||||
|
f32_greater = a[30:0] > b[30:0];
|
||||||
|
end else begin
|
||||||
|
f32_greater = a[30:0] < b[30:0];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// Convert finite FP32 to signed Q12, saturating outside the supported
|
||||||
|
// softmax score range. Subnormals are treated as zero.
|
||||||
|
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 if (exponent == 8'hff) begin
|
||||||
|
f32_to_q12 = value[31] ? -24'sh7fffff : 24'sh7fffff;
|
||||||
|
end else begin
|
||||||
|
shift = integer'(exponent) - 138;
|
||||||
|
if (shift >= 0) begin
|
||||||
|
magnitude = {40'd0, mantissa} << shift;
|
||||||
|
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
|
||||||
|
|
||||||
|
// {integer_part, fractional_lut_index, interpolation_remainder} for
|
||||||
|
// exp(score - max). Inputs below -8 are clamped to exp(-8).
|
||||||
|
function automatic [15:0] exp_range_info;
|
||||||
|
input signed [23:0] score_q12;
|
||||||
|
input signed [23:0] max_q12;
|
||||||
|
reg signed [24:0] distance;
|
||||||
|
reg [15:0] clamped;
|
||||||
|
begin
|
||||||
|
distance = max_q12 - score_q12;
|
||||||
|
if (distance <= 0)
|
||||||
|
clamped = 16'd0;
|
||||||
|
else if (distance >= 25'sd32768)
|
||||||
|
clamped = 16'd32768;
|
||||||
|
else
|
||||||
|
clamped = distance[15:0];
|
||||||
|
|
||||||
|
if (clamped == 16'd32768)
|
||||||
|
exp_range_info = {4'd8, 4'd0, 8'd0};
|
||||||
|
else
|
||||||
|
exp_range_info = {clamped[15:12], clamped[11:8], clamped[7:0]};
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [23:0] exp_frac_lut;
|
||||||
|
input [4:0] index;
|
||||||
|
begin
|
||||||
|
case (index)
|
||||||
|
5'd0: exp_frac_lut = 24'd1048576;
|
||||||
|
5'd1: exp_frac_lut = 24'd985046;
|
||||||
|
5'd2: exp_frac_lut = 24'd925365;
|
||||||
|
5'd3: exp_frac_lut = 24'd869300;
|
||||||
|
5'd4: exp_frac_lut = 24'd816632;
|
||||||
|
5'd5: exp_frac_lut = 24'd767155;
|
||||||
|
5'd6: exp_frac_lut = 24'd720675;
|
||||||
|
5'd7: exp_frac_lut = 24'd677012;
|
||||||
|
5'd8: exp_frac_lut = 24'd635993;
|
||||||
|
5'd9: exp_frac_lut = 24'd597461;
|
||||||
|
5'd10: exp_frac_lut = 24'd561262;
|
||||||
|
5'd11: exp_frac_lut = 24'd527257;
|
||||||
|
5'd12: exp_frac_lut = 24'd495312;
|
||||||
|
5'd13: exp_frac_lut = 24'd465303;
|
||||||
|
5'd14: exp_frac_lut = 24'd437112;
|
||||||
|
5'd15: exp_frac_lut = 24'd410628;
|
||||||
|
default: exp_frac_lut = 24'd385750;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [23:0] exp_int_lut;
|
||||||
|
input [3:0] index;
|
||||||
|
begin
|
||||||
|
case (index)
|
||||||
|
4'd0: exp_int_lut = 24'd1048576;
|
||||||
|
4'd1: exp_int_lut = 24'd385750;
|
||||||
|
4'd2: exp_int_lut = 24'd141909;
|
||||||
|
4'd3: exp_int_lut = 24'd52206;
|
||||||
|
4'd4: exp_int_lut = 24'd19205;
|
||||||
|
4'd5: exp_int_lut = 24'd7065;
|
||||||
|
4'd6: exp_int_lut = 24'd2599;
|
||||||
|
4'd7: exp_int_lut = 24'd956;
|
||||||
|
default: exp_int_lut = 24'd352;
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// Convert a positive unsigned Q15 probability to FP8 E4M3 using
|
||||||
|
// round-to-nearest-even. Softmax probabilities are in [0, 1], so the
|
||||||
|
// positive subnormal and exponent ranges through 1.0 are sufficient.
|
||||||
|
function automatic [7:0] q15_to_fp8e4m3;
|
||||||
|
input [15:0] value;
|
||||||
|
integer msb;
|
||||||
|
integer i;
|
||||||
|
integer shift;
|
||||||
|
reg [3:0] exponent;
|
||||||
|
reg [4:0] rounded;
|
||||||
|
reg [15:0] remainder;
|
||||||
|
reg [15:0] halfway;
|
||||||
|
begin
|
||||||
|
if (value < 16'd512) begin
|
||||||
|
// E4M3 subnormals and the minimum normal are spaced by 2^-9,
|
||||||
|
// which is 64 in unsigned Q15.
|
||||||
|
rounded = value[10:6];
|
||||||
|
remainder = value & 16'h003f;
|
||||||
|
if ((remainder > 16'd32)
|
||||||
|
|| ((remainder == 16'd32) && rounded[0]))
|
||||||
|
rounded = rounded + 1'b1;
|
||||||
|
q15_to_fp8e4m3 = {3'b000, rounded};
|
||||||
|
end else begin
|
||||||
|
msb = 0;
|
||||||
|
for (i = 0; i < 16; ++i) begin
|
||||||
|
if (value[i]) msb = i;
|
||||||
|
end
|
||||||
|
exponent = 4'(msb - 8);
|
||||||
|
shift = integer'(exponent) + 5;
|
||||||
|
rounded = 5'(value >> shift);
|
||||||
|
remainder = value & ((16'd1 << shift) - 1'b1);
|
||||||
|
halfway = 16'd1 << (shift - 1);
|
||||||
|
if ((remainder > halfway)
|
||||||
|
|| ((remainder == halfway) && rounded[0]))
|
||||||
|
rounded = rounded + 1'b1;
|
||||||
|
if (rounded == 5'd16)
|
||||||
|
q15_to_fp8e4m3 = {1'b0, exponent + 1'b1, 3'b000};
|
||||||
|
else
|
||||||
|
q15_to_fp8e4m3 = {1'b0, exponent, rounded[2:0]};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [7:0] normalize_to_fp8e4m3;
|
||||||
|
input [23:0] exp_value;
|
||||||
|
input [31:0] reciprocal;
|
||||||
|
reg [55:0] product;
|
||||||
|
reg [55:0] probability;
|
||||||
|
begin
|
||||||
|
product = exp_value * reciprocal;
|
||||||
|
probability = (product + 56'd524288) >> 20;
|
||||||
|
if (probability > 56'd32768)
|
||||||
|
normalize_to_fp8e4m3 = 8'h38;
|
||||||
|
else
|
||||||
|
normalize_to_fp8e4m3 = q15_to_fp8e4m3(probability[15:0]);
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [23:0] interpolate_exp_frac;
|
||||||
|
input [3:0] frac_index;
|
||||||
|
input [7:0] remainder;
|
||||||
|
reg [23:0] upper;
|
||||||
|
reg [23:0] lower;
|
||||||
|
reg [31:0] product;
|
||||||
|
begin
|
||||||
|
upper = exp_frac_lut({1'b0, frac_index});
|
||||||
|
lower = exp_frac_lut({1'b0, frac_index} + 5'd1);
|
||||||
|
product = (upper - lower) * remainder;
|
||||||
|
interpolate_exp_frac = upper - ((product + 32'd128) >> 8);
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [23:0] scale_exp_frac;
|
||||||
|
input [23:0] frac_value;
|
||||||
|
input [3:0] int_index;
|
||||||
|
reg [47:0] product;
|
||||||
|
begin
|
||||||
|
product = frac_value * exp_int_lut(int_index);
|
||||||
|
scale_exp_frac = (product + 48'd524288) >> 20;
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [31:0] reciprocal_q15;
|
||||||
|
input [29:0] sum_value;
|
||||||
|
reg [63:0] numerator;
|
||||||
|
reg [63:0] quotient;
|
||||||
|
begin
|
||||||
|
numerator = (64'd1 << 35) + ({34'd0, sum_value} >> 1);
|
||||||
|
quotient = (sum_value == 0) ? 64'd0 : numerator / {34'd0, sum_value};
|
||||||
|
reciprocal_q15 = quotient[31:0];
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
wire exp_feed = (state == STATE_EXP) && !exp_feed_done;
|
||||||
|
wire [15:0] exp_feed_range [0:NUM_LANES-1];
|
||||||
|
for (genvar lane = 0; lane < NUM_LANES; ++lane) begin : g_exp_feed_range
|
||||||
|
assign exp_feed_range[lane] = exp_range_info(
|
||||||
|
f32_to_q12(scores[exp_feed_index][lane]),
|
||||||
|
f32_to_q12(max_bits[lane]));
|
||||||
|
end
|
||||||
|
|
||||||
|
integer lane;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (reset) begin
|
||||||
|
state <= STATE_IDLE;
|
||||||
|
load_index <= '0;
|
||||||
|
exp_feed_index <= '0;
|
||||||
|
exp_feed_done <= 1'b0;
|
||||||
|
reciprocal_lane <= '0;
|
||||||
|
norm_index <= '0;
|
||||||
|
exp_pipe_valid <= '0;
|
||||||
|
out_valid <= 1'b0;
|
||||||
|
out_index <= '0;
|
||||||
|
out_data <= '0;
|
||||||
|
done <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
done <= 1'b0;
|
||||||
|
|
||||||
|
if ((state == STATE_IDLE) && start) begin
|
||||||
|
state <= STATE_LOAD;
|
||||||
|
load_index <= '0;
|
||||||
|
exp_pipe_valid <= '0;
|
||||||
|
out_valid <= 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if ((state == STATE_LOAD) && load_valid) begin
|
||||||
|
for (lane = 0; lane < NUM_LANES; ++lane) begin
|
||||||
|
scores[load_index][lane] <= load_data[lane];
|
||||||
|
if ((load_index == 0) || f32_greater(load_data[lane], max_bits[lane]))
|
||||||
|
max_bits[lane] <= load_data[lane];
|
||||||
|
end
|
||||||
|
if (load_last) begin
|
||||||
|
state <= STATE_EXP;
|
||||||
|
exp_feed_index <= '0;
|
||||||
|
exp_feed_done <= 1'b0;
|
||||||
|
exp_pipe_valid <= '0;
|
||||||
|
for (lane = 0; lane < NUM_LANES; ++lane)
|
||||||
|
exp_sums[lane] <= '0;
|
||||||
|
end else begin
|
||||||
|
load_index <= load_index + 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
exp_pipe_valid[0] <= exp_feed;
|
||||||
|
exp_pipe_valid[1] <= exp_pipe_valid[0];
|
||||||
|
exp_pipe_valid[2] <= exp_pipe_valid[1];
|
||||||
|
if (exp_feed) begin
|
||||||
|
exp_pipe_index[0] <= exp_feed_index;
|
||||||
|
for (lane = 0; lane < NUM_LANES; ++lane) begin
|
||||||
|
exp_int_stage0[lane] <= exp_feed_range[lane][15:12];
|
||||||
|
exp_frac_stage0[lane] <= exp_feed_range[lane][11:8];
|
||||||
|
exp_rem_stage0[lane] <= exp_feed_range[lane][7:0];
|
||||||
|
end
|
||||||
|
if (exp_feed_index == $clog2(ROW_SIZE)'(ROW_SIZE - 1))
|
||||||
|
exp_feed_done <= 1'b1;
|
||||||
|
else
|
||||||
|
exp_feed_index <= exp_feed_index + 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (exp_pipe_valid[0]) begin
|
||||||
|
exp_pipe_index[1] <= exp_pipe_index[0];
|
||||||
|
for (lane = 0; lane < NUM_LANES; ++lane) begin
|
||||||
|
exp_frac_stage1[lane] <= interpolate_exp_frac(
|
||||||
|
exp_frac_stage0[lane], exp_rem_stage0[lane]);
|
||||||
|
exp_int_stage1[lane] <= exp_int_stage0[lane];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (exp_pipe_valid[1]) begin
|
||||||
|
exp_pipe_index[2] <= exp_pipe_index[1];
|
||||||
|
for (lane = 0; lane < NUM_LANES; ++lane) begin
|
||||||
|
exp_stage2[lane] <= scale_exp_frac(
|
||||||
|
exp_frac_stage1[lane], exp_int_stage1[lane]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (exp_pipe_valid[2]) begin
|
||||||
|
for (lane = 0; lane < NUM_LANES; ++lane) begin
|
||||||
|
exp_values[exp_pipe_index[2]][lane] <= exp_stage2[lane];
|
||||||
|
exp_sums[lane] <= exp_sums[lane] + exp_stage2[lane];
|
||||||
|
end
|
||||||
|
if (exp_pipe_index[2] == $clog2(ROW_SIZE)'(ROW_SIZE - 1)) begin
|
||||||
|
state <= STATE_RECIP;
|
||||||
|
reciprocal_lane <= '0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (state == STATE_RECIP) begin
|
||||||
|
reciprocals[reciprocal_lane] <= reciprocal_q15(exp_sums[reciprocal_lane]);
|
||||||
|
if (reciprocal_lane == 2'(NUM_LANES - 1)) begin
|
||||||
|
state <= STATE_NORM;
|
||||||
|
norm_index <= '0;
|
||||||
|
out_valid <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
reciprocal_lane <= reciprocal_lane + 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (state == STATE_NORM) begin
|
||||||
|
if (out_valid && out_ready && (out_index == 6'd63)) begin
|
||||||
|
out_valid <= 1'b0;
|
||||||
|
done <= 1'b1;
|
||||||
|
state <= STATE_IDLE;
|
||||||
|
end else if (!out_valid || out_ready) begin
|
||||||
|
for (lane = 0; lane < NUM_LANES; ++lane) begin
|
||||||
|
out_data[lane] <= {
|
||||||
|
4{normalize_to_fp8e4m3(
|
||||||
|
exp_values[norm_index[4:0]][lane], reciprocals[lane])}
|
||||||
|
};
|
||||||
|
end
|
||||||
|
out_index <= norm_index;
|
||||||
|
out_valid <= 1'b1;
|
||||||
|
if (norm_index != 6'd63)
|
||||||
|
norm_index <= norm_index + 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
@@ -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;
|
||||||
@@ -210,7 +211,7 @@ module VX_fpu_fpnew
|
|||||||
.int_fmt_i (fpu_int_fmt),
|
.int_fmt_i (fpu_int_fmt),
|
||||||
`UNUSED_PIN (vectorial_op_i),
|
`UNUSED_PIN (vectorial_op_i),
|
||||||
`UNUSED_PIN (simd_mask_i),
|
`UNUSED_PIN (simd_mask_i),
|
||||||
.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_uq),
|
.in_ready_o (fpu_ready_in_uq),
|
||||||
.flush_i (reset),
|
.flush_i (reset),
|
||||||
@@ -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