1 浮點運算單元FPU
超標量CPU中的浮點運算單元是專門處理浮點數運算的關鍵組件。浮點運算單元的設計涉及多個復雜的子模塊和技術,以保證高效、準確地執行浮點數的加減法、乘法、除法、平方根等操作。
1)浮點數術語
浮點數通常采用IEEE 754標準表示,包括三部分:符號位、指數位和尾數位。
半精度浮點數:16位,FP16,包括1位符號位,5位指數位,10位尾數位。
單精度浮點數:32位,FP32,包括1位符號位,8位指數位,23位尾數位。
雙精度浮點數:64位,FP64,包括1位符號位,11位指數位,52位尾數位。
FP8 是一種新的浮點數格式,主要用于機器學習加速器和一些低精度計算場景,兩種變種:
E4M3(Exponent 4 bits, Mantissa 3 bits):包括1位符號位,4位指數位,3位尾數位。
E5M2(Exponent 5 bits, Mantissa 2 bits):包括1位符號位,5位指數位,2位尾數位。
BF16 (16位浮點數,Brain Floating Point, BP16),是一種為機器學習優化的16位浮點數格式,保留了單精度浮點數的指數范圍,但減少了尾數的位數:包括1位符號位,8位指數位,7位尾數位。BF16 具有與單精度浮點數(FP32)相同的指數范圍,因此可以表示同樣大的數值范圍,但精度較低,這使得 BF16 特別適合于訓練深度神經網絡,因為它可以減少內存帶寬和存儲需求,同時保持足夠的數值范圍。
2)浮點運算單元組成
加法器和減法器,乘法器,除法器,平方根計算單元,歸約和規范化單元,異常處理單元
3)浮點加法和減法單元
浮點加減法需要處理對齊、加減運算和歸約等步驟:
1)對齊:比較指數(對齊操作數,使其指數相同)、移位尾數(根據指數差調整尾數)。
2)加法/減法:計算尾數(執行加法或減法運算)
3)規范化結果:歸約結果(規范化結果,使最高有效位位于合適位置)、舍入結果(根據IEEE 754標準,對結果進行舍入操作:向偶數舍入、向零舍入、向正無窮舍入、向負無窮舍入)。
邏輯實現
module FPAdder (
????input [31:0] a, b, ?// 兩個單精度浮點數
????output [31:0] result
);
????// 提取符號位、指數位和尾數位
????wire sign_a = a[31];
????wire [7:0] exp_a = a[30:23];
????wire [23:0] frac_a = {1'b1, a[22:0]};
????
????wire sign_b = b[31];
????wire [7:0] exp_b = b[30:23];
????wire [23:0] frac_b = {1'b1, b[22:0]};
????
????// 對齊指數和尾數
????wire [7:0] exp_diff = exp_a - exp_b;
????wire [23:0] aligned_frac_b = frac_b >> exp_diff;
????
????// 執行加法
????wire [24:0] frac_sum = frac_a + aligned_frac_b;
????
????// 規范化結果
????wire [7:0] result_exp = exp_a + 1;
????wire [23:0] result_frac = frac_sum[24] ? frac_sum[23:0] : frac_sum[22:0];
????
????assign result = {sign_a, result_exp, result_frac[22:0]};
endmodule
4)浮點乘法單元
浮點乘法包括指數相加和尾數相乘兩個主要步驟:
1)指數相加:結果指數是兩個操作數指數之和,減去一個偏置值。
2)尾數相乘:乘法操作需要高效的部分積生成和壓縮機制。
3)規范化結果。
邏輯實現
module FPMultiplier (
????input [31:0] a, b, ?// 兩個單精度浮點數
????output [31:0] result
);
????// 提取符號位、指數位和尾數位
????wire sign_a = a[31];
????wire [7:0] exp_a = a[30:23];
????wire [23:0] frac_a = {1'b1, a[22:0]};
????
????wire sign_b = b[31];
????wire [7:0] exp_b = b[30:23];
????wire [23:0] frac_b = {1'b1, b[22:0]};
????
????// 計算符號
????wire result_sign = sign_a ^ sign_b;
????
????// 計算指數
????wire [8:0] result_exp = exp_a + exp_b - 8'd127;
????
????// 尾數相乘
????wire [47:0] frac_mult = frac_a * frac_b;
????
????// 規范化結果
????wire [23:0] result_frac = frac_mult[47] ? frac_mult[46:24] : frac_mult[45:23];
????wire [7:0] final_exp = frac_mult[47] ? result_exp + 1 : result_exp;
????
????assign result = {result_sign, final_exp[7:0], result_frac[22:0]};
endmodule
5)浮點除法和平方根單元
浮點除法和平方根計算通常比加減法和乘法更復雜,可以采用多種算法實現,如牛頓-拉弗森法、非恢復性除法等。
浮點除法主要步驟如下:
符號計算:結果的符號是被除數和除數符號的異或。
指數相減:結果的指數是被除數指數減去除數指數再加上偏置值。
尾數除法:計算尾數的商。
規范化結果。
邏輯實現
module FPDivider(
????input [31:0] a, b, ?// 兩個單精度浮點數
????output [31:0] result
);
????// 提取符號位、指數位和尾數位
????wire sign_a = a[31];
????wire [7:0] exp_a = a[30:23];
????wire [23:0] frac_a = {1'b1, a[22:0]}; ?// 隱含1
????wire sign_b = b[31];
????wire [7:0] exp_b = b[30:23];
????wire [23:0] frac_b = {1'b1, b[22:0]}; ?// 隱含1
????// 計算符號
????wire result_sign = sign_a ^ sign_b;
????// 計算指數
????wire [8:0] result_exp = exp_a - exp_b + 8'd127;
????// 尾數相除
????wire [47:0] frac_div = (frac_a << 23) / frac_b;
????// 規范化結果
????wire [23:0] result_frac = frac_div[46] ? frac_div[46:24] : frac_div[45:23];
????wire [7:0] final_exp = frac_div[46] ? result_exp + 1 : result_exp;
????assign result = {result_sign, final_exp[7:0], result_frac[22:0]};
Endmodule
浮點開方主要步驟如下:
符號計算:平方根運算結果的符號為正。
指數計算:結果的指數是操作數指數的一半再加上偏置值。
尾數計算:計算尾數的平方根。
規范化結果。
邏輯實現
module FPSqrt(
????input [31:0] a,
????output [31:0] result
);
????wire [7:0] exp_a;
????wire [23:0] frac_a;
????wire [7:0] result_exp;
????wire [23:0] frac_result;
????wire [23:0] norm_frac_result;
????wire [7:0] norm_exp_result;
????
????// 各個階段模塊化實現
????FPSqrt_Preprocess preprocess (.a(a), .exp_a(exp_a), .frac_a(frac_a));
????FPSqrt_Exponent exponent (.exp_a(exp_a), .result_exp(result_exp));
????FPSqrt_Mantissa mantissa (.frac_a(frac_a), .frac_result(frac_result));
????FPSqrt_Normalize normalize (.frac_result(frac_result), .result_exp(result_exp),
????????????????????????????????.norm_frac_result(norm_frac_result), .norm_exp_result(norm_exp_result));
????FPSqrt_Round round (.norm_frac_result(norm_frac_result), .norm_exp_result(norm_exp_result),
????????????????????????.final_result(result));
endmodule
6)歸約和規范化單元
歸約和規范化用于確保結果符合標準的浮點數格式,包括對結果的尾數進行移位處理,以使結果尾數的最高有效位為1,并調整指數值。
7)異常處理單元
異常處理包括對各種浮點運算異常的檢測和處理,例如:
溢出:結果超出可表示的范圍。
下溢:結果小于可表示的最小值。
除零:除法操作中分母為零。
無效操作:如0/0或sqrt(-1)。
2 單指令多數據SIMD
SIMD(Single Instruction, Multiple Data)是一種并行計算架構,通過擴展處理器的指令集來操作多個數據元素,這些數據元素通常被存儲在一個大的寄存器中,例如處理器可以使用一條指令同時對四個 32 位浮點數或八個 16 位整數進行運算。SIMD設計在現代超標量CPU中被廣泛應用,特別是在多媒體處理、科學計算和其他需要處理大量數據的應用中。
1)常見的 SIMD 指令集
Intel MMX、SSE、AVX 和 AVX-512
ARM NEON
IBM AltiVec
AMD 3DNow!
2)SIMD 寄存器
SIMD 指令通常使用寬寄存器來存儲多個數據元素。
MMX 寄存器:64 位寬,通常處理 8 個 8 位數據或 4 個 16 位數據。
SSE 寄存器:128 位寬,通常處理 4 個 32 位浮點數或 16 個 8 位整數。
AVX 寄存器:256 位寬,通常處理 8 個 32 位浮點數或 32 個 8 位整數。
AVX-512 寄存器:512 位寬,處理的數據量更大。
3)SIMD操作數
SIMD 指令的操作數通常表示為向量類型的數據。例如在 Intel 的 AVX 指令集中,ymm?寄存器表示 256 位寄存器,其中可以存儲 8 個 32 位浮點數。
4)SIMD 指令操作
算術運算:加法、減法、乘法、除法等
邏輯運算:與、或、非、異或等
移位運算:左移、右移、算術右移等
比較運算:大于、小于、等于等
數據搬移:加載、存儲、混合、打包和解包數據
5)SIMD執行步驟
指令獲取和解碼:處理器從內存中獲取 SIMD 指令,并將其解碼為內部操作碼和操作數。
數據加載:將操作數從內存加載到 SIMD 寄存器中。
并行計算:在多個數據元素上并行執行指令。
結果存儲:將計算結果從 SIMD 寄存器存儲回內存或其他寄存器中。
SIMD 加法器示例(并行處理四個 32 位整數)
module SIMDAdder (
????input [127:0] A, // 四個 32 位整數輸入 A
????input [127:0] B, // 四個 32 位整數輸入 B
????output [127:0] Sum // 四個 32 位整數輸出 Sum
);
????assign Sum[31:0] ??= A[31:0] ??+ B[31:0]; ??// 第一個整數加法
????assign Sum[63:32] ?= A[63:32] ?+ B[63:32]; ?// 第二個整數加法
????assign Sum[95:64] ?= A[95:64] ?+ B[95:64]; ?// 第三個整數加法
????assign Sum[127:96] = A[127:96] + B[127:96]; // 第四個整數加法
endmodule
6)SIMD 優化技術
數據對齊:確保數據在內存中的對齊,以便于 SIMD 加載和存儲操作。
數據預取:提前加載數據以減少等待時間,提高指令執行效率。
向量化:將標量代碼轉換為向量代碼,使其能夠利用 SIMD 指令集。
循環展開:減少循環控制開銷,通過展開循環體使更多操作在同一條指令中執行。
指令調度:優化指令順序,以最大限度地減少依賴關系和等待時間。
7)SIMD 的應用
多媒體處理:圖像處理、音頻處理、視頻編碼和解碼。
科學計算:矩陣運算、向量運算、快速傅里葉變換(FFT)。
數據分析:大數據處理、機器學習、神經網絡。
加密和解密:數據加密標準(AES)、安全哈希算法(SHA)。