乘法器的实现(阵列、Booth、Wallace)
文章目錄
- 1 乘法器
- 2 部分積的產生
- 2.1 波茲(Booth)編碼
- 2.2 改進的波茲編碼
- 3 部分積的累加
- 3.1 陣列乘法器
- 3.2 進位保留乘法器
- 3.3 Wallace 樹形乘法器
- 4 Verilog 實現
- 4.1 普通陣列乘法器
- 4.2 Booth 乘法器
- 4.3 Wallace 乘法器
- 5 總結
- 參考
1 乘法器
M和N位寬輸入的乘法,采用一個N加法器需要M個周期。
利用移位和相加將M個部分積(partial product)加在一起。部分積的計算位相乘本質上是與邏輯。
101010 被乘數× 1011 乘數———————————101010 \101010 | 部分積000000 |+ 101010 /—————————————1110011102 部分積的產生
2.1 波茲(Booth)編碼
乘數 8’b0111_1110 可以轉換成 8’b1000_0000 - 8’b0000_0010 。這里用8’b1000_00I0 表示(I表示 -1 )。
這可以減少非0行的數量,使得部分積的數目至少可以減少原來的一半。部分積數目的減少意味著相加次數的減少,從而加快了運算速度并減少了面積。
保證了在每兩個連續位中最多只有一個是 1 或者 -1 。形式上相當于把乘數變換成一個四進制形式。8’b1000_00I0 = (2,0,0,-2)(四進制)
問題:與{0,1}相乘等效于AND,但是與{-2,-1,0,1,2}相乘還需要反向邏輯和移位邏輯,大小不同的部分積陣列對乘法器設計不合理。
2.2 改進的波茲編碼
改進的波茲編碼(modified Booth’s recoding)乘數由最高有效位(msb)到最低有效位(lsb)進行,按3位一組進行劃分,相互重疊一位,編碼表:
| 000 | 0 | 00 |
| 001 | +被乘數 | 01 |
| 010 | +被乘數 | 01 |
| 011 | +2×被乘數 | 10 |
| 100 | -2×被乘數 | I0 |
| 101 | -被乘數 | 0I |
| 110 | -被乘數 | 0I |
| 111 | 0 | 00 |
本質是從msb到lsb檢查乘數中1的字串,用一個以1開頭或以-1結尾的字符串代替他們。
例子:
011 :一串1的開始,所以用一個開頭的1代替(100)
110 :一串1的結尾,所以用一個結尾的-1代替(0I0)
8’b0111_1110,從msb到lsb,分成3位一組首尾重疊的4組:01(1),11(1),11(1),10(0)。編碼后為10,00,00,I0,這與上述的編碼是吻合的。
3 部分積的累加
對部分積相加是一個多操作數的加法,一個直接累加的部分積方法是用許多加法器形成陣列,所以被稱為 陣列乘法器(array multiplier)。
一個更為先進的方法與樹結構的形式完成加法。
3.1 陣列乘法器
AND 門產生部分積,加法器陣列實現相加。
所有關鍵路徑都具有相同的長度。
上述乘法器只能進行無符號數相乘。
3.2 進位保留乘法器
如果進位向下沿而不是向左,可以得到一個更有效的實現。進位不是立即相加,而是傳遞給下一級加法器,在最后一級在一個快速進位傳播(如超前進位)加法器中合并。
代價:需要一個額外的加法器,被稱為向量合并(vector-merging)加法器。由此得到的乘法器被稱為進位保留乘法器。
優點:在最壞情形下關鍵路徑最短且唯一確定。
拓撲優化后的結構:
這種結構可以更好的映射到硅片上。
3.3 Wallace 樹形乘法器
部分積加法器可以設計成樹形,可以減少關鍵路徑和所需的加法器單元數目。
上面的4個4位部分積,只有第3bit需要加 4 個。
第一步,第3列和低4列引入2個半加器,如圖b所示,壓縮后得到圖c。
第二步,第3、4、5列引入3個全加器,第2列引入1個半加器,得到圖d。
第三步,使用簡單的兩輸入加法器。
前兩步一共使用了3個全加器、3個半加器。原來的進位保留乘法器結構需要6個全加器、6個半加器。
全加器3個輸入兩個輸出,所以運算過程中又稱為壓縮器。
優點:
- 節省了較大乘法器所需硬件,減少了傳播延時。
缺點:
- 不規則,高質量版圖設計任務變復雜。
4 Verilog 實現
4.1 普通陣列乘法器
以 8bit 無符號數相乘為例,注意這里的設計沒有考慮性能。
array_multiplier.v:
`timescale 1ns/1ps module array_multiplier ( input I_sys_clk,input I_reset_n,input I_valid,input [7:0] I_a,input [7:0] I_b,output reg O_valid,output reg [15:0] O_c );//--- Main body of code --- always @(posedge I_sys_clk or negedge I_reset_n) beginif(~I_reset_n) beginO_valid <= 1'b0;O_c <= 16'b0;end elsebeginO_valid <= I_valid;O_c <= (({8{I_b[0]}} & I_a) ) + (({8{I_b[1]}} & I_a) << 1) + (({8{I_b[2]}} & I_a) << 2) + (({8{I_b[3]}} & I_a) << 3) + (({8{I_b[4]}} & I_a) << 4) + (({8{I_b[5]}} & I_a) << 5) + (({8{I_b[6]}} & I_a) << 6) + (({8{I_b[7]}} & I_a) << 7) ;end endendmoduletestbench array_multiplier_tb.sv:
`timescale 1ns/1psmodule array_multiplier_tb();parameter T = 5; reg I_sys_clk; reg I_reset_n; reg I_valid ; reg [7:0] I_a ; reg [7:0] I_b ; wire O_valid ; wire [15:0] O_c ;initial beginI_sys_clk <= 'b0;I_reset_n <= 'b0;I_valid <= 'b0; I_a <= 'b0; I_b <= 'b0; #(T*20) I_reset_n <= 'b1;#(T*20) data_gen();$finish(); endalways #(T/2) I_sys_clk <= ~I_sys_clk;array_multiplier array_multiplier_u ( .I_sys_clk(I_sys_clk),.I_reset_n(I_reset_n),.I_valid (I_valid ),.I_a (I_a ),.I_b (I_b ),.O_valid (O_valid ),.O_c (O_c ) );task data_gen();for (int i = 0; i < 256; i++) beginI_valid <= 'b1; I_a <= i; I_b <= i;$display("%d x %d = %d", i, i, i*i);@(posedge I_sys_clk);I_valid <= 'b0;end endtaskendmodulesim.do 文件:
cd D:/prj/modelsim_prj/multiplier/array_multiplier/ vlib work vlog array_multiplier.v array_multiplier_tb.sv vsim -novopt work.array_multiplier_tbsim.bat 文件:
vsim -do sim.do所有文件放在相同路徑下,雙擊批處理文件即可開始Modelsim仿真。
仿真結果:
4.2 Booth 乘法器
Verilog 設計,注意,這個代碼只是描述算法,需要進行符號位拓展、乘換成與邏輯、以及將乘2的冪轉換為移位處理。
`timescale 1ns/1psmodule booth_multiplier (input I_sys_clk,input I_reset_n,input I_valid ,input [7:0] I_a ,input [7:0] I_b ,output reg O_valid ,output reg [15:0] O_c );//--- Main body of code --- wire [8:0] W_b; wire [15:0] W_a_n; wire [2:0] W_booth_code_pre [0:3]; reg R_valid ; reg signed [15:0] R_partial_product [0:3];assign W_b = {I_b, 1'b0}; assign W_a_n = -{{8{I_a[7]}}, I_a};genvar gen_i; for (gen_i = 0; gen_i < 4; gen_i = gen_i + 1) begin assign W_booth_code_pre[gen_i] = W_b[gen_i*2 +: 3];always @(posedge I_sys_clk or negedge I_reset_n)beginif(~I_reset_n) beginR_partial_product[gen_i] <= 1'b0;end elsebegincase (W_booth_code_pre[gen_i])3'b000: R_partial_product[gen_i] <= 9'b0;3'b001: R_partial_product[gen_i] <= $signed(I_a) * 1 * 2**(gen_i*2) ;3'b010: R_partial_product[gen_i] <= $signed(I_a) * 1 * 2**(gen_i*2) ;3'b011: R_partial_product[gen_i] <= $signed(I_a) * 2 * 2**(gen_i*2) ;3'b100: R_partial_product[gen_i] <= $signed(I_a) * -2 * 2**(gen_i*2) ;3'b101: R_partial_product[gen_i] <= $signed(I_a) * -1 * 2**(gen_i*2) ;3'b110: R_partial_product[gen_i] <= $signed(I_a) * -1 * 2**(gen_i*2) ;3'b111: R_partial_product[gen_i] <= 9'b0;default: R_partial_product[gen_i] <= 9'b0;endcaseendend endalways @(posedge I_sys_clk or negedge I_reset_n) beginif(~I_reset_n) beginR_valid <= 1'b0;end elsebeginR_valid <= I_valid;end endalways @(posedge I_sys_clk or negedge I_reset_n) beginif(~I_reset_n) beginO_valid <= 1'b0;O_c <= 16'b0;end elsebeginO_valid <= R_valid;O_c <= R_partial_product[0] + R_partial_product[1] + R_partial_product[2] + R_partial_product[3] ;end endendmoduletestchech:
`timescale 1ns/1psmodule booth_multiplier_tb();parameter T = 5; reg I_sys_clk; reg I_reset_n; reg I_valid ; reg [7:0] I_a ; reg [7:0] I_b ; wire O_valid ; wire [15:0] O_c ;// reference model signal reg [7:0] R_i ; reg [7:0] R1_i ; reg [7:0] R2_i ;initial beginI_sys_clk <= 'b0;I_reset_n <= 'b0;I_valid <= 'b0; I_a <= 'b0; I_b <= 'b0; #(T*20) I_reset_n <= 'b1;#(T*20) data_gen();$finish(); endalways #(T/2) I_sys_clk <= ~I_sys_clk;booth_multiplier booth_multiplier_u ( .I_sys_clk(I_sys_clk),.I_reset_n(I_reset_n),.I_valid (I_valid ),.I_a (I_a ),.I_b (I_b ),.O_valid (O_valid ),.O_c (O_c ) );task data_gen();for (int i = 0; i < 256; i++) beginI_valid <= 'b1; I_a <= i; I_b <= i;R_i <= i;R1_i <= R_i;R2_i <= R1_i;// reference modelif (O_valid)begin$display("i=%d, O_c=%d, check=%d", $signed(R2_i), $signed(O_c), $signed(O_c) == $signed(R2_i) * $signed(R2_i));end@(posedge I_sys_clk);I_valid <= 'b0;end endtaskendmoduleModilsim do文件做對應修改,sim.do:
cd D:/prj/modelsim_prj/multiplier/booth_multiplier/ vlib work vlog booth_multiplier.v booth_multiplier_tb.sv vsim -novopt work.booth_multiplier_tb仿真結果:
4.3 Wallace 乘法器
以4bit×4bit為例,按照結構把線連起來就行:
wallace_multiplier.v:
仿真結果:
5 總結
數字集成電路設計可能對加法器的面積和版圖有較高的要求。對于FPGA設計,可能基本陣列加法器用著還更簡單順手。主要看的的題目可能問的是與一個常數相乘的設計,這個時候要參考 Booth 編碼的思想,因為不是實時乘數的話,預編碼之后確實還是節省資源的。
參考
數字集成電路-電路、系統與設計(第二版)
總結
以上是生活随笔為你收集整理的乘法器的实现(阵列、Booth、Wallace)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一文读懂链上身份(DID):赛道及项目一
- 下一篇: 普华i-VirtualCloud应用案例