基于Verilog的32位有符号流水线乘法器设计与实现
1.二进制乘法运算机制
1.1无符号数乘法运算
以4位乘法器为例,计算2×6:
0 0 0 0 0 0 1 0 (2)
X 0 0 0 0 0 1 1 0 (6)
---------------------
0 0 0 0 0 0 0 0 (0)
0 0 0 0 0 1 0 0 (4)
0 0 0 0 1 0 0 0 (8)
0 0 0 0 0 0 0 0 (0)
0 0 0 0 0 0 0 0 (0)
0 0 0 0 0 0 0 0 (0)
0 0 0 0 0 0 0 0 (0)
0 0 0 0 0 0 0 0 (0)
---------------------
0 0 0 0 1 1 0 0 (12)
注意:4位×4位乘法器的最大结果位宽为8位(4+4)。在计算时,需要将乘数和被乘数通过符号位扩展到相应位宽。对于无符号乘法,虽然扩展的符号位没有实际作用,但对于有符号运算则是必需的。考虑到模块需要同时支持有符号和无符号运算,建议统一进行位宽扩展。
1.2有符号数乘法运算
计算-2 × -6:
1 1 1 1 1 1 1 0 (-2)
X 1 1 1 1 1 0 1 0 (-6)
---------------------
0 0 0 0 0 0 0 0
1 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0
1 1 1 1 0 0 0 0
1 1 1 0 0 0 0 0
1 1 0 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
---------------------
0 0 0 0 1 1 0 0 (12)
1.3混合符号乘法运算
有符号×无符号(-2 × 6):
1 1 1 1 1 1 1 0 (-2)
X 0 0 0 0 0 1 1 0 (6)
---------------------
0 0 0 0 0 0 0 0
1 1 1 1 1 1 0 0
1 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
---------------------
1 1 1 1 0 1 0 0 (-12)
无符号×有符号(2 × -6):
0 0 0 0 0 0 1 0 (2)
X 1 1 1 1 1 0 1 0 (-6)
---------------------
0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0
0 1 0 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
---------------------
1 1 1 1 0 1 0 0 (-12)
2.乘法运算优化策略
通过对上述四种运算方式的分析,可以总结出一个重要规律:符号位本身不影响运算流程,仅影响最终结果的截取位置。
以无符号×有符号为例进行说明:bin(00000010)表示十进制2,而bin(11111010)作为有符号数时表示-6,作为无符号数时表示250。因此,2×250的结果若只取低8位,作为有符号数则为bin(11110100) = -12。这表明有符号乘法可以转换为无符号乘法进行计算,最后通过控制截位位置即可得到正确结果。
以下以-1000 × -1200为例说明16位乘法的简化过程:
2.1位宽扩展处理
dec(-1000) = bin(11111111111111111111110000011000) = dec(4294966296)
dec(-1200) = bin(11111111111111111111101101010000) = dec(4294966096)
2.2乘数分解与移位运算
将十进制数按2的幂次进行分解:
dec(4294966096) = 1×2^31 + 1×2^30 + 1×2^29 + 1×2^28 +
1×2^27 + 1×2^26 + 1×2^25 + 1×2^24 + 1×2^23 + 1×2^22 +
1×2^21 + 1×2^20 + 1×2^19 + 1×2^18 + 1×2^17 + 1×2^16 +
1×2^15 + 1×2^14 + 1×2^13 + 1×2^12 + 1×2^11 + 0×2^10 +
1×2^9 + 1×2^8 + 0×2^7 + 1×2^6 + 0×2^5 + 1×2^4 + 0×2^3 +
0×2^2 + 0×2^1 + 0×2^0
由此可得:
dec(4294966296) × dec(4294966096) = dec(4294966296)×2^31 + dec(4294966296)×2^30 +
dec(4294966296)×2^29 + dec(4294966296)×2^28 + dec(4294966296)×2^27 +
dec(4294966296)×2^26 + dec(4294966296)×2^25 + dec(4294966296)×2^24 +
dec(4294966296)×2^23 + dec(4294966296)×2^22 + dec(4294966296)×2^21 +
dec(4294966296)×2^20 + dec(4294966296)×2^19 + dec(4294966296)×2^18 +
dec(4294966296)×2^17 + dec(4294966296)×2^16 + dec(4294966296)×2^15 +
dec(4294966296)×2^14 + dec(4294966296)×2^13 + dec(4294966296)×2^12 +
dec(4294966296)×2^11 + 0×2^10 + dec(4294966296)×2^9 + dec(4294966296)×2^8 +
0×2^7 + dec(4294966296)×2^6 + 0×2^5 + dec(4294966296)×2^4 + 0×2^3 +
0×2^2 + 0×2^1 + 0×2^0
虽然公式看起来复杂,但将指数视为左移运算符后,乘法运算就转化为移位和加法的组合。
2.3流水线加法结构
对于表达式 num = a + b + c + d + e + f + g + h,可以采用树形流水线结构进行优化:
2.4结果截取
dec(4294966296) × dec(4294966096) = hex(FFFFF76800124F80)
其中16位×16位乘法器的最大位宽为32位,取低32位:
hex(00124F80) = dec(1200000)
至此,一个完整的乘法运算流程得以实现。
3.Verilog硬件实现
3.1 16位流水线乘法器
16位有符号乘法器实现代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/03/28 22:54:41
// Design Name:
// Module Name: multiplier_16
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies: 16位有符号乘法器
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module multiplier_16
#(
parameter A_WIDTH = 16 ,
parameter A_SIGNED = 1 ,
parameter B_WIDTH = 16 ,
parameter B_SIGNED = 1
)
(
input clk ,
input rst ,
input [A_WIDTH-1:0] data_a,
input [B_WIDTH-1:0] data_b,
output [A_WIDTH + B_WIDTH - 1:0] product
);
wire [32-1:0] extend_a;
wire [32-1:0] extend_b;
assign extend_a = A_SIGNED ? {{(32-A_WIDTH){data_a[A_WIDTH-1]}}, data_a} :
{(32-A_WIDTH){1'b0}}, data_a};
assign extend_b = B_SIGNED ? {{(32-B_WIDTH){data_b[B_WIDTH-1]}}, data_b} :
{(32-B_WIDTH){1'b0}}, data_b};
genvar idx0;
reg [31:0] partial_sum0 [15:0];
generate
for (idx0 = 0; idx0 <= 15; idx0 = idx0 + 1) begin : gen_stage0
always @(posedge clk) begin
if (rst) begin
partial_sum0[idx0] <= 0;
end else begin
case({extend_b[2*idx0+1], extend_b[2*idx0]})
2'b00: begin
partial_sum0[idx0] <= 0;
end
2'b01: begin
partial_sum0[idx0] <= extend_a << (2*idx0);
end
2'b10: begin
partial_sum0[idx0] <= ({extend_a[30:0], 1'b0}) << (2*idx0);
end
2'b11: begin
partial_sum0[idx0] <= ({extend_a[30:0], 1'b0} + extend_a) << (2*idx0);
end
endcase
end
end
end
endgenerate
genvar idx1;
reg [31:0] partial_sum1 [7:0];
generate
for (idx1 = 0; idx1 <= 7; idx1 = idx1 + 1) begin : gen_stage1
always @(posedge clk) begin
if (rst) begin
partial_sum1[idx1] <= 0;
end else begin
partial_sum1[idx1] <= partial_sum0[2*idx1] + partial_sum0[2*idx1+1];
end
end
end
endgenerate
genvar idx2;
reg [31:0] partial_sum2 [3:0];
generate
for (idx2 = 0; idx2 <= 3; idx2 = idx2 + 1) begin : gen_stage2
always @(posedge clk) begin
if (rst) begin
partial_sum2[idx2] <= 0;
end else begin
partial_sum2[idx2] <= partial_sum1[2*idx2] + partial_sum1[2*idx2+1];
end
end
end
endgenerate
genvar idx3;
reg [31:0] partial_sum3 [1:0];
generate
for (idx3 = 0; idx3 <= 1; idx3 = idx3 + 1) begin : gen_stage3
always @(posedge clk) begin
if (rst) begin
partial_sum3[idx3] <= 0;
end else begin
partial_sum3[idx3] <= partial_sum2[2*idx3] + partial_sum2[2*idx3+1];
end
end
end
endgenerate
reg [31:0] final_result;
always @(posedge clk) begin
if (rst) begin
final_result <= 0;
end else begin
final_result <= partial_sum3[0] + partial_sum3[1];
end
end
assign product = final_result;
endmodule
3.2 32位流水线乘法器
32位有符号乘法器实现代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/09/11 22:21:12
// Design Name:
// Module Name: multiplier_pp
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module multiplier
#(
parameter A_WIDTH = 32 ,
parameter A_SIGNED = 1 ,
parameter B_WIDTH = 32 ,
parameter B_SIGNED = 1
)
(
input clk ,
input rst ,
input [A_WIDTH-1:0] data_a,
input [B_WIDTH-1:0] data_b,
output [A_WIDTH + B_WIDTH - 1:0] product
);
wire [64-1:0] extend_a;
wire [64-1:0] extend_b;
assign extend_a = A_SIGNED ? {{(64-A_WIDTH){data_a[A_WIDTH-1]}}, data_a} :
{(64-A_WIDTH){1'b0}}, data_a};
assign extend_b = B_SIGNED ? {{(64-B_WIDTH){data_b[B_WIDTH-1]}}, data_b} :
{(64-B_WIDTH){1'b0}}, data_b};
genvar idx0;
reg [63:0] partial_sum0 [31:0];
generate
for (idx0 = 0; idx0 <= 31; idx0 = idx0 + 1) begin : gen_stage0
always @(posedge clk) begin
if (rst) begin
partial_sum0[idx0] <= 0;
end else begin
case({extend_b[2*idx0+1], extend_b[2*idx0]})
2'b00: begin
partial_sum0[idx0] <= 0;
end
2'b01: begin
partial_sum0[idx0] <= extend_a << (2*idx0);
end
2'b10: begin
partial_sum0[idx0] <= ({extend_a[62:0], 1'b0}) << (2*idx0);
end
2'b11: begin
partial_sum0[idx0] <= ({extend_a[62:0], 1'b0} + extend_a) << (2*idx0);
end
endcase
end
end
end
endgenerate
genvar idx1;
reg [63:0] partial_sum1 [15:0];
generate
for (idx1 = 0; idx1 <= 15; idx1 = idx1 + 1) begin : gen_stage1
always @(posedge clk) begin
if (rst) begin
partial_sum1[idx1] <= 0;
end else begin
partial_sum1[idx1] <= partial_sum0[2*idx1] + partial_sum0[2*idx1+1];
end
end
end
endgenerate
genvar idx2;
reg [63:0] partial_sum2 [7:0];
generate
for (idx2 = 0; idx2 <= 7; idx2 = idx2 + 1) begin : gen_stage2
always @(posedge clk) begin
if (rst) begin
partial_sum2[idx2] <= 0;
end else begin
partial_sum2[idx2] <= partial_sum1[2*idx2] + partial_sum1[2*idx2+1];
end
end
end
endgenerate
genvar idx3;
reg [63:0] partial_sum3 [3:0];
generate
for (idx3 = 0; idx3 <= 3; idx3 = idx3 + 1) begin : gen_stage3
always @(posedge clk) begin
if (rst) begin
partial_sum3[idx3] <= 0;
end else begin
partial_sum3[idx3] <= partial_sum2[2*idx3] + partial_sum2[2*idx3+1];
end
end
end
endgenerate
genvar idx4;
reg [63:0] partial_sum4 [1:0];
generate
for (idx4 = 0; idx4 <= 1; idx4 = idx4 + 1) begin : gen_stage4
always @(posedge clk) begin
if (rst) begin
partial_sum4[idx4] <= 0;
end else begin
partial_sum4[idx4] <= partial_sum3[2*idx4] + partial_sum3[2*idx4+1];
end
end
end
endgenerate
reg [63:0] final_result;
always @(posedge clk) begin
if (rst) begin
final_result <= 0;
end else begin
final_result <= partial_sum4[0] + partial_sum4[1];
end
end
assign product = final_result;
endmodule