日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

乘法器的实现(阵列、Booth、Wallace)

發布時間:2024/3/7 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 乘法器的实现(阵列、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 /—————————————111001110

2 部分積的產生

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位一組進行劃分,相互重疊一位,編碼表:

乘數位編碼位編碼
000000
001+被乘數01
010+被乘數01
011+2×被乘數10
100-2×被乘數I0
101-被乘數0I
110-被乘數0I
111000

本質是從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 endendmodule

testbench 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 endtaskendmodule

sim.do 文件:

cd D:/prj/modelsim_prj/multiplier/array_multiplier/ vlib work vlog array_multiplier.v array_multiplier_tb.sv vsim -novopt work.array_multiplier_tb

sim.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 endendmodule

testchech:

`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 endtaskendmodule

Modilsim 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:

`timescale 1ns/1psmodule wallace_multiplier (input I_sys_clk,input I_reset_n,input I_valid ,input [3:0] I_a ,input [3:0] I_b ,output reg O_valid ,output reg [7:0] O_c );reg R_valid ; reg [3:0] R_partial_product [0:3]; wire [1:0] W_level1_c,W_level1_carry; wire [3:0] W_level2_c,W_level2_carry; wire [6:0] W_level3[0:1];genvar gen_i; generatefor (gen_i = 0; gen_i < 4; gen_i = gen_i + 1) beginalways @(posedge I_sys_clk or negedge I_reset_n)beginif(~I_reset_n) beginR_partial_product[gen_i] = 4'd0;end elsebeginR_partial_product[gen_i] = {4{I_b[gen_i]}} & I_a;endendend endgenerate// level1 adder_half adder_half_u1 (.I_a (R_partial_product[2][1]),.I_b (R_partial_product[3][0]),.O_c (W_level1_c[0]),.O_carry(W_level1_carry[0]) ); adder_half adder_half_u2 (.I_a (R_partial_product[1][3]),.I_b (R_partial_product[2][2]),.O_c (W_level1_c[1]),.O_carry(W_level1_carry[1]) );// level2 adder_half adder_half_u3 (.I_a (R_partial_product[1][1]),.I_b (R_partial_product[2][0]),.O_c (W_level2_c[0] ),.O_carry(W_level2_carry[0]) ); adder adder_u1 (.I_a (R_partial_product[0][3]),.I_b (R_partial_product[1][2]),.I_carry (W_level1_c[0] ),.O_c (W_level2_c[1] ),.O_carry (W_level2_carry[1] ) ); adder adder_u2 (.I_a (R_partial_product[1][3]),.I_b (W_level1_c[1] ),.I_carry (W_level1_carry[0] ),.O_c (W_level2_c[2] ),.O_carry (W_level2_carry[2] ) ); adder adder_u3 (.I_a (R_partial_product[2][3]),.I_b (R_partial_product[3][2]),.I_carry (W_level1_carry[1] ),.O_c (W_level2_c[3] ),.O_carry (W_level2_carry[3] ) );assign W_level3[0] = {R_partial_product[3][3], W_level2_c[3:1], R_partial_product[0][2:0]}; assign W_level3[1] = {W_level2_carry[3:0], W_level2_c[0], R_partial_product[1][0], 1'b0};always @(posedge I_sys_clk or negedge I_reset_n) beginif(~I_reset_n) beginR_valid <= 1'b0;O_valid <= 1'd0;O_c <= 8'd0;end elsebeginR_valid <= I_valid;O_valid <= R_valid;O_c <= W_level3[0] + W_level3[1]; end endendmodulemodule adder_half (input I_a,input I_b,output O_c,output O_carry );assign O_c = I_a ^ I_b; assign O_carry = I_a & I_b;endmodulemodule adder (input I_a,input I_b,input I_carry,output O_c,output O_carry );assign O_c = I_a ^ I_b ^ I_carry; assign O_carry = (I_a & I_b) | ((I_a ^ I_b) & I_carry);endmodule

仿真結果:

5 總結

數字集成電路設計可能對加法器的面積和版圖有較高的要求。對于FPGA設計,可能基本陣列加法器用著還更簡單順手。主要看的的題目可能問的是與一個常數相乘的設計,這個時候要參考 Booth 編碼的思想,因為不是實時乘數的話,預編碼之后確實還是節省資源的。

參考

數字集成電路-電路、系統與設計(第二版)

總結

以上是生活随笔為你收集整理的乘法器的实现(阵列、Booth、Wallace)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。