• 二叉树乘法器


          对于两个N位数相乘 P=AB,之前的移位累加乘法器是先将B装载于一个2N位的寄存器中,然后B逐次移位,再根据A的各位情况累加。

          现在我们将A按权展开:                               

          以两个8位数相乘为例:

               

           首先我们可以写一个函数实现1位数和8位数的相乘,以得到上面的八个相加的数;

           然后我们可以将这八个数分组两两相加,第一次相加后得到4个中间结果,再将4个数分组两两相加,得到2个中间结果,最后再将这两个数相加得到最终结果。这样增加了芯片资源的耗用,但是可以提升速度。

          在《数字系统设计与Verilog HDL》中对于8位二叉树(加法树)乘法器有如下代码:

    module add_tree(out,a,b,clk);
    output [15:0] out;
    input [7:0] a,b;
    input clk;
    wire [15:0] out;
    wire [14:0] out1,c1;
    wire [12:0] out2;
    wire [10:0] out3,c2;
    wire [8:0] out4;
    reg [14:0] temp0;
    reg [13:0] temp1;
    reg [12:0] temp2;
    reg [11:0] temp3;
    reg [10:0] temp4;
    reg [9:0] temp5;
    reg [8:0] temp6;
    reg [7:0] temp7;
    //该函数实现8x1乘法
    function [7:0] mult8x1;
    input [7:0] operand;
    input sel;
    begin
    mult8x1=(sel)?(operand):8'b00000000;
    end
    endfunction
    //调用函数实现b各位与a相乘
    always @ ( posedge clk )
    begin
    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

         上面代码在调用函数的时候,左移k位是为了实现公式中2的k次方这个权系数。

          其实该代码其实是有错的,以temp6+temp7为例,temp6为9位,temp7为8位,相加的结果out4它定义为9位,如果两数相加结果为9位,则不会出现问题;

    如果两数相加产生进位,则进位将丢失,得不到正确结果。该代码的前仿真结果如下:

         由此可以看到,255×255时结果错误,就是因为有进位丢失。

         现在我们修改上述中间变量的位宽。由于两个8位数相乘结果最多为16位,因此如果我们将所有中间变量都改为16位的,结果肯定不会出问题,但是这样比较浪费资源。

         所以这里我们将temp6(9b)+temp7(8b)的结果out4设为10位,temp4(11b)+temp5(10b)的结果out3设为12位,temp2(13b)+temp3(12b)的结果out2设为14位,temp0(15b)+temp1(14b)的结果out1设为16位。

         然后将out3(12b)+out4(10b)的结果c2设为13位,out1(16b)+out2(14b)的结果c1设为16位,这里就不用考虑进位丢失了,因此最终结果最多为16位。

         修改的这部分代码如下: 

    wire  [15:0] out;
    wire [15:0] out1,c1;
    wire [13:0] out2;
    wire [11:0] out3;
    wire [12:0] c2;
    wire [9:0] out4;

        现在再仿真的结果如下:(可以看到结果正确了)

        该乘法器能在一个时钟周期内完成乘法运算。但是它不能插入流水线,因为后面的分组加法运算是组合逻辑实现的。我们可以看一下用XST综合的时序报告:

       (位宽有问题的代码的综合结果)

       Minimum input arrival time before clock: 3.687ns

       Maximum output required time after clock: 16.068ns

       现在我们将加法运算也放入always块内,在此需要先将wire型变量改为reg型,assign语句删除。always块如下:(位宽没改)

    always @ ( posedge clk )
    begin
    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);
    out1<=temp0+temp1;
    out2<=temp2+temp3;
    out3<=temp4+temp5;
    out4<=temp6+temp7;
    c1<=out1+out2;
    c2<=out3+out4;
    out<=c1+c2;
    end

        由代码分析可知道从第一个数据输入到第一个数据输出有3个时钟周期延迟,仿真如下:

        

        但是我们再看一下综合报告:

        Minimum input arrival time before clock: 3.687ns

        Maximum output required time after clock: 6.216ns

        与之前的对比可知,建立时间一样,但是保持时间小多了,因此时钟周期也小多了。并且,该实现方式可以在加法器之间插入寄存器以实现流水线,从而再次提高时钟频率。



  • 相关阅读:
    PAT B1027 打印沙漏 (20 分)
    PAT B1025 反转链表 (25 分)
    PAT B1022 D进制的A+B (20 分)
    PAT B1018 锤子剪刀布 (20 分)
    PAT B1017 A除以B (20 分)
    PAT B1015 德才论 (25 分)
    PAT B1013 数素数 (20 分)
    PAT B1010 一元多项式求导 (25 分)
    HDU 1405 The Last Practice
    HDU 1165 Eddy's research II
  • 原文地址:https://www.cnblogs.com/haigege/p/2218158.html
Copyright © 2020-2023  润新知