1. Wallace树乘法器原理
使用华莱士树构建方法:此方法的基本原理是采用进位保存加法器(CSA)将参与运算的三个数变成两个数输出,从而减少一个相加数,通过这种方法可以对图1中同一列(p)的部分积进行化简,化简的结果是最后每个位数的S构成一个加数,每个位数的进位C构成另外一个加数,将S和C通过高性能加法器相加即可求得结果。图2为4位华莱士树乘法器结构。
8位与4位华莱士树乘法器构建方法相同,通过3-2压缩器分级压缩,压缩到最终剩两个树,最终相加。
2. 推导过程
首先推导部分积相乘结果,对部分积进行编号,以方便后续计算,从右上至坐下分别编号,并转化位树型。
对部分积编号
根据编号生成部分积向量代码为
// 生成部分积
assign a = { x[7],
x[6], x[7],
x[5], x[6], x[7],
x[4], x[5], x[6], x[7],
x[3], x[4], x[5], x[6], x[7],
x[2], x[3], x[4], x[5], x[6], x[7],
x[1], x[2], x[3], x[4], x[5], x[6], x[7],
x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7],
x[0], x[1], x[2], x[3], x[4], x[5], x[6],
x[0], x[1], x[2], x[3], x[4], x[5],
x[0], x[1], x[2], x[3], x[4],
x[0], x[1], x[2], x[3],
x[0], x[1], x[2],
x[0], x[1],
x[0]} &
{ y[7],
y[7], y[6],
y[7], y[6], y[5],
y[7], y[6], y[5], y[4],
y[7], y[6], y[5], y[4], y[3],
y[7], y[6], y[5], y[4], y[3], y[2],
y[7], y[6], y[5], y[4], y[3], y[2], y[1],
y[7], y[6], y[5], y[4], y[3], y[2], y[1], y[0],
y[6], y[5], y[4], y[3], y[2], y[1], y[0],
y[5], y[4], y[3], y[2], y[1], y[0],
y[4], y[3], y[2], y[1], y[0],
y[3], y[2], y[1], y[0],
y[2], y[1], y[0],
y[1], y[0],
y[0]};
随后完成逐级压缩,每级压缩过程如图所示
其中圈两个的使用半加器、三个的使用全加器
逐级压缩最后相乘代码为
// 第一级
hadd U1(.x(a[34]), .y(a[35]), .out(b0));
hadd U2(.x(a[41]), .y(a[42]), .out(b1));
// 第二级
hadd U3(.x(a[26]), .y(a[27]), .out(c0));
fadd U4(.x(a[32]), .y(a[33]), .z(b0[0]), .out(c1));
fadd U5(.x(a[40]), .y(b1[0]), .z(b0[1]), .out(c2));
fadd U6(.x(a[47]), .y(a[48]), .z(b1[1]), .out(c3));
// 第三级
hadd U7(.x(a[19]), .y(a[20]), .out(d0));
fadd U8(.x(a[24]), .y(a[25]), .z(c0[0]), .out(d1));
fadd U9(.x(a[31]), .y(c1[0]), .z(c0[1]), .out(d2));
fadd U10(.x(a[39]), .y(c2[0]), .z(c1[1]), .out(d3));
fadd U11(.x(a[46]), .y(c3[0]), .z(c2[1]), .out(d4));
fadd U12(.x(a[52]), .y(a[53]), .z(c3[1]), .out(d5));
// 第四级
hadd U13(.x(a[13]), .y(a[14]), .out(e0));
fadd U14(.x(a[17]), .y(a[18]), .z(d0[0]), .out(e1));
fadd U15(.x(a[23]), .y(d1[0]), .z(d0[1]), .out(e2));
fadd U16(.x(a[30]), .y(d2[0]), .z(d1[1]), .out(e3));
fadd U17(.x(a[38]), .y(d3[0]), .z(d2[1]), .out(e4));
fadd U18(.x(a[45]), .y(d4[0]), .z(d3[1]), .out(e5));
fadd U19(.x(a[51]), .y(d5[0]), .z(d4[1]), .out(e6));
fadd U20(.x(a[56]), .y(a[57]), .z(d5[1]), .out(e7));
// 第五级
hadd U21(.x(a[8]), .y(a[9]), .out(f0));
fadd U22(.x(a[11]), .y(a[12]), .z(e0[0]), .out(f1));
fadd U23(.x(a[16]), .y(e1[0]), .z(e0[1]), .out(f2));
fadd U24(.x(a[22]), .y(e2[0]), .z(e1[1]), .out(f3));
fadd U25(.x(a[29]), .y(e3[0]), .z(e2[1]), .out(f4));
fadd U26(.x(a[37]), .y(e4[0]), .z(e3[1]), .out(f5));
fadd U27(.x(a[44]), .y(e5[0]), .z(e4[1]), .out(f6));
fadd U28(.x(a[50]), .y(e6[0]), .z(e5[1]), .out(f7));
fadd U29(.x(a[55]), .y(e7[0]), .z(e6[1]), .out(f8));
fadd U30(.x(a[59]), .y(a[60]), .z(e7[1]), .out(f9));
// 第六级
hadd U31(.x(a[4]), .y(a[5]), .out(g0));
fadd U32(.x(a[6]), .y(a[7]), .z(f0[0]), .out(g1));
fadd U33(.x(a[10]), .y(f1[0]), .z(f0[1]), .out(g2));
fadd U34(.x(a[15]), .y(f2[0]), .z(f1[1]), .out(g3));
fadd U35(.x(a[21]), .y(f3[0]), .z(f2[1]), .out(g4));
fadd U36(.x(a[28]), .y(f4[0]), .z(f3[1]), .out(g5));
fadd U37(.x(a[36]), .y(f5[0]), .z(f4[1]), .out(g6));
fadd U38(.x(a[43]), .y(f6[0]), .z(f5[1]), .out(g7));
fadd U39(.x(a[49]), .y(f7[0]), .z(f6[1]), .out(g8));
fadd U40(.x(a[54]), .y(f8[0]), .z(f7[1]), .out(g9));
fadd U41(.x(a[58]), .y(f9[0]), .z(f8[1]), .out(g10));
fadd U42(.x(a[61]), .y(a[62]), .z(f9[1]), .out(g11));
//第七级
assign add_a = {g11[1], g10[1], g9[1], g8[1], g7[1], g6[1], g5[1], g4[1], g3[1], g2[1], g1[1], g0[1], g0[0], a[2]};
assign add_b = {a[63], g11[0], g10[0], g9[0], g8[0], g7[0], g6[0], g5[0], g4[0], g3[0], g2[0], g1[0], a[3], a[1]};
assign add_out = add_a + add_b;
3. 4/8位wallace树乘法器代码
最终,8位Wallace整体实现代码为,后附4位Wallace乘法器
`timescale 1ns / 1ps
module wallac_mult_8bit(x, y, out);
parameter size = 8; // 定义参数,乘法器的位数
input [size - 1 : 0] x, y; // 输入y是乘数,x是被乘数
output [2*size - 1 : 0] out; // 乘法器的输出(组合逻辑)
wire [size*size - 1 : 0] a; // a为部分积
wire [1 : 0] b0, b1; // 第一级的输出,包含进位
wire [1 : 0] c0, c1, c2, c3; // 第二级的输出,包含进位
wire [1 : 0] d0, d1, d2, d3, d4, d5; // 第三级的输出,包含进位
wire [1 : 0] e0, e1, e2, e3, e4, e5, e6, e7; // 第四级的输出,包含进位
wire [1 : 0] f0, f1, f2, f3, f4, f5, f6, f7, f8, f9; // 第五级的输出,包含进位
wire [1 : 0] g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, g10, g11; // 第六级的输出,包含进位
wire [2*size - 3 : 0] add_a, add_b; // 第六级的输入
wire [2*size - 2 : 0] add_out; // 第六级的输出
// 生成部分积
assign a = { x[7],
x[6], x[7],
x[5], x[6], x[7],
x[4], x[5], x[6], x[7],
x[3], x[4], x[5], x[6], x[7],
x[2], x[3], x[4], x[5], x[6], x[7],
x[1], x[2], x[3], x[4], x[5], x[6], x[7],
x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7],
x[0], x[1], x[2], x[3], x[4], x[5], x[6],
x[0], x[1], x[2], x[3], x[4], x[5],
x[0], x[1], x[2], x[3], x[4],
x[0], x[1], x[2], x[3],
x[0], x[1], x[2],
x[0], x[1],
x[0]} &
{ y[7],
y[7], y[6],
y[7], y[6], y[5],
y[7], y[6], y[5], y[4],
y[7], y[6], y[5], y[4], y[3],
y[7], y[6], y[5], y[4], y[3], y[2],
y[7], y[6], y[5], y[4], y[3], y[2], y[1],
y[7], y[6], y[5], y[4], y[3], y[2], y[1], y[0],
y[6], y[5], y[4], y[3], y[2], y[1], y[0],
y[5], y[4], y[3], y[2], y[1], y[0],
y[4], y[3], y[2], y[1], y[0],
y[3], y[2], y[1], y[0],
y[2], y[1], y[0],
y[1], y[0],
y[0]};
// 第一级
hadd U1(.x(a[34]), .y(a[35]), .out(b0));
hadd U2(.x(a[41]), .y(a[42]), .out(b1));
// 第二级
hadd U3(.x(a[26]), .y(a[27]), .out(c0));
fadd U4(.x(a[32]), .y(a[33]), .z(b0[0]), .out(c1));
fadd U5(.x(a[40]), .y(b1[0]), .z(b0[1]), .out(c2));
fadd U6(.x(a[47]), .y(a[48]), .z(b1[1]), .out(c3));
// 第三级
hadd U7(.x(a[19]), .y(a[20]), .out(d0));
fadd U8(.x(a[24]), .y(a[25]), .z(c0[0]), .out(d1));
fadd U9(.x(a[31]), .y(c1[0]), .z(c0[1]), .out(d2));
fadd U10(.x(a[39]), .y(c2[0]), .z(c1[1]), .out(d3));
fadd U11(.x(a[46]), .y(c3[0]), .z(c2[1]), .out(d4));
fadd U12(.x(a[52]), .y(a[53]), .z(c3[1]), .out(d5));
// 第四级
hadd U13(.x(a[13]), .y(a[14]), .out(e0));
fadd U14(.x(a[17]), .y(a[18]), .z(d0[0]), .out(e1));
fadd U15(.x(a[23]), .y(d1[0]), .z(d0[1]), .out(e2));
fadd U16(.x(a[30]), .y(d2[0]), .z(d1[1]), .out(e3));
fadd U17(.x(a[38]), .y(d3[0]), .z(d2[1]), .out(e4));
fadd U18(.x(a[45]), .y(d4[0]), .z(d3[1]), .out(e5));
fadd U19(.x(a[51]), .y(d5[0]), .z(d4[1]), .out(e6));
fadd U20(.x(a[56]), .y(a[57]), .z(d5[1]), .out(e7));
// 第五级
hadd U21(.x(a[8]), .y(a[9]), .out(f0));
fadd U22(.x(a[11]), .y(a[12]), .z(e0[0]), .out(f1));
fadd U23(.x(a[16]), .y(e1[0]), .z(e0[1]), .out(f2));
fadd U24(.x(a[22]), .y(e2[0]), .z(e1[1]), .out(f3));
fadd U25(.x(a[29]), .y(e3[0]), .z(e2[1]), .out(f4));
fadd U26(.x(a[37]), .y(e4[0]), .z(e3[1]), .out(f5));
fadd U27(.x(a[44]), .y(e5[0]), .z(e4[1]), .out(f6));
fadd U28(.x(a[50]), .y(e6[0]), .z(e5[1]), .out(f7));
fadd U29(.x(a[55]), .y(e7[0]), .z(e6[1]), .out(f8));
fadd U30(.x(a[59]), .y(a[60]), .z(e7[1]), .out(f9));
// 第六级
hadd U31(.x(a[4]), .y(a[5]), .out(g0));
fadd U32(.x(a[6]), .y(a[7]), .z(f0[0]), .out(g1));
fadd U33(.x(a[10]), .y(f1[0]), .z(f0[1]), .out(g2));
fadd U34(.x(a[15]), .y(f2[0]), .z(f1[1]), .out(g3));
fadd U35(.x(a[21]), .y(f3[0]), .z(f2[1]), .out(g4));
fadd U36(.x(a[28]), .y(f4[0]), .z(f3[1]), .out(g5));
fadd U37(.x(a[36]), .y(f5[0]), .z(f4[1]), .out(g6));
fadd U38(.x(a[43]), .y(f6[0]), .z(f5[1]), .out(g7));
fadd U39(.x(a[49]), .y(f7[0]), .z(f6[1]), .out(g8));
fadd U40(.x(a[54]), .y(f8[0]), .z(f7[1]), .out(g9));
fadd U41(.x(a[58]), .y(f9[0]), .z(f8[1]), .out(g10));
fadd U42(.x(a[61]), .y(a[62]), .z(f9[1]), .out(g11));
//
assign add_a = {g11[1], g10[1], g9[1], g8[1], g7[1], g6[1], g5[1], g4[1], g3[1], g2[1], g1[1], g0[1], g0[0], a[2]};
assign add_b = {a[63], g11[0], g10[0], g9[0], g8[0], g7[0], g6[0], g5[0], g4[0], g3[0], g2[0], g1[0], a[3], a[1]};
assign add_out = add_a + add_b;
// 最终输出
assign out = {add_out, a[0]};
endmodule
// 全加器模块
module fadd(x, y, z, out);
input x, y, z;
output [1 : 0] out;
assign out = x + y + z;
endmodule
// 半加器模块
module hadd(x, y, out);
input x, y;
output [1 : 0] out;
assign out = x + y;
endmodule
注意,如果要两个乘法器一块仿真,需要扇出其中一个的全加器和半加器模块,防止重复定义报错。
`timescale 1ns / 1ps
module wallac_mult_4bit(x, y, out);
parameter size = 4; // 定义参数,乘法器的位数
input [size - 1 : 0] x, y; // 输入y是乘数,x是被乘数
output [2*size - 1 : 0] out; // 乘法器的输出(组合逻辑)
wire [size*size - 1 : 0] a; // a为部分积
wire [1 : 0] b0, b1; // 第一级的输出,包含进位
wire [1 : 0] c0, c1, c2, c3; // 第二级的输出,包含进位
wire [5 : 0] add_a, add_b; // 第三级的输入
wire [6 : 0] add_out; // 第三级的输出
// 生成部分积
assign a = {x[3], x[2], x[3], x[1], x[2], x[3], x[0], x[1],
x[2], x[3], x[0], x[1], x[2], x[0], x[1], x[0]} &
{y[3], y[3], y[2], y[3], y[2], y[1], y[3], y[2],
y[1], y[0], y[2], y[1], y[0], y[1], y[0], y[0]};
// 第一级
hadd U1(.x(a[8]), .y(a[9]), .out(b0));
hadd U2(.x(a[11]), .y(a[12]), .out(b1));
// 第二级
hadd U3(.x(a[4]), .y(a[5]), .out(c0));
fadd U4(.x(a[6]), .y(a[7]), .z(b0[0]), .out(c1));
fadd U5(.x(b1[0]), .y(a[10]), .z(b0[1]), .out(c2));
fadd U6(.x(a[13]), .y(a[14]), .z(b1[1]), .out(c3));
// 第三级
assign add_a = {c3[1], c2[1], c1[1], c0[1], c0[0], a[2]};
assign add_b = {a[15], c3[0], c2[0], c1[0], a[3], a[1]};
assign add_out = add_a + add_b;
// 最终输出
assign out = {add_out, a[0]};
endmodule
// 全加器模块
module fadd(x, y, z, out);
input x, y, z;
output [1 : 0] out;
assign out = x + y + z;
endmodule
// 半加器模块
module hadd(x, y, out);
input x, y;
output [1 : 0] out;
assign out = x + y;
endmodule
测试思路为,枚举所有乘法结果并于正确结果相比较,如果错误输出错误提示。
`timescale 1ns / 1ps
module wallac_mult_tb;
// 输入和输出
reg [3:0] multiplicand1;
reg [3:0] multiplier1;
wire [7:0] product1;
reg [7:0] multiplicand2;
reg [7:0] multiplier2;
wire [15:0] product2;
// 实例化4位和8位华莱士树乘法器模块
wallac_mult_4bit mult1 (
.x(multiplicand1),
.y(multiplier1),
.out(product1)
);
wallac_mult_8bit mult2 (
.x(multiplicand2),
.y(multiplier2),
.out(product2)
);
integer i, y;
// 生成4位乘法器输入组合并验证输出
always begin
if (i < 256) begin
multiplicand1 = i / 16;
multiplier1 = i % 16;
#1; // 等待乘法器输出稳定
if (product1 !== multiplicand1 * multiplier1) begin
$display("Error at time %0t: multiplicand1 = %d, multiplier1 = %d, expected product1 = %d, got %d",
$time, multiplicand1, multiplier1, multiplicand1 * multiplier1, product1);
end
i = i + 1;
end else begin
i = 0;
end
#9;
end
// 生成8位乘法器输入组合并验证输出
always begin
if (y < 65536) begin
multiplicand2 = y / 256;
multiplier2 = y % 256;
#1; // 等待乘法器输出稳定
if (product2 !== multiplicand2 * multiplier2) begin
$display("Error at time %0t: multiplicand2 = %d, multiplier2 = %d, expected product2 = %d, got %d",
$time, multiplicand2, multiplier2, multiplicand2 * multiplier2, product2);
end
y = y + 1;
end else begin
y = 0;
end
#19;
end
initial begin
i = 0;
y = 2568;
multiplicand1 = 4'b0000;
multiplier1 = 4'b0000;
multiplicand2 = 8'b0;
multiplier2 = 8'b0;
#50000;
$stop;
end
initial begin
$monitor("a = %d, b = %d, result = %d", multiplicand2, multiplier2, product2);
//$fsdbDumpfile("wallac_mult.fsdb");
//$fsdbDumpvars();
end
endmodule
4. 仿真结果
如图为部分打印结果,没有任何错误报告提示,表明65536种输出结果均正确。
5.综合与分析
约束条件:
create_clock -name vclk -period 10
set in_ports [all_inputs]
set_input_delay 0 -clock vclk -add_delay $in_ports
set_output_delay 0 -clock vclk -add_delay [all_outputs]
面积约束
set_max_area 0
相较于4位华莱士树乘法器2.89 ns,8bit乘法器数据到达时间为6.95 ns。面积消耗由520增加到2572。