数字IC前端学习笔记:数字乘法器的优化设计(带流水线的Wallace Tree乘法器)

相关阅读

数字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 带流水线的华莱士树乘法器仿真结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

日晨难再

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值