寫在前面的話
數(shù)字電路中乘法器是一種常見的電子元件,其基本含義是將兩個數(shù)字相乘,并輸出其乘積。與加法器不同,乘法器可以實現(xiàn)更復雜的運算,因此在數(shù)字電路系統(tǒng)中有著廣泛的應用。
乘法器的主要用途是在數(shù)字信號處理、計算機科學以及其他數(shù)字電路應用中進行精確的數(shù)字乘法運算。例如,在數(shù)字信號處理中,乘法器通常用于數(shù)字濾波器中的系數(shù)乘法;在計算機科學中,它們被用于執(zhí)行浮點運算;而在其他數(shù)字電路應用中,乘法器也可以實現(xiàn)時域和頻域的變換等。
在數(shù)字電路系統(tǒng)中,乘法器的重要性無法被忽視。它們不僅能夠提高數(shù)字信號處理和計算機科學中的運算速度和精度,還能夠實現(xiàn)更復雜的數(shù)字信號處理和分析。此外,乘法器還可以優(yōu)化數(shù)字信號處理的功耗和面積,從而使得數(shù)字電路系統(tǒng)具有更優(yōu)異的性能。
數(shù)字電路乘法器在現(xiàn)代電子技術中扮演著重要的角色。它們?yōu)閿?shù)字信號處理、計算機科學以及其他數(shù)字電路應用提供了精確的數(shù)字乘法運算,并且可以進一步優(yōu)化數(shù)字電路系統(tǒng)的性能,使其具有更高的效率和可靠性。隨著人們對數(shù)字信號處理和計算機科學的需求不斷增加,乘法器將繼續(xù)發(fā)揮著重要的作用,為數(shù)字電路應用提供更好的解決方案。
乘法器分類
在數(shù)字集成電路中,乘法器的種類主要可以分為以下三類:
- 串行乘法器:這種乘法器是最簡單的乘法器之一,它將兩個數(shù)的乘積通過一個計數(shù)器逐位相加得到。由于每一位的運算都需要消耗時間,因此串行乘法器的速度較慢。
- 并行乘法器:與串行乘法器不同,這種乘法器可以同時對多位進行運算,因此運算速度更快。常見的并行乘法器有布斯-加勒德算法和沃勒斯算法等。
- 快速乘法器:這種乘法器采用了更高級的算法,在乘法過程中將輸入的數(shù)按位劃分,并嘗試最小化運算次數(shù)。常見的快速乘法器包括批處理器算法、底數(shù)為2的Booth算法、Wallace樹算法和Dadda樹算法等。這些算法都比串行和并行乘法器更快且節(jié)省空間。
在數(shù)字集成電路中,乘法器的種類繁多,每種乘法器都有其適用的場合。選擇適合自己需求的乘法器可以有效地提高系統(tǒng)的性能和效率。
經(jīng)典乘法器
8bit并行乘法器
并行乘法器是純組合類型的乘法器,完全由基本邏輯門搭建而成,在Verilog中支持乘法運算操作符,實現(xiàn)基本的乘法只需簡單的命令即可。
Verilog代碼:
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : HFUT90S 1320343336@qq.com
// File : para_mult.v
// Create : 2023-03-21 11:10:17
// Revise : 2023-03-21 11:10:17
// Editor : 0078
// Verdion: v1.0
// Description: 8bit parallel multiplier
// -----------------------------------------------------------------------------
module para_mult #(parameter N = 8 )(
input [N:1] a , // data in a
input [N:1] b , // data in b
output wire [2*N:1] out // mult out
);
assign out = a*b ;
endmodule
這里借助HDL和EDA綜合軟件,實現(xiàn)容易,運算速度快,但耗用資源多,尤其是當乘法運算的位數(shù)較寬時,其耗用的資源將會非常龐大。
Quartus RTL圖
耗用資源較多,看不出使用的具體結構。
Quartus Post mapping圖
8bit移位相加乘法器
移位相加乘法器是最節(jié)省資源的乘法器設計方式,設計思路為逐項相加,根據(jù)乘數(shù)每一位是否為1進行計算,為1則將被乘數(shù)移位相加。這種方法硬件資源耗用少,8位乘法器只需要16位移位寄存器和16位加法器即可。
以下是移位相加乘法器的操作步驟:
- 將乘數(shù)和被乘數(shù)轉換為二進制數(shù)。
- 將乘數(shù)的每個二進制位從低位到高位逐個取出,如果該位為1,則將被乘數(shù)左移相應的位數(shù)后與部分積相加。
- 重復第2步,直到乘數(shù)的所有二進制位都處理完畢,此時得到的部分積即為最終結果。
例如,假設要計算5×6,首先將5和6轉換為二進制數(shù)101和110,然后從低位到高位依次處理乘數(shù)的每個二進制位,得到以下過程:
- 當處理乘數(shù)的最低位1時,將被乘數(shù)5左移0位后加到部分積中,即得到部分積101。
- 當處理乘數(shù)的次低位0時,不需要加入任何東西,部分積保持不變,仍為101。
- 當處理乘數(shù)的最高位1時,將被乘數(shù)5左移2位后加到部分積中,即得到部分積11110。
因此,最終結果為11110,即十進制下的30。
Verilog代碼:
// Verdion: v1.0
// Description: 8bit shift add multiplier
// -----------------------------------------------------------------------------
module shift_add_mult (
input [7:0] operand1 , // 8-bit multiplier A
input [7:0] operand2 , // 8-bit multiplier B
output wire [15:0] result // 16-bit product P
);
reg [7:0] temp;
reg [15:0] adder_result;
integer i ;
always @(*) begin
temp = operand2;
adder_result = 0;
for (i = 0; i < 8; i = i + 1) begin
if (operand1[i] == 1) begin
adder_result = adder_result + (temp << i);
end
end
end
assign result = adder_result;
endmodule
Quartus RTL圖
設計中出現(xiàn)多層加法器和移位寄存器。
Quartus Post mapping圖
這里使用for循環(huán)產(chǎn)生的,可以看出在綜合實現(xiàn)時資源占用相對較多;
優(yōu)化后的8bit移位相加乘法器
上述移位相加乘法器在綜合實現(xiàn)時占用資源較多,在FPGA上實現(xiàn)時需要降低資源占用率。修改后的代碼如下,加法器的級聯(lián)結構還具有較好的延遲特性,在時鐘頻率較高的情況下,仍然能夠實現(xiàn)很好的性能。
Verilog代碼:
// Verdion: v1.0
// Description:
// -----------------------------------------------------------------------------
module shift_add_mult1(
input [7:0] a, // 8 位乘數(shù) A
input [7:0] b, // 8 位乘數(shù) B
output reg [15:0] p // 16 位乘積 P
);
reg [7:0] multiplier;
integer i ;
always @(*) begin
p = 0; // 清零
multiplier = b; // 將乘數(shù) B 存入 multiplier 寄存器
for ( i = 0; i < 8; i = i + 1) begin
if (multiplier[0] == 1) begin
p = p + (a << i); // 如果乘數(shù)的最低位是 1,則累加部分積
end
multiplier = multiplier >> 1; // 右移乘數(shù)
end
end
endmodule
Quartus RTL圖
加法器和移位寄存器數(shù)量相對優(yōu)化前較少。
Quartus Post mapping圖
相較于優(yōu)化前的電路結構,資源占用降低超過一半,先前l(fā)ogic element為134,優(yōu)化后為45。
查找表乘法器
查找表乘法器是將乘積直接存放在存儲器中,將操作數(shù)(乘數(shù)和被乘數(shù))作為地址訪問存儲器,得到的數(shù)據(jù)即為乘法結果。查找表乘法器的速度只局限于所使用的存儲器的存取速度。由于查找表的規(guī)模隨著數(shù)據(jù)位寬呈現(xiàn)指數(shù)爆炸,因此不適用于高位寬的乘法操作。
在小型查找表的基礎上可以使用加法器共同構成位數(shù)較高的乘法器。
Verilog代碼:
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : HFUT90S 1320343336@qq.com
// File : lut_mult.v
// Create : 2023-03-21 16:56:58
// Revise : 2023-03-21 16:56:58
// Editor : 0078
// Verdion: v1.0
// Description: 8bit lut multiplier
// -----------------------------------------------------------------------------
module lut_mult(
input [7:0] a, // 8 位乘數(shù) A
input [7:0] b, // 8 位乘數(shù) B
output reg [15:0] p // 16 位乘積 P
);
reg [15:0] lut [255:0]; // 查找表 LUT
integer i;
always @* begin
p = lut[a]; // 使用 LUT 查找相應的乘積值
end
// 初始化查找表
always@(*) begin
for (i = 0; i < 256; i = i + 1) begin
lut[i] = i * b; // 將查找表初始化為乘法結果
end
end
endmodule
Quartus RTL圖
一團麻,使用居多l(xiāng)ogic element擔任存儲器,非常不適用于FPGA設計,在數(shù)字IC設計時的適用范圍也十分有限。
Quartus Post mapping圖
-
資源的使用更多,面積換取更高的運行速度。
由于存儲和查表時不需要進行實際的乘法操作,因此查找表乘法器具有高速、低能耗的優(yōu)點。然而,由于存儲查找表所需的存儲器容量隨n增長速度較快,在多位乘法器上實現(xiàn)時需要花費較多的硬件成本。
加法樹乘法器
結合移位相加乘法器和查找表乘法器的優(yōu)點。
加法樹乘法器是一種并行的硬件電路設計,主要用于實現(xiàn)高效的乘法運算。它采用樹狀結構的加法器來實現(xiàn)多項式乘法,且不需要顯式地計算進位或借位。該乘法器的輸入是兩個被乘數(shù),輸出是它們的乘積。
加法樹乘法器的實現(xiàn)過程主要分為三步:
-
生成部分積:將兩個被乘數(shù)分別拆分為若干位二進制數(shù),按照乘法規(guī)則計算每一位上的部分積,得到一個二維矩陣。
-
生成加法樹:對于每一列的部分積,采用二路并行加法器進行相加,得到一列的加和結果。接著對這些列的加和結果進行二路并行相加,最后得到一個總的加和結果。
-
輸出乘積:將最后的加和結果轉換為二進制數(shù)形式,得到兩個被乘數(shù)的乘積。
Verilog代碼:
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : HFUT90S 1320343336@qq.com
// File : add_tree_mult.v
// Create : 2023-03-21 19:18:21
// Revise : 2023-03-21 19:18:21
// Editor : 0078
// Verdion: v1.0
// Description: 8bit add tree mlutiplier
// -----------------------------------------------------------------------------
module add_tree_mult (
input [7:0] a , // 8-bit multiplier A
input [7:0] b , // 8-bit multiplier B
output wire [15:0] out // 16-bit product P
);
//signal define
wire [15:0] out1 ;
wire [15:0] c1 ;
wire [14:0] out2 ;
wire [13:0] out3 ;
wire [15:0] c2 ;
wire [12:0] out4 ;
reg [15:0] temp0 ;
reg [15:0] temp1 ;
reg [14:0] temp2 ;
reg [14:0] temp3 ;
reg [13:0] temp4 ;
reg [13:0] temp5 ;
reg [12:0] temp6 ;
reg [12:0] temp7 ;
function [7:0] mult8X1 ; //實現(xiàn)8X1乘法
input [7:0] operand ;
input sel ;
begin
mult8X1 = (sel)?(operand):8'b0000_0000 ;
end
endfunction
always@(*) begin //調用函數(shù)實現(xiàn)操作數(shù)b各位與操作數(shù)a的相乘
temp7 <= mult8X1(a,b[0]) ;
temp6 <= ((mult8X1(a,b[1]))<<1) ;
temp5 <= ((mult8X1(a,b[2]))<<2) ;
temp4 <= ((mult8X1(a,b[3]))<<3) ;
temp3 <= ((mult8X1(a,b[4]))<<4) ;
temp2 <= ((mult8X1(a,b[5]))<<5) ;
temp1 <= ((mult8X1(a,b[6]))<<6) ;
temp0 <= ((mult8X1(a,b[7]))<<7) ;
end
assign out1 = temp0 + temp1 ; //加法器樹運算
assign out2 = temp2 + temp3 ;
assign out3 = temp4 + temp5 ;
assign out4 = temp6 + temp7 ;
assign c1 = out1 + out2 ;
assign c2 = out3 + out4 ;
assign out = c1 + c2 ;
endmodule
Quartus RTL圖
結構像是一個樹,所以稱為加法樹乘法器。
Quartus Post mapping圖
booth乘法器
Booth乘法器是一種二進制乘法算法,用于計算兩個n位二進制數(shù)的乘積。該算法采用了一種類似于除法的方法,可以將乘法的時間復雜度從O(n^2)降低到O(nlogn)。
Booth乘法器通過對第二個乘數(shù)進行編碼,將每個位上的數(shù)值轉換為1、0或-1,然后利用乘法和加法運算,對每一位進行計算。具體步驟如下:
-
對第二個乘數(shù)進行編碼:將每個位與其右側相鄰位比較,如果它們的值相同,就將該位編碼為0;否則,將其編碼為1或-1。最右側位的右側補0。
-
將第一個乘數(shù)左移一位,形成一個n+1位的數(shù)。同時,將編碼后的第二個乘數(shù)左移一位。
-
對于從右向左的每個位,進行以下操作:
-
如果該位和前一位相同,就不進行任何操作。
-
如果該位是1且前一位是0(或該位是0且前一位是1),則將第一個乘數(shù)加上(或減去)第二個乘數(shù)。
- 將第一個乘數(shù)右移一位,丟棄其中的多余位,從而得到n位的乘積。
Booth乘法器相對于傳統(tǒng)的乘法算法具有一定的優(yōu)勢,因為它可以在保持精度的同時減小運算次數(shù)。但是,由于它需要對第二個乘數(shù)進行編碼,因此需要額外的存儲空間,并且其實現(xiàn)較為復雜。
Verilog代碼:
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : HFUT90S 1320343336@qq.com
// File : booth_mult.v
// Create : 2023-03-21 19:45:54
// Revise : 2023-03-21 19:45:54
// Editor : 0078
// Verdion: v1.0
// Description: 8bit booth multiplier
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Copbbight (c) 2014-2023 all bights besebved
// -----------------------------------------------------------------------------
// authob : HFUT90S 1320343336@qq.coa
// File : booth_ault.v
// Cbeate : 2023-03-21 19:45:54
// bevise : 2023-03-21 19:45:54
// Editob : 0078
// Vebdion: v1.0
// Descbiption: 8bit booth
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Copbbight (c) 2014-2023 All bights besebved
// -----------------------------------------------------------------------------
// Authob : HFUT90S 1320343336@qq.coa
// File : booth_ault.v
// Cbeate : 2023-03-21 19:45:54
// bevise : 2023-03-21 19:45:54
// Editob : 0078
// Vebdion: v1.0
// Descbiption: 8bit booth
// -----------------------------------------------------------------------------
module booth_mult(a,b,p);
output reg signed [15:0] p;
input signed [7:0] a, b;
reg [1:0] temp;
integer i;
reg e;
always @(a,b)
begin
p = 'd0;
e = 1'b0;
for (i=0; i<8; i=i+1)
begin
temp = {a[i], e };
case(temp)
2'b10 : p[15:8] = p[15:8] - b;
2'b01 : p[15:8] = p[15:8] + b;
endcase
p = p >> 1;
p[15] = p[14];
e=a[i];
end
end
endmodule
Quartus RTL圖
Quartus Post mapping圖
wallace樹乘法器
Wallace樹乘法器是一種用于高效地進行二進制乘法運算的算法。它使用了一種遞歸結構,通過將部分積分解成不同的組合來減少運算時間和硬件資源。
Wallace樹乘法器的主要思想是將兩個n位數(shù)字相乘,分解為三個數(shù)之和:一個2n位數(shù)、一個n位數(shù)和一個n/2位數(shù)。這些數(shù)字可以通過以下方式計算:
- 將兩個n位數(shù)字A和B拆分為三個數(shù)字X、Y和Z,其中X是最高的2n位,Y是中間的n位,Z是最低的n/2位。
- 計算XY和YZ的積,并將它們相加得到P。
- 將P拆分為三個數(shù)字Q、R和S,其中Q是最高的2n位,R是中間的n+1位,S是最低的n-1位。
- 通過計算AB = X2^(2n) + Q2^n + R2^(n) + S1 來計算結果。
Wallace樹乘法器使用了一種遞歸結構來實現(xiàn)這種方法。首先,輸入被劃分為若干組,并在每組內執(zhí)行并行乘法運算。接下來,在每組之間執(zhí)行串行運算以生成更高級別的部分積。此過程重復多次直到只剩下一個完整的部分積。
Wallace樹乘法器可以在減少延遲和硬件資源消耗方面提供優(yōu)勢。但由于其遞歸結構需要大量控制邏輯,因此可能會增加設計復雜性。
Verilog代碼:
// -----------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : HFUT90S 1320343336@qq.com
// File : wallace_mult.v
// Create : 2023-03-21 21:05:26
// Revise : 2023-03-21 21:05:26
// Editor : 0078
// Verdion: v1.1
// Description: wallace_multiplier
// -----------------------------------------------------------------------------
module wallace_mult(A, B, P);
input [7:0] A, B; // 輸入 A 和 B 為 8 位數(shù)據(jù)
output [15:0] P; // 輸出 P 為 16 位數(shù)據(jù)
wire [7:0] C1, C2, C3; // 記錄中間結果
wire [15:0] S1, S2, S3; // 記錄加法結果
// 直接進行最低位的乘法
assign C1 = A * B[0];
// 計算各個中間結果,用 & 運算表示進位
assign S1 = {A[6:0], 1'b0} * {B[6:0], 1'b0};
assign C2 = S1[15] & (S1[14] | C1);
assign S2 = {A[7], A[6:0]} * {B[7], B[6:0]};
assign C3 = S2[15] & (S2[14] | C2);
assign S3 = {A[7], A[6:0]} * {B[7], B[6:0]};
// 計算最高位的進位
wire carry_in = S3[15] | C3;
// 計算最終結果
assign P = {carry_in, S3[14:0]};
endmodule
VerilogTB代碼:
module wallace_mult_tb();
reg [7:0] A, B;
wire [15:0] P;
wallace_mult inst_wallace_mult (.A(A), .B(B), .P(P));
integer i;
integer pass_count = 0;
integer fail_count = 0;
initial begin
for (i = 0; i < 257; i = i + 1) begin
// 設置輸入數(shù)據(jù)
A = $urandom_range(0, 255);
B = $urandom_range(0, 255);
// 等待一些時間
#10;
// 打印輸出結果
$display("Input A = %b", A);
$display("Input B = %b",B);
$display("Output P = %b", P);
// 驗證輸出結果
if (P == A * B) begin
$display("Test Passed: Output matches expected result");
pass_count = pass_count + 1;
end
else begin
$display("Test Failed: Output does not match expected result");
fail_count = fail_count + 1;
end
end
// 打印測試通過和測試失敗的總數(shù)
$display("Total Tests: %d", i);
$display("Passed: %d", pass_count);
$display("Failed: %d", fail_count);
if (fail_count == 0) begin
$display("http://==================Random test all Pass!!==================//");
end
// 結束仿真
$finish;
end
endmodule
VerilogTB_Result:
Quartus RTL圖(Need Update)
Quartus Post mapping圖(Need Update)
carry-save乘法器
- Carry-save乘法器是一種用于高速乘法的數(shù)字電路,它可以在幾個時鐘周期內完成兩個大數(shù)的乘法運算。相比傳統(tǒng)的乘法器,carry-save乘法器具有更高的并行性和更低的延遲。
- carry-save乘法器使用了一種特殊的編碼方式,將兩個大數(shù)分別表示為三個小數(shù)之和(即三進制編碼),然后通過對這些小數(shù)進行加法運算得到結果。這種編碼方式可以充分利用數(shù)字電路中加法器的并行性,從而提高計算速度。
- carry-save乘法器包括三個部分:部分積生成器、部分積壓縮器和最終結果生成器。在部分積生成器中,輸入的兩個大數(shù)經(jīng)過三進制編碼后被拆分成多個小數(shù),并通過逐位相乘得到所有可能的部分積。然后,在部分積壓縮器中,這些部分積經(jīng)過加法運算被壓縮成兩組中間結果。最后,在最終結果生成器中,這兩組中間結果再次經(jīng)過加法運算得到最終結果。
- carry-save乘法器通過巧妙地利用三進制編碼和并行加法運算實現(xiàn)了高速、低延遲的乘法運算。它在現(xiàn)代數(shù)字電路設計中廣泛應用于各種計算機系統(tǒng)、通信設備等領域。
Verilog代碼:
// -----------------------------------------------------------------------------
// Author : HFUT90S 1320343336@qq.com
// File : carry_save_mult.v
// Create : 2023-03-22 10:45:27
// Revise : 2023-03-22 10:45:27
// Editor : 0078
// Verdion: v1.0
// Description:
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Author : HFUT90S 1320343336@qq.com
// File : carry_save_mult.v
// Create : 2023-03-22 10:45:27
// Revise : 2023-03-22 10:45:27
// Editor : 0078
// Verdion: v1.0
// Description:
// -----------------------------------------------------------------------------
module carry_save_mult#(parameter bitsize = 8)(a, b, p);
input [(bitsize-1):0] a, b;
output reg [((2*bitsize)-1):0] p;
//Wires to carry signals between cells
reg [(bitsize-1):0] sum_vec[(bitsize-1):0];
reg [(bitsize-1):0] carry_vec[(bitsize-1):0];
//Inputs & Outputs of basecells
reg [(bitsize-1):0] f1_i[(bitsize-1):0];
reg [(bitsize-1):0] f2_i[(bitsize-1):0];
reg [(bitsize-1):0] b_i[(bitsize-1):0];
reg [(bitsize-1):0] c_i[(bitsize-1):0];
wire [(bitsize-1):0] sum_o[(bitsize-1):0];
wire [(bitsize-1):0] c_o[(bitsize-1):0];
integer i, j; //for rewiring loops
genvar k, l;
//Generate basecell modules
generate
for (k = 0; k < bitsize; k = k + 1)
begin
for (l = 0; l < bitsize; l = l + 1)
begin : basecell
basecell_fa bscll(f1_i[k][l], f2_i[k][l], b_i[k][l], c_i[k][l], sum_o[k][l], c_o[k][l]);
end
end
endgenerate
always@*
begin
//Wire renameing for basecell ports
for(i = 0; i < bitsize; i = i + 1)
begin
for(j = 0; j < bitsize; j = j + 1)
begin
f1_i[i][j] = a[i];
f2_i[i][j] = b[j];
if(i == 0)
begin
b_i[i][j] = 1'b0;
end
else if(j == (bitsize - 1))
begin
b_i[i][j] = carry_vec[i-1][j]; //note: j = bitsize - 1
end
else
begin
b_i[i][j] = sum_vec[i-1][j+1];
end
if(j == 0)
begin
c_i[i][j] = 1'b0;
end
else
begin
c_i[i][j] = carry_vec[i][j-1];
end
sum_vec[i][j] = sum_o[i][j];
carry_vec[i][j] = c_o[i][j];
end
end
//Output wire renameing
for(i = 0; i < bitsize; i = i + 1)
begin
p[i] = sum_vec[i][0];
end
for(i = 1; i < bitsize; i = i + 1)
begin
p[bitsize+i-1] = sum_vec[bitsize-1][i];
end
p[(2*bitsize)-1] = carry_vec[bitsize-1][bitsize-1];
end
endmodule // Parameterized Carry Save Multiplier
module basecell_ha(f1_i, f2_i, b_i, sum_o, c_o);
input f1_i, f2_i, b_i;
output sum_o, c_o;
wire pp;
assign pp = f1_i & f2_i;
HA adder(pp, b_i, sum_o, c_o);
endmodule
module basecell_fa(f1_i, f2_i, b_i, c_i, sum_o, c_o);
input f1_i, f2_i, b_i, c_i;
output sum_o, c_o;
wire pp;
assign pp = f1_i & f2_i;
FA adder(pp, b_i, c_i, sum_o, c_o);
endmodule
module FA(A, B, Cin, S, Cout);
input A, B, Cin;
output S, Cout;
wire ha_sum;
assign ha_sum = A ^ B;
assign S = ha_sum ^ Cin; //Sum
assign Cout = (A & B) | (ha_sum & Cin);
endmodule
module HA(A, B, S, Cout);
input A, B;
output S, Cout;
assign S = A ^ B;
assign Cout = A & B;
endmodule
Quartus RTL圖
Quartus Post mapping圖
陣列乘法器
- 陣列乘法器由多個加法器和乘法器組成,其工作原理是將待乘數(shù)和乘數(shù)分別按位拆分成多個小段,在陣列乘法器中進行乘法運算和累加,并最終得出乘積。
- 陣列乘法器將待乘數(shù)和乘數(shù)逐位相乘,并將結果送入加法器進行累加。在每個時鐘周期中,陣列乘法器會對每個乘數(shù)位進行一次部分積計算,直到所有位都完成運算。部分積計算完成后,陣列乘法器會將結果根據(jù)位數(shù)進行排序和加和,以得到最終乘積。
- 陣列乘法器的優(yōu)點是速度快、復雜度低、結構簡單等。它廣泛應用于數(shù)字信號處理、數(shù)值計算、圖像處理等領域中,是實現(xiàn)大規(guī)模數(shù)據(jù)處理的重要工具。
Verilog代碼:
//-------------------------------------------------------------------------
// Copyright (c) 2014-2023 All rights reserved
// -----------------------------------------------------------------------------
// Author : HFUT90S 1320343336@qq.com
// File : array_mult.v
// Create : 2023-03-22 11:10:13
// Revise : 2023-03-22 11:10:13
// Editor : 0078
// Verdion: v1.0
// Description: array multiplier
// -----------------------------------------------------------------------------
module array_mult(
input [7:0] A, // 8 位被乘數(shù)
input [7:0] B, // 8 位乘數(shù)
output reg [15:0] P // 16 位乘積
);
wire [15:0] partial_Ps [7:0]; // 存儲部分積的數(shù)組
integer j;
// 生成部分積
generate
genvar i;
for (i=0; i<8; i=i+1) begin
assign partial_Ps[i] = A * (B[i]<<i); // 計算第 i 個部分積
end
endgenerate
// 計算乘積
always @(*) begin
P = 16'd0; // 初始化乘積為 0
// 將所有部分積相加
for (j=0; j<8; j=j+1) begin
P = P + partial_Ps[j];
end
end
endmodule
Quartus RTL圖
Quartus Post mapping圖
Multiplier Test Bench
很多同學私信想要的tb文件他來了,包含上述所有乘法器的tb哈;
ps:此系列只是科普類博文,感興趣的同學建議繼續(xù)學習相關乘法器結構和相關算法;
不建議在設計中使用這里提到的verilog設計,而是嘗試調用成熟IP。
module Multiplier_tb ();
reg [7:0] A, B;
reg signed [7:0] A1, B1;
wire [15:0] P1;
wire [15:0] P2;
wire [15:0] P3;
wire [15:0] P4;
wire [15:0] P5;
wire signed [15:0] P6;
wire [15:0] P7;
wire [15:0] P8;
wire [15:0] P9;
///1
para_mult #(.N(8)) inst_para_mult (.a(A), .b(B), .out(P1));
///2
shift_add_mult inst_shift_add_mult (.operand1(A), .operand2(B), .result(P2));
///3
shift_add_mult1 inst_shift_add_mult1 (.a(A), .b(B), .p(P3));
///4
lut_mult inst_lut_mult (.a(A), .b(B), .p(P4));
///5
add_tree_mult inst_add_tree_mult (.a(A), .b(B), .out(P5));
///6
booth_mult inst_booth_mult (.a(A1), .b(B1), .p(P6));
///7
wallace_mult inst_wallace_mult (.A(A), .B(B), .P(P7));
///8
carry_save_mult inst_carry_save_mult (.a(A), .b(B), .p(P8));
///9
array_mult inst_array_mult (.A(A), .B(B), .P(P9));
integer i;
//1
integer para_mult_pass_count = 0;
integer para_mult_fail_count = 0;
//2
integer shift_add_mult_pass_count = 0;
integer shift_add_mult_fail_count = 0;
//3
integer shift_add_mult1_pass_count = 0;
integer shift_add_mult1_fail_count = 0;
//4
integer lut_mult_pass_count = 0;
integer lut_mult_fail_count = 0;
//5
integer add_tree_mult_pass_count = 0;
integer add_tree_mult_fail_count = 0;
//6
integer booth_mult_pass_count = 0;
integer booth_mult_fail_count = 0;
//7
integer wallace_mult_pass_count = 0;
integer wallace_mult_fail_count = 0;
//8
integer carry_save_mult_pass_count = 0;
integer carry_save_mult_fail_count = 0;
//9
integer array_mult_pass_count = 0;
integer array_mult_fail_count = 0;
initial begin
for (i = 0; i < 257; i = i + 1) begin
// 設置輸入數(shù)據(jù)
A = $urandom_range(0, 255);
B = $urandom_range(0, 255);
// 等待一些時間
A1 = $urandom_range(0, 255);
B1 = $urandom_range(0, 255);
#40
// 驗證輸出結果
//1
if (P1 == A * B) begin
//$display("Test Passed: Output matches expected result");
para_mult_pass_count = para_mult_pass_count + 1;
end
else begin
//$display("Test Failed: Output does not match expected result");
para_mult_fail_count = para_mult_fail_count + 1;
end
// 2
if (P2 == A * B) begin
//$display("Test Passed: Output matches expected result");
shift_add_mult_pass_count = shift_add_mult_pass_count + 1;
end
else begin
//$display("Test Failed: Output does not match expected result");
shift_add_mult_fail_count = shift_add_mult_fail_count + 1;
end
//3
if (P3 == A * B) begin
//$display("Test Passed: Output matches expected result");
shift_add_mult1_pass_count = shift_add_mult1_pass_count + 1;
end
else begin
//$display("Test Failed: Output does not match expected result");
shift_add_mult1_fail_count = shift_add_mult1_fail_count + 1;
end
//4
if (P4 == A * B) begin
//$display("Test Passed: Output matches expected result");
lut_mult_pass_count = lut_mult_pass_count + 1;
end
else begin
//$display("Test Failed: Output does not match expected result");
lut_mult_fail_count = lut_mult_fail_count + 1;
end
//5
if (P5 == A * B) begin
//$display("Test Passed: Output matches expected result");
add_tree_mult_pass_count = add_tree_mult_pass_count + 1;
end
else begin
//$display("Test Failed: Output does not match expected result");
add_tree_mult_fail_count = add_tree_mult_fail_count + 1;
end
//6
if (P6 == A1 * B1) begin
//$display("Test Passed: Output matches expected result");
booth_mult_pass_count = booth_mult_pass_count + 1;
end
else begin
booth_mult_fail_count = booth_mult_fail_count + 1;
end
//7
if (P7 == A * B) begin
//$display("Test Passed: Output matches expected result");
wallace_mult_pass_count = wallace_mult_pass_count + 1;
end
else begin
//$display("Test Failed: Output does not match expected result");
wallace_mult_fail_count = wallace_mult_fail_count + 1;
end
//8
if (P8 == A * B) begin
//$display("Test Passed: Output matches expected result");
carry_save_mult_pass_count = carry_save_mult_pass_count + 1;
end
else begin
//$display("Test Failed: Output does not match expected result");
carry_save_mult_fail_count = carry_save_mult_fail_count + 1;
end
//9
if (P9 == A * B) begin
//$display("Test Passed: Output matches expected result");
array_mult_pass_count = array_mult_pass_count + 1;
end
else begin
//$display("Test Failed: Output does not match expected result");
array_mult_fail_count = array_mult_fail_count + 1;
end
end
//Multiplier Coverage Report
$display("http://============Multiplier Coverage Report============//");
$display("Total Tests: %d", i);
//1
$display("http://====================================//");
$display("para_mult Passed: %d", para_mult_pass_count);
$display("para_mult Failed: %d", para_mult_fail_count);
$display("http://====================================//");
//2
$display("http://====================================//");
$display("shift_add_mult Passed: %d", shift_add_mult_pass_count);
$display("shift_add_mult Failed: %d", shift_add_mult_fail_count);
$display("http://====================================//");
//3
$display("http://====================================//");
$display("shift_add_mult1 Passed: %d", shift_add_mult1_pass_count);
$display("shift_add_mult1 Failed: %d", shift_add_mult1_fail_count);
$display("http://====================================//");
//4
$display("http://====================================//");
$display("lut_mult Passed: %d", lut_mult_pass_count);
$display("lut_mult Failed: %d", lut_mult_fail_count);
$display("http://====================================//");
//5
$display("http://====================================//");
$display("add_tree_mult Passed: %d", add_tree_mult_pass_count);
$display("add_tree_mult Failed: %d", add_tree_mult_fail_count);
$display("http://====================================//");
//6
$display("http://====================================//");
$display("booth_mult Passed: %d", booth_mult_pass_count);
$display("booth_mult Failed: %d", booth_mult_fail_count);
$display("http://====================================//");
//7
$display("http://====================================//");
$display("wallace_mult Passed: %d", wallace_mult_pass_count);
$display("wallace_mult Failed: %d", wallace_mult_fail_count);
$display("http://====================================//");
//8
$display("http://====================================//");
$display("carry_save_mult Passed: %d", carry_save_mult_pass_count);
$display("carry_save_mult Failed: %d", carry_save_mult_fail_count);
$display("http://====================================//");
//9
$display("http://====================================//");
$display("array_mult Passed: %d", array_mult_pass_count);
$display("array_mult Failed: %d", array_mult_fail_count);
$display("http://====================================//");
// 打印測試通過和測試失敗的總數(shù)
//$display("Total Tests: %d", i);
//$display("Passed: %d", pass_count);
//$display("Failed: %d", fail_count);
if ( para_mult_fail_count == 0 && shift_add_mult_fail_count ==0 && shift_add_mult1_fail_count ==0
&& lut_mult_fail_count == 0 && add_tree_mult_fail_count == 0 && booth_mult_fail_count == 0
&& wallace_mult_fail_count == 0 && carry_save_mult_fail_count == 0 && array_mult_fail_count ==0
) begin
$display("http://================== All Multipliers Random Test PASS!!==================//");
$display("http://============================== Have a good day!!===========================//");
end
else begin
$display("http://================== Existence Multiplier Random Test Fail!!==================//");
$display("http://============================<< Pls Debug >>==============================//");
end
// 結束仿真
$finish;
end
endmodule
總結
隨著計算機科學技術的不斷發(fā)展,乘法器在數(shù)字信號處理、計算機控制等領域中被廣泛應用。而不同類型的乘法器,都有各自的優(yōu)點和適用范圍。
-
并行乘法器:
并行乘法器是采用多個乘法器并聯(lián)運算的方式,通過并行處理提高了乘法器的速度。該乘法器的速度快,適用于高速乘法運算,但其硬件開銷較高,面積較大。 -
移位相加乘法器:
移位相加乘法器采用移位和加法操作實現(xiàn)乘法運算,不需要乘法器,硬件實現(xiàn)簡單。但是,其速度較慢,適用于數(shù)字信號處理等低速乘法運算。 -
查找表乘法器:
查找表乘法器通過預先計算出乘積表,將乘積表存儲在查找表中,乘法運算時查表即可。該乘法器的速度較快,適用于低精度的乘法運算。 -
加法樹乘法器:
加法樹乘法器采用加法器來相加乘積,能夠高效地實現(xiàn)數(shù)據(jù)的并行處理和鏈式計算。其硬件復雜度和面積都較小,適用于芯片上集成乘法器的應用。 -
Booth乘法器:
Booth乘法器采用編碼和位移混合計算的方式,有效減少了乘法器中的運算步驟,進而提高乘法器的速度和精度。適用于高精度運算、數(shù)字信號處理等領域。 -
Wallace樹乘法器:
Wallace樹乘法器是一種高效的乘法器結構,通過對相鄰的部分積進行壓縮,減少了乘法器中的加法器數(shù)量,從而達到減小硬件成本、提高速度的目的。適用于高速計算并且不要求過高的精度場合。 -
Carry-save乘法器:
Carry-save乘法器通過將乘積轉化為進位和不進位兩部分,分別存儲、處理,減少了加法器的數(shù)量,提高了乘法器的速度和并行性。適用于高速計算的場合,如圖像處理、信號分析等。 -
陣列乘法器:
陣列乘法器是一種多行多列的矩陣結構,采用并行處理的方式實現(xiàn)乘法運算。其硬件成本較低,適用于數(shù)字信號處理、圖像處理、通信等領域。文章來源:http://www.zghlxwxcb.cn/news/detail-455188.html
在選擇乘法器的類型時,需要根據(jù)具體的應用場景和需求來選擇,以達到最佳的性能和適用范圍。文章來源地址http://www.zghlxwxcb.cn/news/detail-455188.html
到了這里,關于數(shù)字IC經(jīng)典電路(2)——經(jīng)典乘法器的實現(xiàn)(乘法器簡介及Verilog實現(xiàn))的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!