diff --git a/PyGolden/mxcore_gemm_functions.py b/PyGolden/mxcore_gemm_functions.py index 056809b..5e20d6d 100644 --- a/PyGolden/mxcore_gemm_functions.py +++ b/PyGolden/mxcore_gemm_functions.py @@ -309,6 +309,7 @@ def pack_uint8_to_lines(byte_list): nan_byte = 0x7D if data_type != "FP8ALT" else 0x7F if poisoned and block_poison_enable: quantized_all = [nan_byte] * len(block_fp32) + scale = 0xFF else: quantized_all = [quantize_fn(v, scale) for v in block_fp32] mx_row_segments.append((quantized_all[:q_cols], scale)) @@ -498,14 +499,15 @@ def write_to_c_header(fp9_matrix_a, fp9_matrix_b, scale_matrix_a, scale_matrix_b segment = [_acc_to_fp32_u32(result_matrix[row_idx][col_start + q_start + j]) for j in range(q_cols)] block_fp32 = segment + [0] * (result_mx_block_size - q_cols) scale, poisoned = block_scale(block_fp32, data_type="FP8ALT" if data_type == "FP8ALT" else "FP8") - result_scale_mx.append(scale) quantize_fn = quantize_e5m2 if data_type != "FP8ALT" else quantize_e4m3 nan_byte = 0x7D if data_type != "FP8ALT" else 0x7F if poisoned and block_poison_enable: quantized_all = [nan_byte] * len(block_fp32) + scale = 0xFF else: quantized_all = [quantize_fn(v, scale) for v in block_fp32] result_mx_all.extend(quantized_all[:q_cols]) + result_scale_mx.append(scale) # Pack bytes into memory_data_width words bytes_per_word = memory_data_width // 8 diff --git a/PyGolden/mxcore_utils.py b/PyGolden/mxcore_utils.py index 5f4e18e..6097726 100644 --- a/PyGolden/mxcore_utils.py +++ b/PyGolden/mxcore_utils.py @@ -18,9 +18,6 @@ def bin32_to_float(s32): # "01000000101000000000000000000000" -> 5.0 b = int(s32[-32:], 2) return struct.unpack('!f', struct.pack('!I', b))[0] -def to_signed8(x): - return x - 256 if x > 127 else x - def vec_to_hex(vec, vector_size=8, memory_data_width=32): """ Converts a vector of binary strings into hex memory lines (padded mode). @@ -178,13 +175,7 @@ def block_scale(block, data_type="FP8"): emax = 15 if data_type == "FP8" else 8 max_exp = max([(fp32_to_fields(x)[1]) for x in block]) is_special = any((fp32_to_fields(x)[1] == 0xFF) for x in block) - scaled = max_exp - (127 + emax) - scale_emax = 127 - if scaled > scale_emax: - return scale_emax & 0xFF, True - if scaled < -scale_emax: - return (-scale_emax) & 0xFF, is_special - return scaled & 0xFF, is_special + return max(max_exp - emax, 0), is_special def _quantize_mxfp8(fp32_val, scale, mant_bits, exp_bits, bias, exp_max, exp_min, sat_byte, nan_byte, full_field_reserved): sign, exp, mant = fp32_to_fields(fp32_val) @@ -199,7 +190,7 @@ def _quantize_mxfp8(fp32_val, scale, mant_bits, exp_bits, bias, exp_max, exp_min is_subnorm_in = (exp == 0) unbiased_exp = (1 - 127) if is_subnorm_in else (exp - 127) full_mant = mant if is_subnorm_in else ((1 << 23) | mant) - scaled_exp = unbiased_exp - to_signed8(scale) + scaled_exp = unbiased_exp - (scale - 127) if scaled_exp > exp_max: return (sign << 7) | sat_byte diff --git a/mxcore-rtl/src/hwpe/block_scale.sv b/mxcore-rtl/src/hwpe/block_scale.sv index b0b0379..f5ede4c 100644 --- a/mxcore-rtl/src/hwpe/block_scale.sv +++ b/mxcore-rtl/src/hwpe/block_scale.sv @@ -19,13 +19,10 @@ module block_scale #( output logic block_poison_o ); - localparam int FP32_BIAS = 127; localparam int E5M2_EMAX = 15; localparam int E4M3_EMAX = 8; localparam int MXFP8_EMAX = (Encoding == 0) ? E5M2_EMAX : E4M3_EMAX; - localparam int SCALE_EMAX = (2 ** (ScaleWidth-1)) - 1; - // Number of Levels/Stages in the Comparator Tree localparam int STAGES = $clog2(BlockSize); @@ -41,8 +38,6 @@ module block_scale #( // Scaled Exponent logic signed [9:0] scaled_exponent; - logic scale_overflow; - logic scale_underflow; // Comparator Tree Stages logic [STAGES:0][BlockSize-1:0][7:0] stage; @@ -71,14 +66,10 @@ module block_scale #( endgenerate assign max_exponent = stage[STAGES][0]; - assign scaled_exponent = $signed({2'b00, max_exponent}) - FP32_BIAS - MXFP8_EMAX; - assign scale_overflow = scaled_exponent > SCALE_EMAX; - assign scale_underflow = scaled_exponent < -SCALE_EMAX; - - assign block_scale_o = scale_overflow ? ScaleWidth'(SCALE_EMAX) : - scale_underflow ? ScaleWidth'(-SCALE_EMAX) : - scaled_exponent[ScaleWidth-1:0]; + // OCP E8M0 Scale (Bias 127) + assign scaled_exponent = $signed({2'b00, max_exponent}) - MXFP8_EMAX; + assign block_scale_o = (scaled_exponent < 0) ? '0 : scaled_exponent[ScaleWidth-1:0]; - assign block_poison_o = scale_overflow || (|is_special); + assign block_poison_o = |is_special; endmodule : block_scale diff --git a/mxcore-rtl/src/hwpe/fp32_to_mxfp8_quantizer.sv b/mxcore-rtl/src/hwpe/fp32_to_mxfp8_quantizer.sv index 424c30b..7d0f7fb 100644 --- a/mxcore-rtl/src/hwpe/fp32_to_mxfp8_quantizer.sv +++ b/mxcore-rtl/src/hwpe/fp32_to_mxfp8_quantizer.sv @@ -84,7 +84,7 @@ module fp32_to_mxfp8_quantizer #( end else begin unbiased_exponent = is_input_subnorm ? (1 - FP32_BIAS) : (fp32_exponent - FP32_BIAS); full_mantissa = is_input_subnorm ? {1'b0, fp32_mantissa} : {1'b1, fp32_mantissa}; - scaled_exponent = unbiased_exponent - $signed(scale_i); + scaled_exponent = unbiased_exponent - ($signed({2'b00, scale_i}) - FP32_BIAS); // Overflow if (scaled_exponent > EXPONENT_MAX) begin mxfp8_exponent = (Encoding == 0) ? ((Saturate == 1) ? 5'h1e : 5'h1f) : 4'hf; diff --git a/mxcore-rtl/src/hwpe/mxcore_hwpe_result_quantizer.sv b/mxcore-rtl/src/hwpe/mxcore_hwpe_result_quantizer.sv index 5373b4a..5f546de 100644 --- a/mxcore-rtl/src/hwpe/mxcore_hwpe_result_quantizer.sv +++ b/mxcore-rtl/src/hwpe/mxcore_hwpe_result_quantizer.sv @@ -77,7 +77,7 @@ module mxcore_hwpe_result_quantizer #( assign mxfp8_result_o.strb = {(OutputDataWidth/8){1'b1}}; assign mx_result_scale_o.valid = fp32_result_i.valid; - assign mx_result_scale_o.data = block_scale; + assign mx_result_scale_o.data = (block_poison && block_poison_i) ? '1 : block_scale; assign mx_result_scale_o.strb = {ScaleWidth/8{1'b1}}; endmodule : mxcore_hwpe_result_quantizer