相关阅读
数字IC前端https://chenzhang.blog.csdn.net/article/details/133611299
由于Wallace Tree乘法器的特性(数字乘法器的优化设计(Wallace Tree乘法器),可以很轻松地将其设计成流水线的形式,下面简单介绍一下流水线设计。
组合逻辑的延迟(Latency)是一个很重要的性能指标,而吞吐率(Throughput)指的是数据输入的速度,也可以说是电路处理数据的速率。流水线(Pipeline)将一个任务分解为多个子任务,每个子任务并不完整地执行信号处理的全部步骤而只负责将前部子任务的结果进一步处理并传递给之后的部分,这就使得输入的吞吐率可以提升,因为输入无需在输出前保持不变,而可以以流水线切换速度改变输入。
流水线的中间结果是使用寄存器来保存的,这些寄存器的布局是由电路的DFG(信号流图)的前馈割集决定的,以保证各个子任务之间的数据相关性。
一般来说,一个连通图的一个割集是一组支路的集合,如果把这些支路从图中去掉,原本连通的图将变为不连通,而原本的连通图将被分为两个连通子图(注意,一定要是两个),而且割集必须得是最小的,意思是当割集中的任何一条支路没有被去掉时,则不会形成两个连通子图。
图1中用虚线标出了信号流图中的两个割集,但并不是所有割集都代表了流水线的布局,只有前馈割集才能正确地反映流水线中数据的相关性,前馈指的是数据在割集的每一条支路上都是向着前进的方向(指从含有信号来源的一边子图向信号终点的一边子图流动)。图1中存在一个前馈割集,因为该割集中的支路上的信号流向都是从左半子图到右半子图;而图1中还有一个非前馈割集,即信号在支路上的流向不一致。
图1 流水线寄存器布局
图2所示为华莱士树乘法器的计算过程,根据不同的计算阶段,我们插入三级流水线,恰好分别对应图2中的三条横线。
图2 华莱士树乘法器的覆盖过程
4x4带流水线的Wallace Tree乘法器的Verilog代码如下所示。
module Wallace_Multiplier_Withpipe(
input [3:0] A,
input [3:0] B,
input clk,
input rstn,
output [7:0] Sum
);
wire [3:0] partial_product [3:0];
reg [3:0] partial_product_r [3:0]; // 存一拍部分积,用于第一层流水线寄存器
wire [3:0] W_level1_sum, W_level1_carry;
reg [3:0] W_level1_sum_r, W_level1_carry_r; // 存一拍中间结果,用于第二层流水线寄存器
reg [3:0] partial_product_r_r [3:0]; // 存两拍部分积,用于第二层流水线寄存器,从图中可以看出有6个部分积需要存
reg [3:0] partial_product_r_r_r [3:0]; // 存三拍部分积,用于第三层流水线寄存器,从图中可以看出有2个部分积需要存
reg [3:0] W_level1_sum_r_r; // 存两拍中间结果,用于第三层流水线寄存器,从图中可以看出有1个中间结果需要存
wire [3:0] W_level2_sum, W_level2_carry;
reg [3:0] W_level2_sum_r, W_level2_carry_r; // 存一拍中间结果,用于第三层流水线寄存器
// 产生部分积
assign partial_product[0] = B[0]?A:4'b0;
assign partial_product[1] = B[1]?A:4'b0;
assign partial_product[2] = B[2]?A:4'b0;
assign partial_product[3] = B[3]?A:4'b0;
// 存部分积,对应第一层流水线
always@(posedge clk, negedge rstn) begin
if(~rstn) begin
partial_product_r[0] <= 4'b0;
partial_product_r[1] <= 4'b0;
partial_product_r[2] <= 4'b0;
partial_product_r[3] <= 4'b0;
end
else begin
partial_product_r[0] <= partial_product[0];
partial_product_r[1] <= partial_product[1];
partial_product_r[2] <= partial_product[2];
partial_product_r[3] <= partial_product[3];
end
end
// 阶段1
// ***************************************************
Adder_half adder_half_u1(
.Add1 (partial_product_r[0][1]),
.Add2 (partial_product_r[1][0]),
.Res (W_level1_sum[0]),
.Carry (W_level1_carry[0])
);
Adder adder_u1(
.Add1 (partial_product_r[0][2]),
.Add2 (partial_product_r[1][1]),
.I_carry (partial_product_r[2][0]),
.Res (W_level1_sum[1]),
.Carry (W_level1_carry[1])
);
Adder adder_u2(
.Add1 (partial_product_r[0][3]),
.Add2 (partial_product_r[1][2]),
.I_carry (partial_product_r[2][1]),
.Res (W_level1_sum[2]),
.Carry (W_level1_carry[2])
);
Adder_half adder_half_u2(
.Add1 (partial_product_r[1][3]),
.Add2 (partial_product_r[2][2]),
.Res (W_level1_sum[3]),
.Carry (W_level1_carry[3])
);
// 存中间结果,对应第二层流水线
always@(posedge clk,negedge rstn) begin
if(~rstn) begin
W_level1_sum_r <= 4'b0;
W_level1_carry_r <= 4'b0;
partial_product_r_r[0][0] <= 1'b0;
partial_product_r_r[2][3] <= 1'b0;
partial_product_r_r[3] <= 4'b0;
end
else begin
W_level1_sum_r <= W_level1_sum;
W_level1_carry_r <= W_level1_carry;
partial_product_r_r[0][0] <= partial_product_r[0][0];
partial_product_r_r[2][3] <= partial_product_r[2][3];
partial_product_r_r[3] <= partial_product_r[3];
end
end
// ***************************************************
// 阶段2
// ***************************************************
Adder_half adder_half_u3(
.Add1 (W_level1_sum_r[1]),
.Add2 (W_level1_carry_r[0]),
.Res (W_level2_sum[0]),
.Carry (W_level2_carry[0])
);
Adder adder_u3(
.Add1 (W_level1_sum_r[2]),
.Add2 (W_level1_carry_r[1]),
.I_carry (partial_product_r_r[3][0]),
.Res (W_level2_sum[1]),
.Carry (W_level2_carry[1])
);
Adder adder_u4(
.Add1 (W_level1_sum_r[3]),
.Add2 (W_level1_carry_r[2]),
.I_carry (partial_product_r_r[3][1]),
.Res (W_level2_sum[2]),
.Carry (W_level2_carry[2])
);
Adder adder_u5 (
.Add1 (W_level1_carry_r[3]),
.Add2 (partial_product_r_r[2][3]),
.I_carry (partial_product_r_r[3][2]),
.Res (W_level2_sum[3]),
.Carry (W_level2_carry[3])
);
// 存中间结果,对应第三层流水线
always@(posedge clk,negedge rstn) begin
if(~rstn) begin
W_level2_sum_r <= 4'b0;
W_level2_carry_r <= 4'b0;
partial_product_r_r_r[0][0] <= 1'b0;
partial_product_r_r_r[3][3] <= 1'b0;
W_level1_sum_r_r[0] <= 1'b0;
end
else begin
W_level2_sum_r <= W_level2_sum;
W_level2_carry_r <= W_level2_carry;
partial_product_r_r_r[0][0] <= partial_product_r_r[0][0];
partial_product_r_r_r[3][3] <= partial_product_r_r[3][3];
W_level1_sum_r_r[0] <= W_level1_sum_r[0];
end
end
// ***************************************************
// 向量合并
// ***************************************************
assign Sum[2:0] = {W_level2_sum[0]_r, W_level1_sum_r_r[0], partial_product_r_r_r[0][0]};
assign Sum[7:3] = {partial_product_r_r_r[3][3], W_level2_sum_r[3:1]} + W_level2_carry_r;
// ***************************************************
endmodule
// 半加器
module Adder_half(
input Add1,
input Add2,
output Res,
output Carry
);
assign Res = Add1 ^ Add2;
assign Carry = Add1 & Add2;
endmodule
// 全加器
module Adder(
input Add1,
input Add2,
input I_carry,
output Res,
output Carry
);
assign Res = Add1 ^ Add2 ^ I_carry;
assign Carry = (Add1 & Add2) | ((Add1 ^ Add2) & I_carry);
endmodule
使用Modelsim软件进行仿真的结果如图3所示,可以看出从输出到输入需要两个周期的延迟,并且是以流水线的形式工作。
图3 带流水线的华莱士树乘法器仿真结果